2013-03-04 13 views
6

Ich verwende sympy ein Polynom zu lösen:Ignorieren imaginäre Wurzeln in sympy

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

y eine Liste möglicher Lösungen ist. Ich muss jedoch die imaginären ignorieren und nur die echten Lösungen verwenden. Außerdem hätte ich gerne die Lösung als Wert, nicht als Ausdruck. Im Moment sieht es so aus:

[-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] 

Ich brauche den Wert des letzten Ausdrucks (-2.22756). Gibt es Funktionen, die das vereinfachen?

+4

SymPy ist höchstwahrscheinlich nicht die richtige Bibliothek, wenn Sie nur an der Float/Double-Approximation der Wurzel interessiert sind. Wenn Sie numpy/scipy verwenden, erhalten Sie wahrscheinlich bessere Leistung und einfacheren Code. Und wenn Sie sympy über numpy/scipy wählen, weil es kleiner ist, können Sie mit mpmath, das innerhalb von sympy für Numerik verwendet wird, beliebig kleiner werden (mit beliebiger Genauigkeit, die nicht durch die Maschine begrenzt wird) – Krastanov

Antwort

0

Wie Krastonov mpmath erwähnt hatte eine einfachere Methode zur Verfügung gestellt:

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 
-3

Ich konnte einfach Lösungen mit dem Zeichen "I" ignorieren und .evalf() verwenden, um den Ausdruck zu bewerten. Der Code ist jetzt:

x = Symbol('x') 
    y = solve(int(row["scaleA"])*x**3 + int(row["scaleB"])*x**2 + int(row["scaleC"])*x + int(row["scaleD"]), x) 
    for root in y: 
     if "I" not in str(root): 
      print("This One:" + str(root.evalf())) 
+3

Eine bessere Möglichkeit, echte Wurzeln herauszufiltern, ist 'zu prüfen root.is_real'. – asmeurer

9

Wenn Sie x gesetzt real, SymPy wird Ihnen nur die richtigen Lösungen

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

Ich versuche, eine Gleichung mit dieser Methode zu lösen, aber es gibt immer noch imaginäre Lösungen – Alex

+0

Verwenden Sie lösen? Beachten Sie, dass das neue 'solveset' Annahmen ignoriert, die auf Symbole gesetzt sind (verwenden Sie' solveset (domain = S.Reals) ', um in der realen Domäne zu lösen. Wenn Sie lösung verwenden, ist dies ein Fehler, der [berichtet] werden sollte (https: //github.com/sympy/sympy/issues/new). – asmeurer

+0

Ich habe beide versucht: zu lösen, mit den Annahmen, SolveSet und SolveSet mit Domain = S.Reals. Solve war einfach übersprungen die Annahmen auf der Variablen zu lösen (als lösungssatz) in 30 sekunden zu den lösungen kommen, während lösungssatz mit einer domäne nicht in der lage war, in 20 minuten zur lösung zu kommen. Könnte es ein duplikat sein? (https://github.com/sympy/sympy/issues/9973) – Alex

0

solve() hat keine konsistente Ausgabe für verschiedene Arten von Lösungen, bitte verwenden Sie 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

1

Dies ist genau die Art von Sache, die real_roots für gefertigt und ist besonders für Ihren Fall, in dem die Koeffizienten ganze Zahlen sind:

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(...), ...] 

Der Wert von CRootOf Instanzen sein können ausgewertet zu irgendeiner Genauigkeit, die Sie brauchen, und sollte keinen Imaginärteil enthalten. Zum Beispiel

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

Hinweis: Soweit ich mich erinnere, wird zurückschicken Wurzeln lösen, dass es nicht in der Lage war, trafen die Annahmen zu bestätigen (dh, wenn sie für die Annahme nicht falsch erwiesen dann werden sie zurück). Wenn Sie eine konsistentere Ausgabe von "@PyRick" wünschen, setzen Sie das Flag dict=True.