Spaces:
Running
Running
"""Tests for algorithms for computing symbolic roots of polynomials. """ | |
from sympy.core.numbers import (I, Rational, pi) | |
from sympy.core.singleton import S | |
from sympy.core.symbol import (Symbol, Wild, symbols) | |
from sympy.functions.elementary.complexes import (conjugate, im, re) | |
from sympy.functions.elementary.exponential import exp | |
from sympy.functions.elementary.miscellaneous import (root, sqrt) | |
from sympy.functions.elementary.piecewise import Piecewise | |
from sympy.functions.elementary.trigonometric import (acos, cos, sin) | |
from sympy.polys.domains.integerring import ZZ | |
from sympy.sets.sets import Interval | |
from sympy.simplify.powsimp import powsimp | |
from sympy.polys import Poly, cyclotomic_poly, intervals, nroots, rootof | |
from sympy.polys.polyroots import (root_factors, roots_linear, | |
roots_quadratic, roots_cubic, roots_quartic, roots_quintic, | |
roots_cyclotomic, roots_binomial, preprocess_roots, roots) | |
from sympy.polys.orthopolys import legendre_poly | |
from sympy.polys.polyerrors import PolynomialError, \ | |
UnsolvableFactorError | |
from sympy.polys.polyutils import _nsort | |
from sympy.testing.pytest import raises, slow | |
from sympy.core.random import verify_numerically | |
import mpmath | |
from itertools import product | |
a, b, c, d, e, q, t, x, y, z = symbols('a,b,c,d,e,q,t,x,y,z') | |
def _check(roots): | |
# this is the desired invariant for roots returned | |
# by all_roots. It is trivially true for linear | |
# polynomials. | |
nreal = sum(1 if i.is_real else 0 for i in roots) | |
assert sorted(roots[:nreal]) == list(roots[:nreal]) | |
for ix in range(nreal, len(roots), 2): | |
if not ( | |
roots[ix + 1] == roots[ix] or | |
roots[ix + 1] == conjugate(roots[ix])): | |
return False | |
return True | |
def test_roots_linear(): | |
assert roots_linear(Poly(2*x + 1, x)) == [Rational(-1, 2)] | |
def test_roots_quadratic(): | |
assert roots_quadratic(Poly(2*x**2, x)) == [0, 0] | |
assert roots_quadratic(Poly(2*x**2 + 3*x, x)) == [Rational(-3, 2), 0] | |
assert roots_quadratic(Poly(2*x**2 + 3, x)) == [-I*sqrt(6)/2, I*sqrt(6)/2] | |
assert roots_quadratic(Poly(2*x**2 + 4*x + 3, x)) == [-1 - I*sqrt(2)/2, -1 + I*sqrt(2)/2] | |
_check(Poly(2*x**2 + 4*x + 3, x).all_roots()) | |
f = x**2 + (2*a*e + 2*c*e)/(a - c)*x + (d - b + a*e**2 - c*e**2)/(a - c) | |
assert roots_quadratic(Poly(f, x)) == \ | |
[-e*(a + c)/(a - c) - sqrt(a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c), | |
-e*(a + c)/(a - c) + sqrt(a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c)] | |
# check for simplification | |
f = Poly(y*x**2 - 2*x - 2*y, x) | |
assert roots_quadratic(f) == \ | |
[-sqrt(2*y**2 + 1)/y + 1/y, sqrt(2*y**2 + 1)/y + 1/y] | |
f = Poly(x**2 + (-y**2 - 2)*x + y**2 + 1, x) | |
assert roots_quadratic(f) == \ | |
[1,y**2 + 1] | |
f = Poly(sqrt(2)*x**2 - 1, x) | |
r = roots_quadratic(f) | |
assert r == _nsort(r) | |
# issue 8255 | |
f = Poly(-24*x**2 - 180*x + 264) | |
assert [w.n(2) for w in f.all_roots(radicals=True)] == \ | |
[w.n(2) for w in f.all_roots(radicals=False)] | |
for _a, _b, _c in product((-2, 2), (-2, 2), (0, -1)): | |
f = Poly(_a*x**2 + _b*x + _c) | |
roots = roots_quadratic(f) | |
assert roots == _nsort(roots) | |
def test_issue_7724(): | |
eq = Poly(x**4*I + x**2 + I, x) | |
assert roots(eq) == { | |
sqrt(I/2 + sqrt(5)*I/2): 1, | |
sqrt(-sqrt(5)*I/2 + I/2): 1, | |
-sqrt(I/2 + sqrt(5)*I/2): 1, | |
-sqrt(-sqrt(5)*I/2 + I/2): 1} | |
def test_issue_8438(): | |
p = Poly([1, y, -2, -3], x).as_expr() | |
roots = roots_cubic(Poly(p, x), x) | |
z = Rational(-3, 2) - I*7/2 # this will fail in code given in commit msg | |
post = [r.subs(y, z) for r in roots] | |
assert set(post) == \ | |
set(roots_cubic(Poly(p.subs(y, z), x))) | |
# /!\ if p is not made an expression, this is *very* slow | |
assert all(p.subs({y: z, x: i}).n(2, chop=True) == 0 for i in post) | |
def test_issue_8285(): | |
roots = (Poly(4*x**8 - 1, x)*Poly(x**2 + 1)).all_roots() | |
assert _check(roots) | |
f = Poly(x**4 + 5*x**2 + 6, x) | |
ro = [rootof(f, i) for i in range(4)] | |
roots = Poly(x**4 + 5*x**2 + 6, x).all_roots() | |
assert roots == ro | |
assert _check(roots) | |
# more than 2 complex roots from which to identify the | |
# imaginary ones | |
roots = Poly(2*x**8 - 1).all_roots() | |
assert _check(roots) | |
assert len(Poly(2*x**10 - 1).all_roots()) == 10 # doesn't fail | |
def test_issue_8289(): | |
roots = (Poly(x**2 + 2)*Poly(x**4 + 2)).all_roots() | |
assert _check(roots) | |
roots = Poly(x**6 + 3*x**3 + 2, x).all_roots() | |
assert _check(roots) | |
roots = Poly(x**6 - x + 1).all_roots() | |
assert _check(roots) | |
# all imaginary roots with multiplicity of 2 | |
roots = Poly(x**4 + 4*x**2 + 4, x).all_roots() | |
assert _check(roots) | |
def test_issue_14291(): | |
assert Poly(((x - 1)**2 + 1)*((x - 1)**2 + 2)*(x - 1) | |
).all_roots() == [1, 1 - I, 1 + I, 1 - sqrt(2)*I, 1 + sqrt(2)*I] | |
p = x**4 + 10*x**2 + 1 | |
ans = [rootof(p, i) for i in range(4)] | |
assert Poly(p).all_roots() == ans | |
_check(ans) | |
def test_issue_13340(): | |
eq = Poly(y**3 + exp(x)*y + x, y, domain='EX') | |
roots_d = roots(eq) | |
assert len(roots_d) == 3 | |
def test_issue_14522(): | |
eq = Poly(x**4 + x**3*(16 + 32*I) + x**2*(-285 + 386*I) + x*(-2824 - 448*I) - 2058 - 6053*I, x) | |
roots_eq = roots(eq) | |
assert all(eq(r) == 0 for r in roots_eq) | |
def test_issue_15076(): | |
sol = roots_quartic(Poly(t**4 - 6*t**2 + t/x - 3, t)) | |
assert sol[0].has(x) | |
def test_issue_16589(): | |
eq = Poly(x**4 - 8*sqrt(2)*x**3 + 4*x**3 - 64*sqrt(2)*x**2 + 1024*x, x) | |
roots_eq = roots(eq) | |
assert 0 in roots_eq | |
def test_roots_cubic(): | |
assert roots_cubic(Poly(2*x**3, x)) == [0, 0, 0] | |
assert roots_cubic(Poly(x**3 - 3*x**2 + 3*x - 1, x)) == [1, 1, 1] | |
# valid for arbitrary y (issue 21263) | |
r = root(y, 3) | |
assert roots_cubic(Poly(x**3 - y, x)) == [r, | |
r*(-S.Half + sqrt(3)*I/2), | |
r*(-S.Half - sqrt(3)*I/2)] | |
# simpler form when y is negative | |
assert roots_cubic(Poly(x**3 - -1, x)) == \ | |
[-1, S.Half - I*sqrt(3)/2, S.Half + I*sqrt(3)/2] | |
assert roots_cubic(Poly(2*x**3 - 3*x**2 - 3*x - 1, x))[0] == \ | |
S.Half + 3**Rational(1, 3)/2 + 3**Rational(2, 3)/2 | |
eq = -x**3 + 2*x**2 + 3*x - 2 | |
assert roots(eq, trig=True, multiple=True) == \ | |
roots_cubic(Poly(eq, x), trig=True) == [ | |
Rational(2, 3) + 2*sqrt(13)*cos(acos(8*sqrt(13)/169)/3)/3, | |
-2*sqrt(13)*sin(-acos(8*sqrt(13)/169)/3 + pi/6)/3 + Rational(2, 3), | |
-2*sqrt(13)*cos(-acos(8*sqrt(13)/169)/3 + pi/3)/3 + Rational(2, 3), | |
] | |
def test_roots_quartic(): | |
assert roots_quartic(Poly(x**4, x)) == [0, 0, 0, 0] | |
assert roots_quartic(Poly(x**4 + x**3, x)) in [ | |
[-1, 0, 0, 0], | |
[0, -1, 0, 0], | |
[0, 0, -1, 0], | |
[0, 0, 0, -1] | |
] | |
assert roots_quartic(Poly(x**4 - x**3, x)) in [ | |
[1, 0, 0, 0], | |
[0, 1, 0, 0], | |
[0, 0, 1, 0], | |
[0, 0, 0, 1] | |
] | |
lhs = roots_quartic(Poly(x**4 + x, x)) | |
rhs = [S.Half + I*sqrt(3)/2, S.Half - I*sqrt(3)/2, S.Zero, -S.One] | |
assert sorted(lhs, key=hash) == sorted(rhs, key=hash) | |
# test of all branches of roots quartic | |
for i, (a, b, c, d) in enumerate([(1, 2, 3, 0), | |
(3, -7, -9, 9), | |
(1, 2, 3, 4), | |
(1, 2, 3, 4), | |
(-7, -3, 3, -6), | |
(-3, 5, -6, -4), | |
(6, -5, -10, -3)]): | |
if i == 2: | |
c = -a*(a**2/S(8) - b/S(2)) | |
elif i == 3: | |
d = a*(a*(a**2*Rational(3, 256) - b/S(16)) + c/S(4)) | |
eq = x**4 + a*x**3 + b*x**2 + c*x + d | |
ans = roots_quartic(Poly(eq, x)) | |
assert all(eq.subs(x, ai).n(chop=True) == 0 for ai in ans) | |
# not all symbolic quartics are unresolvable | |
eq = Poly(q*x + q/4 + x**4 + x**3 + 2*x**2 - Rational(1, 3), x) | |
sol = roots_quartic(eq) | |
assert all(verify_numerically(eq.subs(x, i), 0) for i in sol) | |
z = symbols('z', negative=True) | |
eq = x**4 + 2*x**3 + 3*x**2 + x*(z + 11) + 5 | |
zans = roots_quartic(Poly(eq, x)) | |
assert all(verify_numerically(eq.subs(((x, i), (z, -1))), 0) for i in zans) | |
# but some are (see also issue 4989) | |
# it's ok if the solution is not Piecewise, but the tests below should pass | |
eq = Poly(y*x**4 + x**3 - x + z, x) | |
ans = roots_quartic(eq) | |
assert all(type(i) == Piecewise for i in ans) | |
reps = ( | |
{"y": Rational(-1, 3), "z": Rational(-1, 4)}, # 4 real | |
{"y": Rational(-1, 3), "z": Rational(-1, 2)}, # 2 real | |
{"y": Rational(-1, 3), "z": -2}) # 0 real | |
for rep in reps: | |
sol = roots_quartic(Poly(eq.subs(rep), x)) | |
assert all(verify_numerically(w.subs(rep) - s, 0) for w, s in zip(ans, sol)) | |
def test_issue_21287(): | |
assert not any(isinstance(i, Piecewise) for i in roots_quartic( | |
Poly(x**4 - x**2*(3 + 5*I) + 2*x*(-1 + I) - 1 + 3*I, x))) | |
def test_roots_quintic(): | |
eqs = (x**5 - 2, | |
(x/2 + 1)**5 - 5*(x/2 + 1) + 12, | |
x**5 - 110*x**3 - 55*x**2 + 2310*x + 979) | |
for eq in eqs: | |
roots = roots_quintic(Poly(eq)) | |
assert len(roots) == 5 | |
assert all(eq.subs(x, r.n(10)).n(chop = 1e-5) == 0 for r in roots) | |
def test_roots_cyclotomic(): | |
assert roots_cyclotomic(cyclotomic_poly(1, x, polys=True)) == [1] | |
assert roots_cyclotomic(cyclotomic_poly(2, x, polys=True)) == [-1] | |
assert roots_cyclotomic(cyclotomic_poly( | |
3, x, polys=True)) == [Rational(-1, 2) - I*sqrt(3)/2, Rational(-1, 2) + I*sqrt(3)/2] | |
assert roots_cyclotomic(cyclotomic_poly(4, x, polys=True)) == [-I, I] | |
assert roots_cyclotomic(cyclotomic_poly( | |
6, x, polys=True)) == [S.Half - I*sqrt(3)/2, S.Half + I*sqrt(3)/2] | |
assert roots_cyclotomic(cyclotomic_poly(7, x, polys=True)) == [ | |
-cos(pi/7) - I*sin(pi/7), | |
-cos(pi/7) + I*sin(pi/7), | |
-cos(pi*Rational(3, 7)) - I*sin(pi*Rational(3, 7)), | |
-cos(pi*Rational(3, 7)) + I*sin(pi*Rational(3, 7)), | |
cos(pi*Rational(2, 7)) - I*sin(pi*Rational(2, 7)), | |
cos(pi*Rational(2, 7)) + I*sin(pi*Rational(2, 7)), | |
] | |
assert roots_cyclotomic(cyclotomic_poly(8, x, polys=True)) == [ | |
-sqrt(2)/2 - I*sqrt(2)/2, | |
-sqrt(2)/2 + I*sqrt(2)/2, | |
sqrt(2)/2 - I*sqrt(2)/2, | |
sqrt(2)/2 + I*sqrt(2)/2, | |
] | |
assert roots_cyclotomic(cyclotomic_poly(12, x, polys=True)) == [ | |
-sqrt(3)/2 - I/2, | |
-sqrt(3)/2 + I/2, | |
sqrt(3)/2 - I/2, | |
sqrt(3)/2 + I/2, | |
] | |
assert roots_cyclotomic( | |
cyclotomic_poly(1, x, polys=True), factor=True) == [1] | |
assert roots_cyclotomic( | |
cyclotomic_poly(2, x, polys=True), factor=True) == [-1] | |
assert roots_cyclotomic(cyclotomic_poly(3, x, polys=True), factor=True) == \ | |
[-root(-1, 3), -1 + root(-1, 3)] | |
assert roots_cyclotomic(cyclotomic_poly(4, x, polys=True), factor=True) == \ | |
[-I, I] | |
assert roots_cyclotomic(cyclotomic_poly(5, x, polys=True), factor=True) == \ | |
[-root(-1, 5), -root(-1, 5)**3, root(-1, 5)**2, -1 - root(-1, 5)**2 + root(-1, 5) + root(-1, 5)**3] | |
assert roots_cyclotomic(cyclotomic_poly(6, x, polys=True), factor=True) == \ | |
[1 - root(-1, 3), root(-1, 3)] | |
def test_roots_binomial(): | |
assert roots_binomial(Poly(5*x, x)) == [0] | |
assert roots_binomial(Poly(5*x**4, x)) == [0, 0, 0, 0] | |
assert roots_binomial(Poly(5*x + 2, x)) == [Rational(-2, 5)] | |
A = 10**Rational(3, 4)/10 | |
assert roots_binomial(Poly(5*x**4 + 2, x)) == \ | |
[-A - A*I, -A + A*I, A - A*I, A + A*I] | |
_check(roots_binomial(Poly(x**8 - 2))) | |
a1 = Symbol('a1', nonnegative=True) | |
b1 = Symbol('b1', nonnegative=True) | |
r0 = roots_quadratic(Poly(a1*x**2 + b1, x)) | |
r1 = roots_binomial(Poly(a1*x**2 + b1, x)) | |
assert powsimp(r0[0]) == powsimp(r1[0]) | |
assert powsimp(r0[1]) == powsimp(r1[1]) | |
for a, b, s, n in product((1, 2), (1, 2), (-1, 1), (2, 3, 4, 5)): | |
if a == b and a != 1: # a == b == 1 is sufficient | |
continue | |
p = Poly(a*x**n + s*b) | |
ans = roots_binomial(p) | |
assert ans == _nsort(ans) | |
# issue 8813 | |
assert roots(Poly(2*x**3 - 16*y**3, x)) == { | |
2*y*(Rational(-1, 2) - sqrt(3)*I/2): 1, | |
2*y: 1, | |
2*y*(Rational(-1, 2) + sqrt(3)*I/2): 1} | |
def test_roots_preprocessing(): | |
f = a*y*x**2 + y - b | |
coeff, poly = preprocess_roots(Poly(f, x)) | |
assert coeff == 1 | |
assert poly == Poly(a*y*x**2 + y - b, x) | |
f = c**3*x**3 + c**2*x**2 + c*x + a | |
coeff, poly = preprocess_roots(Poly(f, x)) | |
assert coeff == 1/c | |
assert poly == Poly(x**3 + x**2 + x + a, x) | |
f = c**3*x**3 + c**2*x**2 + a | |
coeff, poly = preprocess_roots(Poly(f, x)) | |
assert coeff == 1/c | |
assert poly == Poly(x**3 + x**2 + a, x) | |
f = c**3*x**3 + c*x + a | |
coeff, poly = preprocess_roots(Poly(f, x)) | |
assert coeff == 1/c | |
assert poly == Poly(x**3 + x + a, x) | |
f = c**3*x**3 + a | |
coeff, poly = preprocess_roots(Poly(f, x)) | |
assert coeff == 1/c | |
assert poly == Poly(x**3 + a, x) | |
E, F, J, L = symbols("E,F,J,L") | |
f = -21601054687500000000*E**8*J**8/L**16 + \ | |
508232812500000000*F*x*E**7*J**7/L**14 - \ | |
4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ | |
16194716250000*E**5*F**3*J**5*x**3/L**10 - \ | |
27633173750*E**4*F**4*J**4*x**4/L**8 + \ | |
14840215*E**3*F**5*J**3*x**5/L**6 + \ | |
54794*E**2*F**6*J**2*x**6/(5*L**4) - \ | |
1153*E*J*F**7*x**7/(80*L**2) + \ | |
633*F**8*x**8/160000 | |
coeff, poly = preprocess_roots(Poly(f, x)) | |
assert coeff == 20*E*J/(F*L**2) | |
assert poly == 633*x**8 - 115300*x**7 + 4383520*x**6 + 296804300*x**5 - 27633173750*x**4 + \ | |
809735812500*x**3 - 10673859375000*x**2 + 63529101562500*x - 135006591796875 | |
f = Poly(-y**2 + x**2*exp(x), y, domain=ZZ[x, exp(x)]) | |
g = Poly(-y**2 + exp(x), y, domain=ZZ[exp(x)]) | |
assert preprocess_roots(f) == (x, g) | |
def test_roots0(): | |
assert roots(1, x) == {} | |
assert roots(x, x) == {S.Zero: 1} | |
assert roots(x**9, x) == {S.Zero: 9} | |
assert roots(((x - 2)*(x + 3)*(x - 4)).expand(), x) == {-S(3): 1, S(2): 1, S(4): 1} | |
assert roots(2*x + 1, x) == {Rational(-1, 2): 1} | |
assert roots((2*x + 1)**2, x) == {Rational(-1, 2): 2} | |
assert roots((2*x + 1)**5, x) == {Rational(-1, 2): 5} | |
assert roots((2*x + 1)**10, x) == {Rational(-1, 2): 10} | |
assert roots(x**4 - 1, x) == {I: 1, S.One: 1, -S.One: 1, -I: 1} | |
assert roots((x**4 - 1)**2, x) == {I: 2, S.One: 2, -S.One: 2, -I: 2} | |
assert roots(((2*x - 3)**2).expand(), x) == {Rational( 3, 2): 2} | |
assert roots(((2*x + 3)**2).expand(), x) == {Rational(-3, 2): 2} | |
assert roots(((2*x - 3)**3).expand(), x) == {Rational( 3, 2): 3} | |
assert roots(((2*x + 3)**3).expand(), x) == {Rational(-3, 2): 3} | |
assert roots(((2*x - 3)**5).expand(), x) == {Rational( 3, 2): 5} | |
assert roots(((2*x + 3)**5).expand(), x) == {Rational(-3, 2): 5} | |
assert roots(((a*x - b)**5).expand(), x) == { b/a: 5} | |
assert roots(((a*x + b)**5).expand(), x) == {-b/a: 5} | |
assert roots(x**2 + (-a - 1)*x + a, x) == {a: 1, S.One: 1} | |
assert roots(x**4 - 2*x**2 + 1, x) == {S.One: 2, S.NegativeOne: 2} | |
assert roots(x**6 - 4*x**4 + 4*x**3 - x**2, x) == \ | |
{S.One: 2, -1 - sqrt(2): 1, S.Zero: 2, -1 + sqrt(2): 1} | |
assert roots(x**8 - 1, x) == { | |
sqrt(2)/2 + I*sqrt(2)/2: 1, | |
sqrt(2)/2 - I*sqrt(2)/2: 1, | |
-sqrt(2)/2 + I*sqrt(2)/2: 1, | |
-sqrt(2)/2 - I*sqrt(2)/2: 1, | |
S.One: 1, -S.One: 1, I: 1, -I: 1 | |
} | |
f = -2016*x**2 - 5616*x**3 - 2056*x**4 + 3324*x**5 + 2176*x**6 - \ | |
224*x**7 - 384*x**8 - 64*x**9 | |
assert roots(f) == {S.Zero: 2, -S(2): 2, S(2): 1, Rational(-7, 2): 1, | |
Rational(-3, 2): 1, Rational(-1, 2): 1, Rational(3, 2): 1} | |
assert roots((a + b + c)*x - (a + b + c + d), x) == {(a + b + c + d)/(a + b + c): 1} | |
assert roots(x**3 + x**2 - x + 1, x, cubics=False) == {} | |
assert roots(((x - 2)*( | |
x + 3)*(x - 4)).expand(), x, cubics=False) == {-S(3): 1, S(2): 1, S(4): 1} | |
assert roots(((x - 2)*(x + 3)*(x - 4)*(x - 5)).expand(), x, cubics=False) == \ | |
{-S(3): 1, S(2): 1, S(4): 1, S(5): 1} | |
assert roots(x**3 + 2*x**2 + 4*x + 8, x) == {-S(2): 1, -2*I: 1, 2*I: 1} | |
assert roots(x**3 + 2*x**2 + 4*x + 8, x, cubics=True) == \ | |
{-2*I: 1, 2*I: 1, -S(2): 1} | |
assert roots((x**2 - x)*(x**3 + 2*x**2 + 4*x + 8), x ) == \ | |
{S.One: 1, S.Zero: 1, -S(2): 1, -2*I: 1, 2*I: 1} | |
r1_2, r1_3 = S.Half, Rational(1, 3) | |
x0 = (3*sqrt(33) + 19)**r1_3 | |
x1 = 4/x0/3 | |
x2 = x0/3 | |
x3 = sqrt(3)*I/2 | |
x4 = x3 - r1_2 | |
x5 = -x3 - r1_2 | |
assert roots(x**3 + x**2 - x + 1, x, cubics=True) == { | |
-x1 - x2 - r1_3: 1, | |
-x1/x4 - x2*x4 - r1_3: 1, | |
-x1/x5 - x2*x5 - r1_3: 1, | |
} | |
f = (x**2 + 2*x + 3).subs(x, 2*x**2 + 3*x).subs(x, 5*x - 4) | |
r13_20, r1_20 = [ Rational(*r) | |
for r in ((13, 20), (1, 20)) ] | |
s2 = sqrt(2) | |
assert roots(f, x) == { | |
r13_20 + r1_20*sqrt(1 - 8*I*s2): 1, | |
r13_20 - r1_20*sqrt(1 - 8*I*s2): 1, | |
r13_20 + r1_20*sqrt(1 + 8*I*s2): 1, | |
r13_20 - r1_20*sqrt(1 + 8*I*s2): 1, | |
} | |
f = x**4 + x**3 + x**2 + x + 1 | |
r1_4, r1_8, r5_8 = [ Rational(*r) for r in ((1, 4), (1, 8), (5, 8)) ] | |
assert roots(f, x) == { | |
-r1_4 + r1_4*5**r1_2 + I*(r5_8 + r1_8*5**r1_2)**r1_2: 1, | |
-r1_4 + r1_4*5**r1_2 - I*(r5_8 + r1_8*5**r1_2)**r1_2: 1, | |
-r1_4 - r1_4*5**r1_2 + I*(r5_8 - r1_8*5**r1_2)**r1_2: 1, | |
-r1_4 - r1_4*5**r1_2 - I*(r5_8 - r1_8*5**r1_2)**r1_2: 1, | |
} | |
f = z**3 + (-2 - y)*z**2 + (1 + 2*y - 2*x**2)*z - y + 2*x**2 | |
assert roots(f, z) == { | |
S.One: 1, | |
S.Half + S.Half*y + S.Half*sqrt(1 - 2*y + y**2 + 8*x**2): 1, | |
S.Half + S.Half*y - S.Half*sqrt(1 - 2*y + y**2 + 8*x**2): 1, | |
} | |
assert roots(a*b*c*x**3 + 2*x**2 + 4*x + 8, x, cubics=False) == {} | |
assert roots(a*b*c*x**3 + 2*x**2 + 4*x + 8, x, cubics=True) != {} | |
assert roots(x**4 - 1, x, filter='Z') == {S.One: 1, -S.One: 1} | |
assert roots(x**4 - 1, x, filter='I') == {I: 1, -I: 1} | |
assert roots((x - 1)*(x + 1), x) == {S.One: 1, -S.One: 1} | |
assert roots( | |
(x - 1)*(x + 1), x, predicate=lambda r: r.is_positive) == {S.One: 1} | |
assert roots(x**4 - 1, x, filter='Z', multiple=True) == [-S.One, S.One] | |
assert roots(x**4 - 1, x, filter='I', multiple=True) == [I, -I] | |
ar, br = symbols('a, b', real=True) | |
p = x**2*(ar-br)**2 + 2*x*(br-ar) + 1 | |
assert roots(p, x, filter='R') == {1/(ar - br): 2} | |
assert roots(x**3, x, multiple=True) == [S.Zero, S.Zero, S.Zero] | |
assert roots(1234, x, multiple=True) == [] | |
f = x**6 - x**5 + x**4 - x**3 + x**2 - x + 1 | |
assert roots(f) == { | |
-I*sin(pi/7) + cos(pi/7): 1, | |
-I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 1, | |
-I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 1, | |
I*sin(pi/7) + cos(pi/7): 1, | |
I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 1, | |
I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 1, | |
} | |
g = ((x**2 + 1)*f**2).expand() | |
assert roots(g) == { | |
-I*sin(pi/7) + cos(pi/7): 2, | |
-I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 2, | |
-I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 2, | |
I*sin(pi/7) + cos(pi/7): 2, | |
I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 2, | |
I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 2, | |
-I: 1, I: 1, | |
} | |
r = roots(x**3 + 40*x + 64) | |
real_root = [rx for rx in r if rx.is_real][0] | |
cr = 108 + 6*sqrt(1074) | |
assert real_root == -2*root(cr, 3)/3 + 20/root(cr, 3) | |
eq = Poly((7 + 5*sqrt(2))*x**3 + (-6 - 4*sqrt(2))*x**2 + (-sqrt(2) - 1)*x + 2, x, domain='EX') | |
assert roots(eq) == {-1 + sqrt(2): 1, -2 + 2*sqrt(2): 1, -sqrt(2) + 1: 1} | |
eq = Poly(41*x**5 + 29*sqrt(2)*x**5 - 153*x**4 - 108*sqrt(2)*x**4 + | |
175*x**3 + 125*sqrt(2)*x**3 - 45*x**2 - 30*sqrt(2)*x**2 - 26*sqrt(2)*x - | |
26*x + 24, x, domain='EX') | |
assert roots(eq) == {-sqrt(2) + 1: 1, -2 + 2*sqrt(2): 1, -1 + sqrt(2): 1, | |
-4 + 4*sqrt(2): 1, -3 + 3*sqrt(2): 1} | |
eq = Poly(x**3 - 2*x**2 + 6*sqrt(2)*x**2 - 8*sqrt(2)*x + 23*x - 14 + | |
14*sqrt(2), x, domain='EX') | |
assert roots(eq) == {-2*sqrt(2) + 2: 1, -2*sqrt(2) + 1: 1, -2*sqrt(2) - 1: 1} | |
assert roots(Poly((x + sqrt(2))**3 - 7, x, domain='EX')) == \ | |
{-sqrt(2) + root(7, 3)*(-S.Half - sqrt(3)*I/2): 1, | |
-sqrt(2) + root(7, 3)*(-S.Half + sqrt(3)*I/2): 1, | |
-sqrt(2) + root(7, 3): 1} | |
def test_roots_slow(): | |
"""Just test that calculating these roots does not hang. """ | |
a, b, c, d, x = symbols("a,b,c,d,x") | |
f1 = x**2*c + (a/b) + x*c*d - a | |
f2 = x**2*(a + b*(c - d)*a) + x*a*b*c/(b*d - d) + (a*d - c/d) | |
assert list(roots(f1, x).values()) == [1, 1] | |
assert list(roots(f2, x).values()) == [1, 1] | |
(zz, yy, xx, zy, zx, yx, k) = symbols("zz,yy,xx,zy,zx,yx,k") | |
e1 = (zz - k)*(yy - k)*(xx - k) + zy*yx*zx + zx - zy - yx | |
e2 = (zz - k)*yx*yx + zx*(yy - k)*zx + zy*zy*(xx - k) | |
assert list(roots(e1 - e2, k).values()) == [1, 1, 1] | |
f = x**3 + 2*x**2 + 8 | |
R = list(roots(f).keys()) | |
assert not any(i for i in [f.subs(x, ri).n(chop=True) for ri in R]) | |
def test_roots_inexact(): | |
R1 = roots(x**2 + x + 1, x, multiple=True) | |
R2 = roots(x**2 + x + 1.0, x, multiple=True) | |
for r1, r2 in zip(R1, R2): | |
assert abs(r1 - r2) < 1e-12 | |
f = x**4 + 3.0*sqrt(2.0)*x**3 - (78.0 + 24.0*sqrt(3.0))*x**2 \ | |
+ 144.0*(2*sqrt(3.0) + 9.0) | |
R1 = roots(f, multiple=True) | |
R2 = (-12.7530479110482, -3.85012393732929, | |
4.89897948556636, 7.46155167569183) | |
for r1, r2 in zip(R1, R2): | |
assert abs(r1 - r2) < 1e-10 | |
def test_roots_preprocessed(): | |
E, F, J, L = symbols("E,F,J,L") | |
f = -21601054687500000000*E**8*J**8/L**16 + \ | |
508232812500000000*F*x*E**7*J**7/L**14 - \ | |
4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ | |
16194716250000*E**5*F**3*J**5*x**3/L**10 - \ | |
27633173750*E**4*F**4*J**4*x**4/L**8 + \ | |
14840215*E**3*F**5*J**3*x**5/L**6 + \ | |
54794*E**2*F**6*J**2*x**6/(5*L**4) - \ | |
1153*E*J*F**7*x**7/(80*L**2) + \ | |
633*F**8*x**8/160000 | |
assert roots(f, x) == {} | |
R1 = roots(f.evalf(), x, multiple=True) | |
R2 = [-1304.88375606366, 97.1168816800648, 186.946430171876, 245.526792947065, | |
503.441004174773, 791.549343830097, 1273.16678129348, 1850.10650616851] | |
w = Wild('w') | |
p = w*E*J/(F*L**2) | |
assert len(R1) == len(R2) | |
for r1, r2 in zip(R1, R2): | |
match = r1.match(p) | |
assert match is not None and abs(match[w] - r2) < 1e-10 | |
def test_roots_strict(): | |
assert roots(x**2 - 2*x + 1, strict=False) == {1: 2} | |
assert roots(x**2 - 2*x + 1, strict=True) == {1: 2} | |
assert roots(x**6 - 2*x**5 - x**2 + 3*x - 2, strict=False) == {2: 1} | |
raises(UnsolvableFactorError, lambda: roots(x**6 - 2*x**5 - x**2 + 3*x - 2, strict=True)) | |
def test_roots_mixed(): | |
f = -1936 - 5056*x - 7592*x**2 + 2704*x**3 - 49*x**4 | |
_re, _im = intervals(f, all=True) | |
_nroots = nroots(f) | |
_sroots = roots(f, multiple=True) | |
_re = [ Interval(a, b) for (a, b), _ in _re ] | |
_im = [ Interval(re(a), re(b))*Interval(im(a), im(b)) for (a, b), | |
_ in _im ] | |
_intervals = _re + _im | |
_sroots = [ r.evalf() for r in _sroots ] | |
_nroots = sorted(_nroots, key=lambda x: x.sort_key()) | |
_sroots = sorted(_sroots, key=lambda x: x.sort_key()) | |
for _roots in (_nroots, _sroots): | |
for i, r in zip(_intervals, _roots): | |
if r.is_real: | |
assert r in i | |
else: | |
assert (re(r), im(r)) in i | |
def test_root_factors(): | |
assert root_factors(Poly(1, x)) == [Poly(1, x)] | |
assert root_factors(Poly(x, x)) == [Poly(x, x)] | |
assert root_factors(x**2 - 1, x) == [x + 1, x - 1] | |
assert root_factors(x**2 - y, x) == [x - sqrt(y), x + sqrt(y)] | |
assert root_factors((x**4 - 1)**2) == \ | |
[x + 1, x + 1, x - 1, x - 1, x - I, x - I, x + I, x + I] | |
assert root_factors(Poly(x**4 - 1, x), filter='Z') == \ | |
[Poly(x + 1, x), Poly(x - 1, x), Poly(x**2 + 1, x)] | |
assert root_factors(8*x**2 + 12*x**4 + 6*x**6 + x**8, x, filter='Q') == \ | |
[x, x, x**6 + 6*x**4 + 12*x**2 + 8] | |
def test_nroots1(): | |
n = 64 | |
p = legendre_poly(n, x, polys=True) | |
raises(mpmath.mp.NoConvergence, lambda: p.nroots(n=3, maxsteps=5)) | |
roots = p.nroots(n=3) | |
# The order of roots matters. They are ordered from smallest to the | |
# largest. | |
assert [str(r) for r in roots] == \ | |
['-0.999', '-0.996', '-0.991', '-0.983', '-0.973', '-0.961', | |
'-0.946', '-0.930', '-0.911', '-0.889', '-0.866', '-0.841', | |
'-0.813', '-0.784', '-0.753', '-0.720', '-0.685', '-0.649', | |
'-0.611', '-0.572', '-0.531', '-0.489', '-0.446', '-0.402', | |
'-0.357', '-0.311', '-0.265', '-0.217', '-0.170', '-0.121', | |
'-0.0730', '-0.0243', '0.0243', '0.0730', '0.121', '0.170', | |
'0.217', '0.265', '0.311', '0.357', '0.402', '0.446', '0.489', | |
'0.531', '0.572', '0.611', '0.649', '0.685', '0.720', '0.753', | |
'0.784', '0.813', '0.841', '0.866', '0.889', '0.911', '0.930', | |
'0.946', '0.961', '0.973', '0.983', '0.991', '0.996', '0.999'] | |
def test_nroots2(): | |
p = Poly(x**5 + 3*x + 1, x) | |
roots = p.nroots(n=3) | |
# The order of roots matters. The roots are ordered by their real | |
# components (if they agree, then by their imaginary components), | |
# with real roots appearing first. | |
assert [str(r) for r in roots] == \ | |
['-0.332', '-0.839 - 0.944*I', '-0.839 + 0.944*I', | |
'1.01 - 0.937*I', '1.01 + 0.937*I'] | |
roots = p.nroots(n=5) | |
assert [str(r) for r in roots] == \ | |
['-0.33199', '-0.83907 - 0.94385*I', '-0.83907 + 0.94385*I', | |
'1.0051 - 0.93726*I', '1.0051 + 0.93726*I'] | |
def test_roots_composite(): | |
assert len(roots(Poly(y**3 + y**2*sqrt(x) + y + x, y, composite=True))) == 3 | |
def test_issue_19113(): | |
eq = cos(x)**3 - cos(x) + 1 | |
raises(PolynomialError, lambda: roots(eq)) | |
def test_issue_17454(): | |
assert roots([1, -3*(-4 - 4*I)**2/8 + 12*I, 0], multiple=True) == [0, 0] | |
def test_issue_20913(): | |
assert Poly(x + 9671406556917067856609794, x).real_roots() == [-9671406556917067856609794] | |
assert Poly(x**3 + 4, x).real_roots() == [-2**(S(2)/3)] | |
def test_issue_22768(): | |
e = Rational(1, 3) | |
r = (-1/a)**e*(a + 1)**(5*e) | |
assert roots(Poly(a*x**3 + (a + 1)**5, x)) == { | |
r: 1, | |
-r*(1 + sqrt(3)*I)/2: 1, | |
r*(-1 + sqrt(3)*I)/2: 1} | |