2016-09-05 11 views
1

Ich arbeite mit einigen langen Gleichungen, aber nicht wirklich komplex, und ich wollte sympy verwenden, um sie zu vereinfachen und zu "faktorisieren". Aber ich habe ein paar Probleme festgestellt. Hier ist eine Liste einiger minimal Beispiele:Sympy Subs Einschränkungen

Problem 1: Symmetrie

from sympy import * 
from __future__ import division 
a = symbols('a') 
b = symbols('b') 
expr = 1/12*b + 1 
expr.subs(1/12*b, a) 
expr.subs(b*1/12, a) 

Die erste Zeile gibt das erwartete Ergebnis (dh a+1.), Während in der zweiten gibt es keine Substitution.

Problem 2: faktorisierter Ausdrücke

Einige Teile des Ausdrucks sind faktorisierter und wenn ich den Ausdruck erweitern sie bekommen vereinfacht, wodurch die Substitution unmöglich. Zum Beispiel

(((x+1)**2-x).expand()).subs(x**2+2*x, y+1) 

geben x^2+x+1 und was ich suche ist y+2-x.

Frage

Gibt es eine Möglichkeit, diese Probleme zu lösen? Oder sollte ich ein anderes symbolisches mathematisches Werkzeug benutzen? Irgendwelche Vorschläge sind willkommen.

Antwort

4

Es gibt einen großen Gotcha in SymPy ist, was das heißt, wegen der Art und Weise Python funktioniert, gibt number/number eine Floating-Point (oder tut Integer-Division, wenn Sie Python verwenden 2 und nicht from __future__ import division).

Im ersten Fall und in Ihrem ursprünglichen Ausdruck wertet Python 1/12*b von links nach rechts aus. 1/12 wird von Python zu 0.08333333333333333 ausgewertet, die dann mit b multipliziert wird. Im zweiten Fall wird b*1 als b ausgewertet. Dann wird b/12 durch SymPy ausgewertet (weil b ein SymPy-Objekt ist), um Rational(1, 12)*b zu ergeben.

Aufgrund der ungenauen Natur der Gleitkommazahlen sieht SymPy den Gleitkomma 0.08333333333333333 nicht gleich dem rationalen 1/12.

Es gibt einige weitere Diskussion dieses Problems here. Als Workaround sollten Sie direkte integer/integer vermeiden, ohne es irgendwie zu wickeln, so dass SymPy eine rationale erstellen kann. Im Folgenden werden alle schaffen eine rationale:

b/12 
Rational(1, 12)*b 
S(1)/12*b 

Für (((x+1)**2-x).expand()).subs(x**2+2*x, y+1) das Problem ist, dass x**2 + 2*x nicht genau erscheinen im Ausdruck, der x**2 + x + 1 ist. SymPy ersetzt im Allgemeinen nur Dinge, die es genau sieht.

Es scheint, dass es Ihnen nichts ausmacht, eine x hinzuzufügen und zu subtrahieren, um den Austausch zu ermöglichen. Also würde ich stattdessen (((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x) vorschlagen. Wenn nur ein einzelner Term (x**2) ersetzt wird, funktioniert die Substitution immer, und wird gelöscht, um zu verlassen, was auch immer x bleibt (in diesem Fall -x).

1

Hier ist eine mögliche Lösung für Ihre Probleme:

from sympy import * 

a = symbols('a') 
b = symbols('b') 
expr = 1/12 * b + 1 
print(expr.subs((1/12) * b, a)) 
print(expr.subs(b * (1/12), a)) 

x = symbols('x') 
y = symbols('y') 
expr = ((x + 1)**2 - x).expand() 
print(expr.subs(x**2 + x, y - x + 1)) 
+0

Für das erste Problem denke ich, es gibt eine 'von __future__ Importabteilung ', mit diesem Zusatz habe ich versucht und es funktioniert. Allerdings verstehe ich nicht warum. Für das zweite Problem löst das mein Problem wirklich nicht. Was ich hier gegeben habe, sind minimale Beispiele, aber in Wirklichkeit sind die Gleichungen wirklich lang. Ich kann die Ergebnisse nicht wirklich "betrügen". Und ich kann definitiv den Wert nicht ändern, der ersetzt werden soll ... Danke für das Antworten! – lasofivec

+0

Für die zweite Frage vielleicht ist meine Frage "Ist es möglich zu erweitern, ohne zu vereinfachen"? – lasofivec

1

In Bezug auf das Problem 1, beachten Sie, dass 1/12*b und b*1/12 sind nicht die gleiche Sache in sympy. Die erste ist eine floatende Zahl, die durch ein Symbol multipliziert wird, während die zweite ein exakter symbolischer Ausdruck ist (Sie können es durch eine einfache Druckanweisung auschecken). Da expr1/12*b enthält, ist es nicht überraschend, dass die zweite subs nicht funktioniert.

In Bezug auf Problem 2, die subs Regel, die Sie zur Verfügung stellen ist nicht eindeutig. Insbesondere impliziert die Substitutionsregel die Gleichung x**2+2*x==y+1. Allerdings hat diese Gleichung viele Interpretationen, zum Beispiel

x**2 == y + 1 - 2*x (das ist diejenige, die Sie betrachten),

x**2 + x == y + 1 - x,

x == (y + 1 - x**2)/2,

Aus diesem Grund habe ich sympy abgelehnt betrachten auszuführen Eine Substitution ist eigentlich ein korrekter Ansatz.

Wenn es die erste Interpretation ist, dass Sie wollen, ist es besser, es explizit in der Regel subs zu liefern, das heißt ,

(((x+1)**2-x).expand()).subs(x**2, -2*x + y + 1) 

-x + y + 2