Hello everyone,
Does anyone know how to calculate real roots of degree 3 polynomial with JMP scripting ?
I have the coefficients of the equation : 0 = A + B.X + C.X² + DX^3. What I need is the real solutions.
I started to create a new data table with lots of rows in order to get as close as possible to the desired value, but it takes too much time.
Thanks,
(Not a mathematician, I'm sure this has some flaws...) Similar to your original idea, but make JSL do the work. I'm pretty sure Minimize has seen some improvements since JMP 10. https://community.jmp.com/t5/JMPer-Cable/Minimize-and-Maximize-Functions-in-JSL/ba-p/36355/jump-to/f...
a = -2;
b = -3;
c = 5;
d = 1;
f = Function( {x},
a + b * x + c * x * x + d * x * x * x
);
lo = -1e99;
hi = 1e99;
vlo = f( lo );
vhi = f( hi );
v = 1;
nn=0;
While( (abs(v)>1e-15) ,
test = (lo + hi) / 2;
v = f( test );
If( v > 0,
If(
vhi > 0, hi = test,
vlo > 0, lo = test
),
If(
vhi < 0, hi = test,
vlo < 0, lo = test
)
);
);
New Window( "Example",
Graph Box(
X Scale( -10, 10 ),
Y Scale( -30, 30 ),
Pen Color( "red" );
Y Function( f(x), x );
pencolor("black");
V Line( test );
hline(0);
)
);
If the coefficients on the ^2 and ^3 terms are too big, you'll need to make the -1e99 to 1e99 interval smaller.
You can use this formula to get the first root, substitute that x value into the expression to reduce the polyomial orrder to 2, and the use the quadratic soltution to obtain the remaining roots.
Thank you for this answer.
It's indeed a way of doing, but I'm affraid that won't work everytime I will use the script : the square root of a negative number is the reason why.
In Excel I'm able to do it, but not on JMP, and I rather prefer not to use two softwares for one script.
Does anyone have another way of doing it?
Maybe the Minimize() function can help.Since it find the minimum, rather than the zero, you have to transform your cubic so the zero is at the minimum. Presumably squaring is better than absolute value because the Minimum function says it will take derivatives.
f = Expr( Power( -2 - 3 * x + 5 * Power( x, 2 ) + Power( x, 3 ), 2 ) );
x = -100;
minFromLeft = Minimize( Name Expr( f ), {x} );
xFromLeft = x;
x = 100;
minFromRight = Minimize( Name Expr( f ), {x} );
xFromRight = x;
show(xFromLeft, minFromLeft, xFromRight, minFromRight);
// result:
xFromLeft = -5.5995441248061;
minFromLeft = 1.07130883787516e-10;
xFromRight = 0.276987650239635;
minFromRight = 2.4771578468284;
Searching from the left and the right if you know such bounds should find at least one real root, and with that the problem becomes quadratic.
The minimize function seems a good way of doing it, but I cannot make it work :
I've tried your script, but at the row 3 ( minFromLeft = Minimize( Name Expr( f ), {x} ); )
I get the following alert :
"Optimization failed: Failed: Cannot Decrease Objective Function"
I've the JMP version 10.0.0.
Does it have anything to do with that?
(Not a mathematician, I'm sure this has some flaws...) Similar to your original idea, but make JSL do the work. I'm pretty sure Minimize has seen some improvements since JMP 10. https://community.jmp.com/t5/JMPer-Cable/Minimize-and-Maximize-Functions-in-JSL/ba-p/36355/jump-to/f...
a = -2;
b = -3;
c = 5;
d = 1;
f = Function( {x},
a + b * x + c * x * x + d * x * x * x
);
lo = -1e99;
hi = 1e99;
vlo = f( lo );
vhi = f( hi );
v = 1;
nn=0;
While( (abs(v)>1e-15) ,
test = (lo + hi) / 2;
v = f( test );
If( v > 0,
If(
vhi > 0, hi = test,
vlo > 0, lo = test
),
If(
vhi < 0, hi = test,
vlo < 0, lo = test
)
);
);
New Window( "Example",
Graph Box(
X Scale( -10, 10 ),
Y Scale( -30, 30 ),
Pen Color( "red" );
Y Function( f(x), x );
pencolor("black");
V Line( test );
hline(0);
)
);
If the coefficients on the ^2 and ^3 terms are too big, you'll need to make the -1e99 to 1e99 interval smaller.
I've selected the answer that works for me with my JMP version.
Thank you all for your help!
I tried both Minimize() and the Nonlinear platform. Both works well to solve polynomials, but it's easy to miss one or more roots because of a bad initial value. Looking at the graph helps.
If you have R installed you could try this JSL function:
Names Default To Here(1);
// Function calling R, returns real roots of polynomials
// Input: a matrix of coefficients [x^0 ... x^n]
realroots = Function({p},
R Init();
R Send(p);
R Submit("roots=polyroot(p); real=Re(roots[which(round(Im(roots),12)==0)])");
real = R Get(real);
R Term();
real;
);
// Try it!
p1 = [-4 0 1]; // two real roots: ±2^2=4
p2 = [-27 0 0 1]; // one real root: 3^3=27
p3 = [7 -8 4 1]; // one real root
p4 = [1 -3 1 1]; // three real roots
ex1 = realroots(p1);
ex2 = realroots(p2);
ex3 = realroots(p3);
ex4 = realroots(p4);
Show(ex1, ex2, ex3, ex4);