creating multiple variables/lists/functions via a loop (Maxima) - maxima

below I have listed some ways to create variables/lists/functions via a for loop in Maxima,
but how, via a for loop, to do:
f1(x) := x^1$
f2(x) := x^2$
f3(x) := x^3$
example code:
for i : 1 thru 10 do
(x : concat ('a, i), x :: i)$
[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10];
for i : 1 thru 3 do
(x : concat ('L, i), x :: [(3*i)-2,(3*i)-1,3*i])$
[L1, L2, L3];
/* good, but not quite what I want to do */
for i : 1 thru 3 do
f[i](x) := x^i$
[f[1](2), f[2](2), f[3](2)];
/* is there a way, via a for loop, to create */
f1(x) := x^1$
f2(x) := x^2$
f3(x) := x^3$
[f1(2), f2(2), f3(2)];
EDIT: further code:
/* is there a way, via a for loop, to create */
f(x) := x^1$
g(x) := x^2$
h(x) := x^3$
[f(2), g(2), h(2)];
for tmp1 : 1 thru 10 do
(tmp2 : parse_string(ascii(96+tmp1)), tmp2 :: tmp1)$
[a, b, c, d, e, f, g, h, i, j];
for tmp1 : 1 thru 10 do
(tmp2 : concat(parse_string(ascii(96+tmp1)), tmp1), tmp2 :: tmp1)$
[a1, b2, c3, d4, e5, f6, g7, h8, i9, j10];
EDIT 2: original problems solved (any code improvements/simplifications welcome):
for i : 1 thru 3 do
eval_string(concat("f", i, "(x) := x^", i))$
[f1(2), f2(2), f3(2)];
for i : 1 thru 3 do
eval_string(concat(ascii(96+5+i), "(x) := x^", i))$
[f(2), g(2), h(2)];
sum:0$
for i : 1 thru 3 do
sum:sum + eval_string(concat("f", i, "(2)"))$
sum;
sum:0$
for i : 1 thru 3 do
sum:sum + eval_string(concat(ascii(96+5+i), "(2)"))$
sum;

What is your larger goal here? In general using subscripted symbols e.g. a[1] instead of a1 is to be preferred. When you define a subscripted function, you only define it once, not for every value of the subscript. E.g.
(%i1) f[i](x) := x^i $
(%i2) [f[1], f[2], f[3]];
2 3
(%o2) [lambda([x], x), lambda([x], x ), lambda([x], x )]
(%i3) [f[1](u), f[2](v), f[3](w)];
2 3
(%o3) [u, v , w ]
If that doesn't work for you, maybe you can explain about what you're trying to achieve.

I have collected here, various ways of creating multiple variables/lists/functions via a loop in Maxima,
as an answer to the question, '[f1(2), f2(2), f3(2)]' explicitly answers the original question:
for i : 1 thru 10 do
(x : concat ('a, i), x :: i)$
[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10];
for i : 1 thru 3 do
(x : concat ('L, i), x :: [(3*i)-2,(3*i)-1,3*i])$
[L1, L2, L3];
for tmp1 : 1 thru 10 do
(tmp2 : parse_string(ascii(96+tmp1)), tmp2 :: tmp1)$
[a, b, c, d, e, f, g, h, i, j];
for tmp1 : 1 thru 10 do
(tmp2 : concat(parse_string(ascii(96+tmp1)), tmp1), tmp2 :: tmp1)$
[a1, b2, c3, d4, e5, f6, g7, h8, i9, j10];
for i : 1 thru 3 do
eval_string(concat("f", i, "(x) := x^", i))$
[f1(2), f2(2), f3(2)];
for i : 1 thru 3 do
eval_string(concat(ascii(96+5+i), "(x) := x^", i))$
[f(2), g(2), h(2)];
f[i](x) := x^i$
[f[1], f[2], f[3]];
[f[1](2), f[2](2), f[3](2)];
[f[1](u), f[2](v), f[3](w)];

Related

How to combine two sums and factor out a common element expression?

Here's the initial premise: two sums s1 and s2 are added; the sum element expressions have a common factor a[n].
s1: sum(r1[m,q]*b[m,n]*a[n],n,0,N)$
s2: sum(r2[m,q]*c[m,n]*a[n],n,0,N)$
s1+s2;
I expect the sums to be combined and the common element expression a[n] factored out:
s12: sum(a[n]*(r1[m,q]*b[m,n]+r2[m,q]*c[m,n]),n,0,N);
However, I'm unable to make Maxima produce such contraction. The most simplification I was able to obtain was using sumcontract(s1+s2) and it results in two sums without the common element being factored out:
r1[m,q]*sum(b[m,n]*a[n], n,0,N) + r2[m,q]*sum(c[m,n]*a[n], n,0,N);
How to make Maxima produce the factored out expression from s1+s2 as in s12 above?
NOTE: If we remove the r1 and r2, then the factor(sumcontract(s1+s2)) indeed results in the expected s12 expression. However, with both present, it results in two sums and does not factor out the a[n] as mentioned.
How about this. I've applied sumcontract, intosum, and factor.
(%i1) s1: sum(r1[m,q]*b[m,n]*a[n],n,0,N)$
(%i2) s2: sum(r2[m,q]*c[m,n]*a[n],n,0,N)$
(%i3) s1 + s2;
N N
==== ====
\ \
(%o3) r2 > c a + r1 > b a
m, q / m, n n m, q / m, n n
==== ====
n = 0 n = 0
(%i4) intosum (%);
N N
==== ====
\ \
(%o4) > c r2 a + > b r1 a
/ m, n m, q n / m, n m, q n
==== ====
n = 0 n = 0
(%i5) sumcontract (%);
N
====
\
(%o5) > (c r2 a + b r1 a )
/ m, n m, q n m, n m, q n
====
n = 0
(%i6) factor (%);
N
====
\
(%o6) > (c r2 + b r1 ) a
/ m, n m, q m, n m, q n
====
n = 0
In this, intosum is pushing constant factors back into the sum.

Solving Equations with (wx)Maxima: Control stack exhausted

Solving Equations with (wx)Maxima: Control stack exhausted
I'm trying to solve equations with (wx)Maxima: formulate the equation, then let it insert the variables and solve the equation for the missing variable. But I'm having a hard time. Somehow it's having problems in the last line:
Control stack exhausted (no more space for function call frames).
This is probably due to heavily nested or infinitely recursive function
calls, or a tail call that SBCL cannot or has not optimized away.
That's my code:
kill(all);
load(physical_constants);
load(unit);
setunits([kg,m,s,N]);
showtime: false;
α: 30*%pi/180;
/*α: 30*°;*/
masse: 1000*kg;
g: 9.80665*m/(s*s);
b: 0.3*m;
B: 0.5*m;
L: 0.1*m;
F_g: masse*g;
F_H: masse * g;
kill(S, x);
S: solve(0=F_H-2*x*sin(α), x);
S: assoc(x, S);
kill(H, x);
H: solve(0=-F_g+2*x, x);
H: assoc(x, H);
kill(Ly, x);
Ly: solve(tan(α)=x/(B/2), x);
Ly: assoc(x, Ly);
kill(FN, x);
FN: solve(0=H*B/2-x*(L+Ly)+S*sin(α)*B/2+S*cos(α)*Ly, x);
FN: assoc(x, FN);
If I calculate it "directly", it works though:
kill(all);
load(physical_constants);
load(unit);
setunits([kg,m,s,N]);
showtime: false;
kill(FN, x);
FN: solve([α=30*%pi/180, H=196133/40*N,
B=0.5*m, L=0.1*m,
Ly=sqrt(3)/12*m, S=196133/20*N,
0=H*B/2-x*(L+Ly)+S*sin(α)*B/2+S*cos(α)*Ly],
[x, α, H, B, L, Ly, S]);
FN: assoc(x, FN[1]);
FN: float(FN);
(FN) 1934473685/128529*N
Unfortunately the unit package has not been updated in some time. I'll suggest to use instead the package ezunits, in which dimensional quantities are represented with a back quote. To solve equations, try dimensionally which goes through some gyrations to help other functions with dimensional quantities, e.g. dimensionally (solve (...)). (Note that dimensionally isn't documented, I'm sorry for the shortcoming.)
I've modified your program a little to remove some unneeded stuff and also to use rational numbers instead of floats; Maxima is generally more comfortable with rationals and integers than with floats. Here is the program:
linel: 65 $
load(ezunits) $
α: 30*%pi/180;
masse: 1000`kg;
g: rationalize(9.80665)`m/(s*s);
b: 3/10`m;
B: 5/10`m;
L: 1/10`m;
F_g: masse*g;
F_H: masse * g;
S: dimensionally (solve(0=F_H-2*x*sin(α), x));
S: assoc(x, S);
Ly: dimensionally (solve(tan(α)=x/(B/2), x));
Ly: assoc(x, Ly);
FN: dimensionally (solve(0=H*B/2-x*(L+Ly)+S*sin(α)*B/2+S*cos(α)*Ly, x));
FN: assoc(x, FN);
subst (x = S, F_H-2*x*sin(α));
subst (x = Ly, tan(α)=x/(B/2));
subst (x = FN, H*B/2-x*(L+Ly)+S*sin(α)*B/2+S*cos(α)*Ly);
ratsimp (expand (%));
and here is the output I get. Note that I substituted the solutions back into the equations to verify them. It looks like it worked as expected.
(%i2) linel:65
(%i3) load(ezunits)
(%i4) α:(30*%pi)/180
%pi
(%o4) ---
6
(%i5) masse:1000 ` kg
(%o5) 1000 ` kg
(%i6) g:rationalize(9.80665) ` m/(s*s)
5520653160719109 m
(%o6) ---------------- ` --
562949953421312 2
s
(%i7) b:3/10 ` m
3
(%o7) -- ` m
10
(%i8) B:5/10 ` m
1
(%o8) - ` m
2
(%i9) L:1/10 ` m
1
(%o9) -- ` m
10
(%i10) F_g:masse*g
690081645089888625 kg m
(%o10) ------------------ ` ----
70368744177664 2
s
(%i11) F_H:masse*g
690081645089888625 kg m
(%o11) ------------------ ` ----
70368744177664 2
s
(%i12) S:dimensionally(solve(0 = F_H-2*x*sin(α),x))
690081645089888625 kg m
(%o12) [x = ------------------ ` ----]
70368744177664 2
s
(%i13) S:assoc(x,S)
690081645089888625 kg m
(%o13) ------------------ ` ----
70368744177664 2
s
(%i14) Ly:dimensionally(solve(tan(α) = x/(B/2),x))
1
(%o14) [x = --------- ` m]
4 sqrt(3)
(%i15) Ly:assoc(x,Ly)
1
(%o15) --------- ` m
4 sqrt(3)
(%i16) FN:dimensionally(solve(0 = (H*B)/2-x*(L+Ly)
+(S*sin(α)*B)/2
+S*cos(α)*Ly,x))
1 1
(%o16) [x = (----------------------------------------- ` --)
140737488355328 sqrt(3) + 351843720888320 2
s
2
(351843720888320 sqrt(3) H ` s
3/2
+ 1150136075149814375 3 ` kg m)]
(%i17) FN:assoc(x,FN)
1 1
(%o17) (----------------------------------------- ` --)
140737488355328 sqrt(3) + 351843720888320 2
s
2
(351843720888320 sqrt(3) H ` s
3/2
+ 1150136075149814375 3 ` kg m)
(%i18) subst(x = S,F_H-2*x*sin(α))
kg m
(%o18) 0 ` ----
2
s
(%i19) subst(x = Ly,tan(α) = x/(B/2))
1 1
(%o19) ------- = -------
sqrt(3) sqrt(3)
(%i20) subst(x = FN,(H*B)/2-x*(L+Ly)+(S*sin(α)*B)/2+S*cos(α)*Ly)
1 1
(- ---------) - --
4 sqrt(3) 10 1
(%o20) ((----------------------------------------- ` --)
140737488355328 sqrt(3) + 351843720888320 2
s
2
(351843720888320 sqrt(3) H ` s
3/2 H
+ 1150136075149814375 3 ` kg m) + -) ` m
4
2
690081645089888625 kg m
+ ------------------ ` -----
281474976710656 2
s
(%i21) ratsimp(expand(%))
2
kg m
(%o21) 0 ` -----
2
s
EDIT. About converting kg*m/s^2 to N, you can apply the double back quote operator. For example:
(%i25) F_g `` N
690081645089888625
(%o25) ------------------ ` N
70368744177664
By the way, to convert back to floats, you can apply float:
(%i26) float(%)
(%o26) 9806.649999999998 ` N
Converting FN to N is a little more involved, since it's a more complex expression, especially because of H which doesn't have units attached to it yet. Some inspection seems to show the units of H must be kg*m/s^2. I'll apply declare_units to say that's what are the units of H. Then I'll convert FN to N.
(%i27) declare_units(H,(kg*m)/s^2)
kg m
(%o27) ----
2
s
(%i28) FN `` N
351843720888320 sqrt(3) qty(H)
(%o28) (-----------------------------------------
140737488355328 sqrt(3) + 351843720888320
3/2
1150136075149814375 3
+ -----------------------------------------) ` N
140737488355328 sqrt(3) + 351843720888320
(%i29) float(%)
(%o29) (1.023174629940149 qty(H) + 10033.91548470256) ` N
The notation qty(H) represents the unspecified quantity of H. One could also just subst(H = 100 ` kg*m/s^2, FN) (or any quantity, not just 100) and go from there.

Substitute variable?

I'm trying to substitute L with Lα:
f(x) := c * (x + L);
c: L;
f(x), L: Lα;
I expected the output:
Lα * (x + Lα)
instead I got
L * (x + Lα)
Maybe I should define f(x) instead?
kill(all);
define(
f(x),
c * (x + L)
);
c: L;
f(x), L: Lα;
Nope — same result.
Do I substitute L for Lα in a wrong way?
Edit:
Turns out it is expected behaviour, as maxima evavluates expression only once. One can impose "infinite evaluation" via the flag infeval:
f(x), L: La, infeval;
=> La*(x + La)
Another solution is to use subst instead:
subst(
Lα, L, f(x)
);
(source)
You need to add an extra eval step to make this work:
f(x) := c * (x + L);
c: L;
f(x), L: Lα, eval;
Output:
Lα (x + Lα)
Use subst instead of ev.
(%i1) f(x) := c * (x + L)$
(%i2) c: L$
(%i3) subst(L=La,f(x));
(%o3) La (x + La)
But keep in mind that the function continues to be c*(x+L). The symbol c has been bound to L and if you then bind the symbol L to La, c will continue to be bound to L and not to La. Maxima variables work as in Lisp, which might be different to what you are used to in other languages.

maxima: use function as function argument

Like the title says, I want to use a function as a function argument.
Intuitive I tried something like:
a(t,c) := t+c;
b(R_11, R_12, R_13, d_1x, d_1y, d_1z) := R_11*d_1x + R_12*d_1y + R_13*d_1z;
f( a(t,c), b(R_11, R_12, R_13, d_1x, d_1y, d_1z), %lambda ) := a(t,c) +
%lambda * b(R_11, R_12, R_13, d_1x, d_1y, d_1z);
But Maxima stated "define: in definition of f, found bad argument"
My goal is to simplify my equations to get a better overview. When I differentiate like
diff( f(...), R_11 )
the result for this example should be the partial derivative of b with respect to R_11.
f' = b_R11(...)
Is there a way to do such thinks or is this an odd attempt and there is maybe a better way?
You can declare that b depends on some arguments and then diff will construct formal derivatives of b.
(%i1) depends (b, [R1, R2]);
(%o1) [b(R1, R2)]
(%i2) depends (a, t);
(%o2) [a(t)]
(%i3) f(t, R1, R2) := a(t) + b(R1, R2);
(%o3) f(t, R1, R2) := a(t) + b(R1, R2)
(%i4) diff (f(t, R1, R2), R1);
d
(%o4) --- (b(R1, R2))
dR1
(%i5) diff (f(t, R1, R2), t);
d
(%o5) -- (a(t))
dt
But that only works as long as b is undefined. When b is defined, diff will go ahead and call b and compute the derivative with respect to whatever is returned.
(%i8) b(R1, R2) := 2*R1 + 3*R2;
(%o8) b(R1, R2) := 2 R1 + 3 R2
(%i9) diff (f(t, R1, R2), R1);
(%o9) 2

Maxima - differentiating a piecewise function

Suppose you have a function defined by intervals, such as
f(x):=block(if x<0 then x^2 else x^3);
When we differentiate it with
diff(f(x),x);
we get
d/dx (if x<0 then x^2 else x^3)
whereas I'd like to get
(if x<0 then 2*x else 3*x^2)
Is there a way to obtain such result?
This may help in a simple case:
(%i1) f(x):= charfun(x<0)*x^2 + charfun(x>=0)*x^3$
(%i2) gradef(charfun(y), 0)$
(%i3) diff(f(x),x);
2
(%o3) 2 x charfun(x < 0) + 3 x charfun(x >= 0)
charfun, gradef
You can try also Pw.mac package from Richard Hennessy.
Here's a different approach using a simplification rule for "if" expressions. The unsolved part here is to detect discontinuities and generate delta functions for those locations. If you want to ignore those, you can define FOO to return 0. Note that I didn't attempt to implement the function discontinuities; that part is unsolved here. I can give it a try if there is interest.
(%i1) display2d : false $
(%i2) matchdeclare ([aa, bb, cc], all, xx, symbolp) $
(%i3) 'diff (if aa then bb else cc, xx) $
(%i4) tellsimpafter (''%, apply ("if", [aa, diff (bb, xx), true, diff (cc, xx)]) + FOO (aa, bb, cc, xx)) $
(%i5) FOO (a, b, c, x) := 'lsum ((ev (c, x = d) - ev (b, x = d)) * delta (d, x), d, discontinuities (a, x)) $
(%i6) diff (if x > 0 then x^2 else x^3, x);
(%o6) (if x > 0 then 2*x else 3*x^2)+'lsum((d^3-d^2)*delta(d,x),d,
discontinuities(x > 0,x))
Building on slitinov's answer I wrote this quite naive implementation for functions with more than two "pieces":
gradef(charfun(dummy),0)$
/* piecewise function definition */
itv: [[x<0],[x>=0,x<1], [x>=1]]; /* intervals */
fi: [ 1, x^2+1, 2*x ]; /* local functions */
/* creation of global function f and its derivative df */
f:0;
for i: 1 thru 3 do f:f+charfun(apply("and",itv[i]))*fi[i];
df:diff(f,x);
/* display of local functions and derivatives */
for i: 1 thru 3 do (
apply(assume,itv[i]),
newline(),
print(itv[i]),
print("f = ",ev(f)),
print("df = ",ev(df)),
apply(forget,itv[i])
);
plot2d([f,df],[x,-2,3],[y,-1,5],[style,[lines,4,3],[lines,2,2]]);

Resources