Result of differntiation evaluates numerically in plotting but not in standalone evaluation - maxima

The following is my script:
binom_df(s, N, p):= ( N! / ( s! * (N-s)! ) ) * ( p^s ) * ( 1 - p) ^ ( N-s );
ddn_binom(s, N, p):= diff( binom_df(s, N, p), s);
ddn_binom(s, N, p);
wxplot2d(
[ binom_df( s, 100, 1/2 ), ddn_binom( s, 100, 1/2 ) ],
[s, 30, 70],
[ box, false ],
[ legend, "N=100, p= 1/2",
"diff( binom_df( s, N, p ) )"
],
[ xlabel, "s"]
);
for s: 1 thru 10 step 1 do (
display(s),
pr_val: ev( ( ddn_binom( s1, N1, p1 ) ), s1=s, N1=100, p1=0.5 ),
display(pr_val)
);
ddn_binom( 10, 100, 1/10 );
The call to ddn_binom works in wxplot2d; I get the graph. But the call to ddn_binom in the 'for' loop fails with the message:
diff: second argument must be a variable; found 1
which is the reason I have the last line with constant arguments
but it too fails with the message:
diff: second argument must be a variable; found 10
I am not conversant with the basic principles of how Maxima works.
If you can help me, I would appreciate it.
Thanks.
BD

(%i1) binom_df(s, N, p):= ( N! / ( s! * (N-s)! ) ) * ( p^s ) * ( 1 - p) ^ ( N-s ) $
(%i2) ddn_binom1(s, N, p):= diff(binom_df(s, N, p), s) $
In (%i2) the function body is not evaluated. It is
evaluated every time the function ddn_binom1 is called with the
formal argument s assigned to an actual argument. diff fails if s is a number.
You can use define if you want the body evaluated
(%i3) define(ddn_binom2(s, N, p), diff(binom_df(s, N, p), s)) $
fundef returns the function definitions:
(%i4) display2d: false $
(%i5) fundef(ddn_binom1);
(%o5) ddn_binom1(s,N,p):=diff(binom_df(s,N,p),s)
(%i6) fundef(ddn_binom2);
(%o6) ddn_binom2(s,N,p):=(-(N!*(1-p)^(N-s)*p^s*psi[0](s+1))/((N-s)!*s!))
+(N!*(1-p)^(N-s)*p^s*psi[0]((-s)+N+1))/((N-s)!*s!)
-(N!*log(1-p)*(1-p)^(N-s)*p^s)/((N-s)!*s!)
+(N!*(1-p)^(N-s)*p^s*log(p))/((N-s)!*s!)
Links to the documentation: operator :=, define, fundef

Don't use the variable s in your loop, because it's used in function.
You can first get a function and then evaulate:
for t: 1 thru 10 step 1 do (
display(t),
pr_val: ddn_binom( s1, 100, 0.5 ),
pr_val:ev(pr_val,s1=t),
display(pr_val)
);
You can also use subst:
for t: 1 thru 10 step 1 do (
display(t),
pr_val: subst(t,s1,ddn_binom( s1, 100, 0.5 )),
display(pr_val)
);

Related

How to substitute expressions containing units when using the ezunits package?

Without specifying units, I can express area and volume and have Maxima show the relationship:
(%i1) areaNoUnits: area = width * length$
(%i2) volumeNoUnits: volume = area * height$
(%i3) volumeNoUnits, areaNoUnits;
(%o3) volume = height length width
(%i4) subst(areaNoUnits, volumeNoUnits);
(%o4) volume = height length width
Now I want to specify units so I will use the ezunits package.
The ` (backtick) operator is the building block of ezunits:
An expression a ` b represents a dimensional quantity, with a indicating a nondimensional quantity and b indicating the dimensional units.
When I add units to the area and volume expressions, evaluation and substitution do not work:
(%i1) load ("ezunits")$
(%i2) areaWithUnits: area ` m^2 = (width ` m) * (length ` m);
2 2
(%o2) area ` m = length width ` m
(%i3) volumeWithUnits: volume ` m^3 = (area ` m^2) * (height ` m);
3 3
(%o3) volume ` m = area height ` m
(%i4) volumeWithUnits, areaWithUnits;
3 3
(%o4) volume ` m = area height ` m
(%i5) subst(areaWithUnits, volumeWithUnits);
3 3
(%o5) volume ` m = area height ` m
The expected output is:
volumeWithUnits, areaWithUnits;
3 3
volume ` m = height length width ` m
I do not see a function in the ezunits package to do evaluation or substitution. What is the right way to do this?
I would phrase it like this:
(%i2) load (ezunits) $
(%i3) width: W ` m;
(%o3) W ` m
(%i4) length: L ` m;
(%o4) L ` m
(%i5) area: width * length;
2
(%o5) L W ` m
(%i6) height: H ` m;
(%o6) H ` m
(%i7) volume: area * height;
3
(%o7) H L W ` m
I wrote each part as conceptualname: symbolforquantity ` unit and then wrote just conceptualname in further calculations, instead of conceptualname ` unit.
The substitution you tried in %i5 didn't work because subst is a purely formal substitution -- if there isn't a literal subexpression which is the same as the substituted-for expression, it doesn't match; subst doesn't look for rearrangements or factorizations which could help make a match. There are ways to work around that, so it might be possible to make your original formulation work, but I think it's better overall to sidestep the problem and work with conceptualname and symbolforquantity ` unit.
To say a little about what more one could do with expressions like %o7 above. There are at least two ways to replace symbols H, L, and W with specific values. One is to call subst:
(%i2) load (ezunits) $
(%i3) volume: H*L*W ` m^3;
3
(%o3) H L W ` m
(%i4) subst ([L = 20, W = %pi], volume);
3
(%o4) 20 %pi H ` m
Another is to make use of ev.
(%i5) ev (volume, L = 20, W = %pi);
3
(%o5) 20 %pi H ` m
Note that at the input prompt, something, someflags, somevalues is equivalent to ev(something, someflags, somevalues).
(%i6) volume, L = 20, W = %pi;
3
(%o6) 20 %pi H ` m
This is just a convenience. Within a function, one has to say ev(...); the shorter syntax isn't understood there.
ev is often convenient, but it's generally simpler to predict what the result is going to be with subst instead.

Maxima: Round like in Excel

Is there a function which rounds numbers (even decimal numbers) like round() in Excel?
Example
Round 1,45 to one decimal: 1,5
Round 2,45 to one decimal: 2,5
There is a similar question but they use a different algorithm.
OK, here's an attempt to reimplement Excel =ROUND function in Maxima. Some notes. (1) Values are rounded to 15 significant digits before applying the user's rounding. This is an attempt to work around problems caused by inexact representation of decimals as floating point numbers. (2) I've implemented excel_round and integer_log10 as so-called simplifying functions. That means that the calculation isn't carried out until the arguments are something that can be evaluated (in this case, when the arguments are numbers). (3) I didn't check to see what Excel =ROUND does with negative numbers -- does it round 5 upward (i.e., towards zero in this case), or away from zero? I dunno.
I've posted this solution as the little package excel_round.mac on Github. See: https://github.com/maxima-project-on-github/maxima-packages and navigate to robert-dodier/excel_round. In the interest of completeness, I've pasted the code here as well.
Here are a few examples.
(%i1) excel_round (1.15, 1);
(%o1) 1.2
(%i2) excel_round (1.25, 1);
(%o2) 1.3
(%i3) excel_round (12.455, 2);
(%o3) 12.46
(%i4) excel_round (x, 2);
(%o4) excel_round(x, 2)
(%i5) ev (%, x = 9.865);
(%o5) 9.87
Here is the code. This is the content of excel_round.mac.
/* excel_round -- round to specified number of decimal places,
* rounding termminal 5 upwards, as in MS Excel, apparently.
* Inspired by: https://stackoverflow.com/q/62533742/871096
*
* copyright 2020 by Robert Dodier
* I release this work under terms of the GNU General Public License.
*/
matchdeclare (xx, numberp);
matchdeclare (nn, integerp);
tellsimpafter (excel_round (xx, nn), excel_round_numerical (xx, nn));
matchdeclare (xx, lambda ([e], block ([v: ev (e, numer)], numberp(v))));
tellsimpafter (excel_round (xx, nn), excel_round_numerical (ev (xx, numer), nn));
excel_round_numerical (x, n) :=
block ([r, r1, r2, l],
/* rationalize returns exact rational equivalent of float */
r: rationalize (x),
/* First round to 15 significant decimal places.
* This is a heuristic to recover what a user "meant"
* to type in, since many decimal numbers are not
* exactly representable as floats.
*/
l: integer_log10 (abs (r)),
r1: round (r*10^(15 - l)),
/* Now begin rounding to n places. */
r2: r1/10^((15 - l) - n),
/* If terminal digit is 5, then r2 is integer + 1/2.
* If that's the case, round upwards and rescale,
* otherwise, terminal digit is something other than 5,
* round to nearest integer and rescale.
*/
if equal (r2 - floor(r2), 1/2)
then ceiling(r2)/10.0^n
else round(r2)/10.0^n);
matchdeclare (xx, lambda ([e], numberp(e) and e > 0));
tellsimpafter (integer_log10 (xx), integer_log10_numerical (xx));
matchdeclare (xx, lambda ([e], block ([v: ev (e, numer)], numberp(v) and v > 0)));
tellsimpafter (integer_log10 (xx), integer_log10_numerical (ev (xx, numer)));
matchdeclare (xx, lambda ([e], not atom(e) and op(e) = "/" and numberp (denom (e)) and pow10p (denom (e))));
pow10p (e) := integerp(e) and e > 1 and (e = 10 or pow10p (e/10));
tellsimpafter (integer_log10 (xx), integer_log10 (num (xx)) - integer_log10_numerical (denom (xx)));
integer_log10_numerical (x) :=
if x >= 10
then (for i from 0 do
if x >= 10 then x:x/10 else return(i))
elseif x < 1
then (for i from 0 do
if x < 1 then x:x*10 else return(-i))
else 0;
The problem of rounding numbers is actually pretty subtle, but here is a simple approach which I think gives workable results. Here I define a new function myround which has the behavior described for Excel =ROUND. [1]
(%i4) myround (x, n) := round(x*10^n)/10.0^n;
n
'round(x 10 )
(%o4) myround(x, n) := -------------
n
10.0
(%i5) myround (2.15, 1);
(%o5) 2.2
(%i6) myround (2.149, 1);
(%o6) 2.1
(%i7) myround (-1.475, 2);
(%o7) - 1.48
(%i8) myround (21.5, -1);
(%o8) 20.0
(%i9) myround (626.3, -3);
(%o9) 1000.0
(%i10) myround (1.98, -1);
(%o10) 0.0
(%i11) myround (-50.55, -2);
(%o11) - 100.0
[1] https://support.microsoft.com/en-us/office/round-function-c018c5d8-40fb-4053-90b1-b3e7f61a213c

How to expand in taylor series a composition of functions?

I would like to expand in taylor series a function of type : f(x+f(x)) around x=a in the case where f(a)=0.
(%i1) atvalue(f(x),[x=a],0)$
The direct calculus yields :
(%i2) taylor(f(x+f(x)),x,a,2);
(%o2)/T/ f(a)+(at('diff(f(f(x)+x),x,1),x=a))*(x-a)+((at('diff(f(f(x)+x),x,2),x=a))*(x-a)^2)/2+...
If I define a intermediate function :
(%i3)define(tf(x),taylor(f(x),x,a,2))$
Then a expand in Taylor series I get :
(%i4) taylor(f(x+tf(x)),x,a,2);
(%o4) 0+...
I expect the following result :
f(1+f'(a))f'(a)(x-a)+(x-a)^2 f''(a)[f'(a)+(1+f'(a))^2/2]+o(x-a)^2
How could I solve this problem?
You can use gradef to simplify notation.
gradef(f(x), f1(x)) $
gradef(f1(x), f2(x)) $
atvalue(f(x), x = a, 0) $
e: f(x+f(x)) $
e: taylor(e, x, a, 2) $
e: expand(e, 0, 0)$ /* 'taylor' form to ordinar expression */
e: ev(e, nouns); /* f(a) to 0 */
returns
2 2
(f1 (a) f2(a) + 3 f1(a) f2(a) + f2(a)) (x - a)
(%o7) -----------------------------------------------
2
2
+ (f1 (a) + f1(a)) (x - a)
A solution is as follow :
gradef(f(x), f1(x)) $
gradef(f1(x), f2(x)) $
atvalue(f(x), x = a, 0) $
e: f(x+f(x)) $
e: taylor(e, x, a, 2) $
e: expand(e, 0, 0)$ /* 'taylor' form to ordinar expression*/
e: ev(e, nouns); /* f(a) to 0 */
taylor(e,x,a,2); /* Becomes again a taylor serie which could be reused*/
For example, if I want to find the order of the Steffensen method which is defined, for function f which is C^2 and f(a)=0,f'(a)!=0, by :
Sf(x)=x-f(x)^2/(f(x+f(x)-f(x))
If I straight expand this function around a I get :
Sf(x)=a+(x-a)-(f1(a)^2*(x-a)^2)/f(a)+...
which diverges since f(a)=0.
So this must be proceed in two steps. First I expand the denominator :
den:f(x+f(x))-f(x)$
t:taylor(den,x,a,2);
t: expand(t, 0, 0)$
t: ev(t, nouns)$
t:taylor(t,x,a,2);
Then I expand the function Sf:
Sf:x-f(x)^2/(t)$/*Introducing the taylor serie of den*/
taylor(Sf,x,a,2);
which provides the wanted result :
Sf(x)=a+((f1(a)+1)*f2(a)*(x-a)^2)/(2*f1(a))+...

high order derivatives in lua?

I was messing around with high order derivatives on lua (i haven't tested this on any different language) and found that the lowest you set delta to the sooner it will output 0.0, look at this code and then the output
why does this happen?
function derivate (f, delta)
delta = delta or 1e-4
return function(x) return (f(x + delta) - f(x)) / delta end
end
c = derivate ( math.cos )
-- c is now -sinx
d = derivate (c)
-- d is now -cosx
e = derivate (d)
-- e is now sinx
f = derivate (e)
-- f is now cosx
print(math.cos(1.23 ), c(1.23) , d(1.23) , e(1.23) , f(1.23) )
output :
0.3342377271245 -0.94250551224695 -0.3341434795523 0.94257934790676 0.0

Stop maxima from asking positive, negative or zero

Is there some way to tell maxima that an expression is always positive? Here is an example snippet that causes maxima to ask the question for the expression sin(a)*x:
declare([a,x,y],real);
ca: cos(a) = (x / (sqrt(x*x + y*y)));
a1: solve(ca,a)[1];
solve(a1,y);
You can use assume. From Maxima's own documentation:
-- Function: assume (, ..., )
Adds predicates , ..., to the current context.
If a predicate is inconsistent or redundant with the predicates in
the current context, it is not added to the context. The context
accumulates predicates from each call to `assume'.
`assume' returns a list whose elements are the predicates added to
the context or the atoms `redundant' or `inconsistent' where
applicable.
The predicates , ..., can only be expressions
with the relational operators `=' and `>'.
Predicates cannot be literal equality `=' or literal inequality
`#' expressions, nor can they be predicate functions such as
`integerp'.
Compound predicates of the form ` and ... and '
are recognized, but not ` or ... or '. `not
' is recognized if is a relational predicate.
Expressions of the form `not ( and )' and `not
( or )' are not recognized.
Maxima's deduction mechanism is not very strong; there are many
obvious consequences which cannot be determined by `is'. This is
a known weakness.
`assume' evaluates its arguments.
See also `is', `facts', `forget', `context', and `declare'.
Examples:
(%i1) assume (xx > 0, yy < -1, zz >= 0);
(%o1) [xx > 0, yy < - 1, zz >= 0]
(%i2) assume (aa < bb and bb < cc);
(%o2) [bb > aa, cc > bb]
(%i3) facts ();
(%o3) [xx > 0, - 1 > yy, zz >= 0, bb > aa, cc > bb]
(%i4) is (xx > yy);
(%o4) true
(%i5) is (yy < -yy);
(%o5) true
(%i6) is (sinh (bb - aa) > 0);
(%o6) true
(%i7) forget (bb > aa);
(%o7) [bb > aa]
(%i8) prederror : false;
(%o8) false
(%i9) is (sinh (bb - aa) > 0);
(%o9) unknown
(%i10) is (bb^2 < cc^2);
(%o10) unknown
'assume' works when there is a space either side of the relational operator. In other words in my instance: assume(L>0) does not work, but assume(L > 0) does work!

Resources