Ответ 1
Текущая версия sympy предоставляет ключевое слово одновременное. Сложные операции в предыдущих ответах больше не нужны:
In [1]: (x*sin(y)).subs([(x,y),(y,x)],simultaneous=True)
Out[1]: y⋅sin(x)
Я пытаюсь использовать [SymPy] [1], чтобы одновременно заменить несколько терминов в выражении. Я попробовал функцию [subs function] [2] со словарем как параметром, но обнаружил, что он последовательно заменяет.
In : a.subs({a:b, b:c})
Out: c
Проблема заключается в первой замене, в результате которой можно заменить вторую замену, но она не должна (по моей причине).
Любая идея о том, как выполнять подстановки одновременно, без их вмешательства друг в друга?
Edit: Это реальный пример
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)
Только соответствующая замена должна произойти, в этом случае только первая. Таким образом, ожидаемый результат должен быть следующим:
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)
Текущая версия sympy предоставляет ключевое слово одновременное. Сложные операции в предыдущих ответах больше не нужны:
In [1]: (x*sin(y)).subs([(x,y),(y,x)],simultaneous=True)
Out[1]: y⋅sin(x)
Метод subs(self,*args)
определяется (частично) следующим образом:
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)
Если вы передадите subs
a dict, вы потеряете контроль над порядком замещений.
Если вы передадите subs
список или кортеж, вы можете управлять порядком.
Это не позволяет делать одновременные замены. Это может привести к трудностям, если пользователь должен передать такие вещи, как x.subs([(x,y),(y,x)])
. Поэтому я сомневаюсь, что у sympy есть метод для одновременных замещений. Вместо этого я считаю, что все подстановки либо неупорядочены (если вы передаете dict), либо, в лучшем случае, выполняете 1-проходную упорядоченную замену (если вы передаете список или кортеж):
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)
определяется (частично) следующим образом:
In [14]: x._subs_list??
...
for old, new in sequence:
result = result.subs(old, new)
Это уменьшает порядок, в котором выполняются субтитры.
Пример @~ unutbu 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
Отвечая на отредактированный вопрос.
В вашем примере вы можете использовать некоторые временные переменные, которые не будут переписанными, будут последующими заменами. Затем, после того как все потенциально перекрывающиеся подстановки были сделаны, вы можете заменить временные переменные на реальные.
Этот пример работает для вопроса, если ваша полная проблема содержит более сложные подстановки, я думаю, что вы все равно должны создавать временные переменные, чтобы избежать дублирования подстановок.
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
Примечание. Вы также можете выполнять две замены назад:
f.subs(subs1a).subs(subs_temp) == answer
Ключевое слово simultaneous
будет выполнять несовпадающие подсистемы независимо от ввода (dict или sequence):
>>> x.subs([(x,y),(y,z)],simultaneous=1)
y
>>> x.subs([(y,z),(x,y)],simultaneous=1)
y