The following integral does is not evaluated by Maxima:
integrate(charfun(x<1/2), x, 0, 1);
Is there a different trick to make it work, or is it simply un-implemented?
The share package abs_integrate can integrate some expressions containing signum, abs, and unit_step. In this case you can write charfun(x < 1/2) in terms of signum(1/2 - x) and then abs_integrate can handle it.
You'll need to load abs_integrate. Note that abs_integrate modifies the behavior of integrate; there isn't a separate abs_integrate function to call.
(%i2) load (abs_integrate) $
(%i3) integrate (signum (1/2 - x), x, 0, 1);
(%o3) 0
(%i4) integrate (signum (1/2 - x), x, -1, 1);
(%o4) 1
(%i5) foo (e) := (1 + signum(e))/2;
1 + signum(e)
(%o5) foo(e) := -------------
2
(%i6) integrate (foo (1/2 - x), x, 0, 1);
1
(%o6) -
2
(%i7) integrate (foo (1/2 - x), x, -1, 1);
3
(%o7) -
2
Note that foo corresponds to charfun here.
Related
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
I have the following cubic polynomial f(x)=x³ - 3 x² + x -5 for which the cubic spline should provide the exact same polynomial assuming the following data:
(-1, -10), (0,-5), (1, -6) with second derivative at the extremes f''(-1)=-12, f''(1)=0 (note that f''(x)=6x-6.)
Here the piece of code that I tried on:
/* polynomial to interpolate and data */
f(x) := x^3 - 3* x^2 + x - 5$
x0:-1$
x1:0$
x2:1$
y0:f(x0)$
y1:f(x1)$
y2:f(x2)$
p:[[x0,y0],[x1,y1],[x2,y2]]$
fpp(x) := diff(f(x),x,2);
fpp0 : at( fpp(x), [x=x0]);
fpp2 : at( fpp(x), [x=x2]);
/* here I call cspline with d1=fpp0 and dn=fpp2 */
load(interpol)$
cspline(p, d1=fpp0, dn=fpp2);
I expected the original polynomial (f(x)=x³ -3 x² + x -5) but I got the result:
(%o40) (-16*x^3-15*x^2+6*x-5)*charfun2(x,-inf,0)+(8*x^3-15*x^2+6*x-5)*charfun2(x,0,inf)
which does not agrees with the original polynomial.
Evenmore. Here is a test on the results provided by Maxima.
Code:
/* verification */
h11(x) := -16*x^3 - 15* x^2 + 6* x - 5;
h22(x) := 8* x^3 - 15*x^2 + 6* x - 5;
h11pp(x) := diff(h11(x), x, 2);
h11pp0: at( h11pp(x), [x=x0]);
h22pp(x) := diff(h22(x), x, 2);
h22pp2 : at(h22pp(x), [x=x2]);
which throws 66 and 18 as the boundary conditions, which should be instead -12 and 0.
Thanks.
It appears you've misinterpreted the arguments d1 and dn for cspline. As the description of cspline says, d1 and dn specify the first derivative for the spline at the endpoints, not the second derivative.
When I use the first derivative of f to specify the values for d1 and dn, I get the expected result:
(%i2) f(x) := x^3 - 3* x^2 + x - 5$
(%i3) [x0, x1, x2]: [-1, 0, 1] $
(%i4) [y0, y1, y2]: map (f, %);
(%o4) [- 10, - 5, - 6]
(%i5) p: [[x0, y0], [x1, y1], [x2, y2]];
(%o5) [[- 1, - 10], [0, - 5], [1, - 6]]
(%i6) load (interpol) $
(%i7) cspline (p, d1 = at(diff(f(x), x), x=x0), dn = at(diff(f(x), x), x=x2));
3 2
(%o7) (x - 3 x + x - 5) charfun2(x, minf, 0)
3 2
+ (x - 3 x + x - 5) charfun2(x, 0, inf)
I have the logistic map function in Maxima like so:
F(x,r,n):= x[n]=r*x[n-1]*(1-x[n-1]);
And when I input the correct variables it gives me the answer to, for example, x[0]:
(%i15) n:0$
x[n-1]:[0.1]$
F(x, r:3, n);
(%o15) x[0]=[0.27]
However, this answer does not stay memorized and when I enter x[0] I get
x[0];
(%o5) x[0]
How do I write a function that will calculate x[n] for me and store it in memory, so I can use it later? I am trying to make a bifurcation diagram for the logistic map without using any black boxes, i.e., the orbits functions.
Thank you!
There are different ways to go about it. One straightforward way is to create a list and then iterate, computing its elements one by one. E.g.:
(%i4) x: makelist (0, 10);
(%o4) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
(%i5) x[1]: 0.1;
(%o5) 0.1
(%i6) r: 3;
(%o6) 3
(%i7) for i:2 thru 10 do x[i]: r * x[i - 1] * (1 - x[i - 1]);
(%o7) done
(%i8) x;
(%o8) [0.1, 0.2700000000000001, 0.5913000000000002,
0.7249929299999999, 0.5981345443500454, 0.7211088336156269,
0.603332651091411, 0.7179670896552621, 0.6074710434816448,
0.7153499244388992]
Note that : is the assignment operator, not =.
We have an online platform where we use maxima on the backend to give feedback on the answers that the student give.
Say that the solution of a polynomial long division is the following function:
sol: 3+(2+4*x)/(3*x^2+2*x+8);
Let's say that the student gives the answer:
ans: 3 +(3-5*x)/(3x^2+2*x+8)
We then want to give feedback along the lines.
Your answer is indeed of the following form:
The constant s is correct, but you didn't choose the right linear function r(x).
I try to implement this feedback in the following way:
ans: 3 +(3-5*x)/(3x^2+2*x+8);
remvalue(a,b,c,d);
matchdeclare([a,b,c,d], constantp);
defmatch(match, d+ (a*x+b)/(3*x^2+2*x+8));
match(ans);
However, defmatch doesn't seem to be able to match this. Is there any other function I can use for matching quotient function like this?
It does work in more simple scenarios:
ans: (3-5*x)/(3*x^2+2*x+8);
remvalue(a,b,c);
matchdeclare([a,b,c], constantp);
defmatch(match, (a*x+b)/(3*x^2+2*x+8));
match(ans);
If the problems are all polynomial division, maybe you can use the divide function which returns the quotient and remainder and then verify that the student's input is the same as quotient + remainder/divisor.
As to matching quotient + remainder/divisor, defmatch might not be powerful enough because it is mostly (although not entirely) looking for formal matches, and it can't, in many cases, detect expressions which are equivalent but formally different.
Let me think about how to implement a match function for this problem. Perhaps others have a suggestion too.
EDIT: Here's a way to match such expressions. I'll separate a ratio of polynomials from other terms. If there is one ratio term, and all the other terms are a polynomial, then the pattern you want is matched.
I've made use of at least one obscure but useful and even comprehensible feature of matching of "+" expressions. Since "+" is commutative, the pattern matcher sweeps up all the arguments which match the first predicate that is attempted, then sweeps through with the second, and so, if there are more than two predicts. If any pattern matching variable is declared to match all, it matches all arguments and there are none left. The pattern variables will be attempted in reverse order, so aa will be processed last. The effect is to divide a "+" expression into terms which match a stated predicate and a catch-all for everything else. This is made use of in %i7.
(%i2) matchdeclare (pp, lambda ([e], polynomialp (e, [pvar]))) $
(%i3) matchdeclare (qq, lambda ([e], diff (e, pvar) # 0 and polynomialp (e, [pvar]))) $
(%i4) defmatch (match_pratio, pp/qq, pvar) $
(%i5) matchdeclare (aa, all) $
(%i6) matchdeclare (rr, lambda ([e], match_pratio (e, pvar) # false)) $
(%i7) defmatch (match_pratio_plus_remainder, rr + aa, pvar) $
(%i8) match_foo (e, pvar) :=
block ([aa, pp, qq, rr],
if match_pratio (e, pvar) # false
then [0, pp, qq, pp/qq]
elseif match_pratio_plus_remainder (e, pvar) # false
then if polynomialp (aa, [pvar]) and op(rr) # "+"
then [aa, pp, qq, rr]) $
Here are some examples that match:
(%i9) match_foo (u^2/2 - 3*u + 1 + (u - 1)/(u^2 + u - 1), u);
2
u 2 u - 1
(%o9) [-- - 3 u + 1, u - 1, u + u - 1, ----------]
2 2
u + u - 1
(%i10) match_foo (u^2/2 - 3*u + 1 - 2*(u - 1)/(u^2 + u - 1), u);
2
u 2 2 (u - 1)
(%o10) [-- - 3 u + 1, - 2 (u - 1), u + u - 1, - ----------]
2 2
u + u - 1
(%i11) match_foo (u^2/2 - 3*u + 1 - 2/(u^2 + u - 1), u);
2
u 2 2
(%o11) [-- - 3 u + 1, - 2, u + u - 1, - ----------]
2 2
u + u - 1
(%i12) match_foo (1 - 2/(u^2 + u - 1), u);
2 2
(%o12) [1, - 2, u + u - 1, - ----------]
2
u + u - 1
(%i13) match_foo (- 2/(u^2 + u - 1), u);
2 2
(%o13) [0, - 2, u + u - 1, - ----------]
2
u + u - 1
Here are some examples that don't match: two polynomial ratio terms, no polynomial ratio, and a nonpolynomial term.
(%i14) match_foo (1/u - 2/(u^2 + u - 1), u);
(%o14) false
(%i15) match_foo (1 - (u^2 + u - 1)/2, u);
(%o15) false
(%i16) match_foo (sin(u) - 2/(u^2 + u - 1), u);
(%o16) false
SECOND EDIT: I think I've misnamed match_pratio_plus_remainder, it should probably be match_remainder_plus_quotient. Oh well.
I want to display the partial derivative df/dx of f(x,y) = ln(y-1-x^2)-xy^2.
A comparable example for what I want is:
(%i0) f(x) := x^8$
(%i1) diff(f(x),x);
(%o1) 8*x^7
I've tried:
(%i1) f(x,y):=ln(y-1-x^2)-xy^2$
(%i2) g(x,y):=(diff(f(x,y), x));
(%o2) g(x,y):='diff(f(x,y),x,1)
(%i3) g(x,y):=''(diff(f(x,y), x));
(%o3) g(x,y):='diff(ln(y-x^2-1),x,1)
But it doesn't work (the summand -xy^2 got deleted?).
I want the derivated function. Something like this:
(2*x)
g(x,y):= ——————————— - y^2
(1 + x^2 - y)
the problem with your funciotn is that xy^2 instead of x*y^2for maxima is a variable you should write it as follows:
(%i5) f(x,y):=ln(y-1-x^2)-x*y^2;
(\%o5) f\left(x , \linebreak[0]y\right):=\mathrm{ln}\left(y-1-x^2\right)-x\,y^2
(%i6) diff(f(x,y), x);
(\%o6) \ifracd{d}{d\,x}\,\mathrm{ln}\left(y-x^2-1\right)-y^2