2013-03-04 14 views
6

sto usando sympy per risolvere un polinomio:Ignora radici immaginarie 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 è un elenco di possibili soluzioni. Tuttavia, ho bisogno di ignorare quelli immaginari e utilizzare solo le soluzioni reali. Inoltre, mi piacerebbe che la soluzione come valore non fosse un'espressione. In questo momento sembra:

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

Ho bisogno del valore dell'ultima espressione (-2.22756). Ci sono funzioni in sympy per semplificare questo?

+4

SymPy probabilmente non è la libreria corretta da utilizzare se si è interessati solo alla conversione in virgola mobile/doppia della radice. Se usi numpy/scipy probabilmente otterrai prestazioni migliori e codice più semplice. E se scegli sympy over numpy/scipy perché è più piccolo puoi diventare ancora più piccolo con mpmath che viene usato all'interno di sympy per i numeri (di precisione arbitraria non limitata dalla macchina) – Krastanov

risposta

0

Come aveva accennato Krastonov mpmath fornito un metodo più semplice:

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

Sono riuscito a ignorare semplicemente le soluzioni contenenti il ​​carattere "I" e utilizzato .evalf() per valutare l'espressione. Il codice è ora:

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

Un modo migliore per filtrare le radici reali è controllare ' root.is_real'. – asmeurer

9

Se si imposta x essere reale, SymPy solo vi darà le soluzioni reali

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

Sto cercando di risolvere un'equazione usando questo metodo, ma restituisce comunque soluzioni immaginarie – Alex

+0

Stai usando risolvere? Nota che il nuovo 'solveset' ignora le assunzioni impostate su Symbols (usa' solveset (domain = S.Reals) 'per risolvere nel dominio reale.Se stai usando solve, questo è un bug che dovrebbe essere [segnalato] (https: //github.com/sympy/sympy/issues/new). – asmeurer

+0

Ho provato entrambi: risolvi, con le ipotesi, solveset e solveset con domain = S.Real. Solve stava semplicemente saltando le ipotesi sulla variabile da risolvere (come solveset) arrivando alle soluzioni in 30 secondi, mentre solveset con un dominio non è stato in grado di arrivare alla soluzione in 20 minuti. Potrebbe essere un duplicato? (https://github.com/sympy/sympy/issues/9973) – Alex

0

solve() non ha un output coerente per vari tipi di soluzioni, utilizzare 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

Questo è esattamente il tipo di cosa che real_roots è fatto per ed è particolarmente applicabile al caso in cui i coefficienti sono numeri interi:

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

Il valore di istanze CRootOf può essere valutato secondo la precisione che ti serve e non dovrebbe contenere alcuna parte immaginaria. Ad esempio,

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

Nota: Se non ricordo male, risolvere invierà di nuovo radici che non è stato in grado di confermare incontrato le ipotesi (cioè se non sono stati trovati ad essere false per l'ipotesi allora sono restituiti). Inoltre, se vuoi un output più consistente da risolvere, @PyRick, imposta il flag dict=True.