2010-06-20 18 views
13

Ich versuche [SymPy] [1] zu verwenden, um mehrere Ausdrücke in einem Ausdruck gleichzeitig zu ersetzen. Ich habe die [Subs-Funktion] [2] mit einem Dictionary als Parameter versucht, aber herausgefunden, dass sie sequentiell ersetzt.Nicht-sequentielle Substitution in SymPy

In : a.subs({a:b, b:c}) 
Out: c 

Das Problem ist der erste Wechsel in einem Begriff geführt, die durch die zweite Substitution substituiert werden kann, aber es sollte nicht (für meine Sache).

Irgendeine Idee, wie man die Substitutionen gleichzeitig durchführt, ohne dass sie sich gegenseitig stören?

Edit: Das ist ein echtes Beispiel

In [1]: I_x, I_y, I_z = Symbol("I_x"), Symbol("I_y"), Symbol("I_z") 

In [2]: S_x, S_y, S_z = Symbol("S_x"), Symbol("S_y"), Symbol("S_z") 

In [3]: J_is = Symbol("J_IS") 

In [4]: t = Symbol("t") 

In [5]: substitutions = (
(2 * I_x * S_z, 2 * I_x * S_z * cos(2 * pi * J_is * t) + I_y * sin(2 * pi * J_is * t)), 
(I_x, I_x * cos(2 * pi * J_is * t) + 2 * I_x * S_z * sin(2 * pi * J_is * t)), 
(I_y, I_y * cos(2 * pi * J_is * t) - 2 * I_x * S_z * sin(2 * pi * J_is * t)) 
) 

In [6]: (2 * I_x * S_z).subs(substitutions) 
Out[7]: (I_y*cos(2*pi*J_IS*t) - 2*I_x*S_z*sin(2*pi*J_IS*t))*sin(2*pi*J_IS*t) + 2*S_z*(I_x*cos(2*pi*J_IS*t) + 2*I_x*S_z*sin(2*pi*J_IS*t))*cos(2*pi*J_IS*t) 

Nur die entsprechende Substitution sollte in diesem Fall passiert, nur die erste. So sollte die erwartete Ausgabe wie folgt sein:

In [6]: (2 * I_x * S_z).subs(substitutions) 
Out[7]: I_y*sin(2*pi*J_IS*t) + 2*I_x*S_z*cos(2*pi*J_IS*t) 
+0

Können Sie ein konkretes Beispiel geben von Ihren Substitutionen, damit ich sehen kann, was das Problem ist. Das Problem, das Sie oben haben, kann durch ~ unutbus Antwort gelöst werden. –

+0

@PreludeAndFugue Ich habe ein echtes Beispiel hinzugefügt, meine alten Beispiele waren zu sehr vereinfacht und nicht wirklich nützlich. –

Antwort

13

Die aktuelle Version von sympy bietet das Stichwort gleichzeitige.Die komplizierten Operationen in den vorangegangenen Antworten sind nicht mehr notwendig:

In [1]: (x*sin(y)).subs([(x,y),(y,x)],simultaneous=True) 
Out[1]: y⋅sin(x) 
2

Die subs(self,*args) Methode definiert ist (teilweise) auf diese Weise:

In [11]: x.subs?? 
... 
sequence = args[0] 
if isinstance(sequence, dict): 
    return self._subs_dict(sequence) 
elif isinstance(sequence, (list, tuple)): 
    return self._subs_list(sequence) 

Wenn Sie subs ein dict passieren, Sie Kontrolle über die Reihenfolge des verlieren Substitutionen. Während, wenn Sie subs eine Liste oder Tupel übergeben, können Sie die Reihenfolge steuern.

Dies ermöglicht keine simultanen Auswechslungen. Das würde zu Schwierigkeiten führen, wenn der Benutzer Dinge wie x.subs([(x,y),(y,x)]) weitergeben würde. Also bezweifle ich, dass sympy eine Methode hat, simultane Substitutionen zu machen. Stattdessen glaube ich, alle Substitutionen, entweder ungeordnet sind oder besten (wenn Sie ein dict Pass), durch eine 1-Pass bestellt Substitution erfolgt (wenn Sie eine Liste oder Tupel übergeben):

In [17]: x.subs([(x,y),(y,z)]) 
Out[18]: z 

In [19]: x.subs([(y,z),(x,y)]) 
Out[19]: y 

PS. _subs_list(self, sequence) definiert ist (teilweise) wie folgt aus:

In [14]: x._subs_list?? 
... 
    for old, new in sequence: 
     result = result.subs(old, new) 

Diese Nägel auf der Reihenfolge, in der die U-Boote fertig sind.

+0

Ich habe ein zweites Beispiel hinzugefügt, die Reihenfolge der Substitutionen scheint nach einem Prinzip zu variieren, das ich nicht verstehe. –

+0

Sie könnten es reproduzieren mit OrderedDict http://stackoverflow.com/questions/3080450/non-sequential-substitution-in-sympy/3080803#3080803 – jfs

1

Beispiel für @~unutbu's answer:

>>> import ordereddict # collections.OrderedDict in Python 2.7+ 
>>> from sympy import * 
>>> x,y,z = symbols('xyz') 
>>> x.subs(ordereddict.OrderedDict([(x,y),(y,z)])) 
y 
>>> x.subs(ordereddict.OrderedDict([(y,z),(x,y)])) 
z 
+0

Danke, so ist es etwas unberechenbar mit normalen dicts, weil sie unsortiert sind. Leider spielt in meinem Fall die Reihenfolge keine Rolle, die Ersetzungen treten unabhängig von der Reihenfolge übereinander. –

1

die editierte Frage zu beantworten.

In Ihrem Beispiel können Sie einige temporäre Variablen verwenden, die bei nachfolgenden Ersetzungen nicht überschrieben werden. Sobald alle potenziell überlappenden Substitutionen vorgenommen wurden, können Sie die temporären Variablen durch die reellen ersetzen.

Dieses Beispiel funktioniert für die Frage, wenn Ihr vollständiges Problem komplexere Ersetzungen enthält, sollten Sie nach wie vor in der Lage sein, temporäre Variablen zu erstellen, um überlappende Ersetzungen zu vermeiden.

from sympy import Symbol, sin, cos, pi 

I_x, I_y, I_z = Symbol("I_x"), Symbol("I_y"), Symbol("I_z") 
S_x, S_y, S_z = Symbol("S_x"), Symbol("S_y"), Symbol("S_z") 
J_is = Symbol("J_IS") 
t = Symbol("t") 
I_x_temp, I_y_temp, I_z_temp = Symbol("I_x_temp"), Symbol("I_y_temp"), Symbol("I_z_temp") 

f = 2*I_x*S_z 
answer = I_y*sin(2*pi*J_is*t) + 2*I_x*S_z*cos(2*pi*J_is*t) 

subs1a = [ 
    (2*I_x*S_z, 2*I_x_temp*S_z*cos(2*pi*J_is*t) + I_y_temp*sin(2*pi*J_is*t)), 
    (I_x, I_x_temp*cos(2* pi*J_is*t) + 2*I_x_temp*S_z*sin(2*pi*J_is*t)), 
    (I_y, I_y_temp*cos(2*pi*J_is*t) - 2*I_x_temp*S_z* sin(2*pi*J_is*t)) 
] 

subs_temp = [(I_x_temp, I_x), (I_y_temp, I_y), (I_z_temp, I_z)] 

print f 
f = f.subs(subs1a) 
print f 
f = f.subs(subs_temp) 
print f 
print f == answer # True 

Hinweis, können Sie führen auch wieder zwei Auswechslungen nach hinten:

f.subs(subs1a).subs(subs_temp) == answer 
0

Das Stichwort simultaneous subs nicht-kollidierende tun wird, unabhängig von der Eingabe (dict oder Sequenz):

>>> x.subs([(x,y),(y,z)],simultaneous=1) 
y 
>>> x.subs([(y,z),(x,y)],simultaneous=1) 
y