Непоследовательная замена в SymPy

Я пытаюсь использовать [SymPy][1] для замены несколькими условиями в выражении одновременно. Я попробовал [функция нижних индексов] [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)
13
задан Mad Scientist 23 June 2010 в 11:58
поделиться

3 ответа

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

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

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)

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

2
ответ дан 1 December 2019 в 23:30
поделиться

Пример ответа @ ~ 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
1
ответ дан 1 December 2019 в 23:30
поделиться

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

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

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

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
ответ дан 1 December 2019 в 23:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: