Ignore imaginary roots in sympy

10,716

Solution 1

As Krastonov had mentioned mpmath provided an easier method:

y = polyroots([int(row["scaleA"]), int(row["scaleB"]), int(row["scaleC"]), int(row["scaleD"])-value])
for root in y:
   if "j" not in str(root):
       value = root

Solution 2

If you set x to be real, SymPy will only give you the real solutions

x = Symbol('x', real=True)
solve(..., x)

Solution 3

solve() doesn’t have a consistent output for various types of solutions, please use solveset(Eq,x,domain=S.Reals) :

 from sympy import ImageSet, S 
 x = Symbol('x')
 y = solveset(int(row["scaleA"])*x**3 + int(row["scaleB"])*x**2+int(row["scaleC"])*x + int(row["scaleD"]), x, domain=S.Reals)

http://docs.sympy.org/latest/modules/solvers/solveset.html

Solution 4

This is exactly the sort of thing that real_roots is made for and is especially applicable to your case where the coefficients are integers:

x = Symbol('x')
eq = int(row["scaleA"])*x**3 + int(row["scaleB"])*x**2 + int(row["scaleC"])*x + int(row["scaleD"])
y = real_roots(eq, x)  # gives [CRootOf(...), ...]

The value of CRootOf instances can be evaluated to whatever precision you need and should not contain any imaginary part. For example,

>>> [i.n(12) for i in real_roots(3*x**3 - 2*x**2 + 7*x - 9, x)]
[1.07951904858]

Note: As I recall, solve will send back roots that it wasn't able to confirm met the assumptions (i.e. if they weren't found to be false for the assumption then they are returned). Also, if you want more consistent output from solve, @PyRick, set the flag dict=True.

Share:
10,716
Kreuzade
Author by

Kreuzade

Updated on June 15, 2022

Comments

  • Kreuzade
    Kreuzade almost 2 years

    I'm using sympy to solve a polynomial:

    x = Symbol('x')
    y = solve(int(row["scaleA"])*x**3 + int(row["scaleB"])*x**2 + int(row["scaleC"])*x + int(row["scaleD"]), x)
    

    y is a list of possible solutions. However, I need to ignore the imaginary ones and only use the real solutions. Also, I would like the solution as a value not an expression. Right now it looks like:

    [-2/3 - 55**(1/3)*(-1/2 - sqrt(3)*I/2)/3, -2/3 - 55**(1/3)*(-1/2 + sqrt(3)*I/2)/3, -55**(1/3)/3 - 2/3]
    

    I need the last expression's value (-2.22756). Are there functions in sympy to simplify this?

  • asmeurer
    asmeurer about 11 years
    A better way to filter out real roots is to check root.is_real.
  • Alex Pacini
    Alex Pacini over 7 years
    I am trying to solve an equation using this method but it still returns imaginary solutions
  • asmeurer
    asmeurer over 7 years
    Are you using solve? Note that the new solveset ignores assumptions set on Symbols (use solveset(domain=S.Reals) to solve in the real domain. If you are using solve, this is a bug which should be reported.
  • Alex Pacini
    Alex Pacini over 7 years
    I tried both: solve, with the assumptions, solveset and solveset with domain=S.Reals. Solve was simply skipping the assumptions on the variable to be solved (as solveset) arriving to the solutions in 30 seconds, while solveset with a domain was not able to arrive to the solution in 20 minutes. Could it be a duplicate? (github.com/sympy/sympy/issues/9973)