Непоследовательная замена в SymPy - PullRequest
13 голосов
/ 20 июня 2010

Я пытаюсь использовать [SymPy] [1] для замены нескольких терминов в выражении одновременно.Я попытался [subs function] [2] со словарем в качестве параметра, но обнаружил, что он заменяет последовательно.

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

Проблема в том, что первая замена приводит к тому, что термин может быть заменен вторымзамена, но это не должно (по моей причине).

Есть идеи о том, как выполнять замены одновременно, не мешая друг другу?

Редактировать: Это реальный пример

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)

Ответы [ 5 ]

14 голосов
/ 09 июня 2012

Текущая версия sympy предоставляет ключевое слово одновременно. Сложные операции в предыдущих ответах больше не нужны:

In [1]: (x*sin(y)).subs([(x,y),(y,x)],simultaneous=True)
Out[1]: y⋅sin(x)
2 голосов
/ 21 июня 2010

Метод 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 диктовку, вы теряете контроль над порядком замен.Если вы передаете subs список или кортеж, вы можете контролировать порядок.

Это не позволяет выполнять одновременные замены.Это может привести к трудностям, если пользователь будет передавать такие вещи, как x.subs([(x,y),(y,x)]).Поэтому я сомневаюсь, что у sympy есть метод для одновременных замен.Вместо этого я считаю, что все подстановки либо неупорядочены (если вы передаете диктовку), либо, в лучшем случае, выполняются упорядоченной заменой за 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)

Это ограничивает порядок, в котором выполняются подводные лодки.

1 голос
/ 23 июня 2010

Ответ на отредактированный вопрос.

В вашем примере вы можете использовать некоторые временные переменные, которые не будут перезаписаны при последующих заменах.Затем, как только все потенциально перекрывающиеся замены сделаны, вы можете заменить временные переменные действительными.

Этот пример подходит для вопроса, если ваша полная задача содержит более сложные замены, я думаю, вам следуетпо-прежнему можно создавать временные переменные, чтобы избежать перекрывающихся подстановок.

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
1 голос
/ 21 июня 2010

Пример ответа @ ~ unutbu :

>>> 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 голосов
/ 26 февраля 2014

Ключевое слово simultaneous будет выполнять не конфликтующие сабвуферы независимо от ввода (дикт или последовательность):

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