为什么Sympy subs()不能始终如一地工作?

时间:2019-09-02 09:32:29

标签: python sympy substitution

我想知道为什么Sympy的subs()在以下特定情况下似乎不起作用。这是MWE:

import sympy as sy

L_ee, L_es, L_ev, L_ss, L_sv, L_vv, X, Y, Z, J_e, J_s, J_v = sy.symbols('L_ee L_es L_ev L_ss L_sv L_vv X Y Z J_e J_s J_v')

eq1 = sy.Eq(J_e, -L_ee * X - L_es * Y - L_ev * Z)
eq2 = sy.Eq(J_s, -L_es * X - L_ss * Y - L_sv * Z)
eq3 = sy.Eq(J_v, -L_ev * X - L_sv * Y - L_vv * Z)

sol1 = sy.solve(eq3, Z)

# Replace Z into the 1st eq.
eq1 = eq1.subs(Z, sol1[0])

sol2 = sy.solve(eq1, X)
eq2 = eq2.subs(X, sol2[0])

eq2 = eq2.subs([(Z, sol1[0]), (X, sol2[0])])
eq2 = sy.factor(eq2, (Y, J_v, J_e))

T, bismuth = sy.symbols('T bismuth')
flux_eq = sy.Eq(T*eq2.lhs, T*eq2.rhs)
eq2_flux = flux_eq.subs([(J_v, 0), (J_e, 0)])

bismuth_exp = sy.symbols('bismuth_exp')
bismuth_exp = -eq2_flux.rhs / Y
print(eq2_flux.rhs)

# Works as expected here
print(eq2_flux.rhs.subs(bismuth_exp, bismuth), type(eq2_flux.rhs.subs(bismuth_exp, bismuth)))
print(bismuth_exp)

# But then, why doesn't it work here?
print(eq2.rhs.subs(bismuth_exp, bismuth), type(eq2.rhs.subs(bismuth_exp, bismuth)))

我的目标是用“铋”来编写eq2.rhs。在上面的代码中,我首先使“铋”出现在与eq2.rhs非常相似的表达式中,即eq2_flux.rhs。所以我先打印该表达式,然后再用铋打印相同的表达式。我得到正确的“ -Y *铋”,即Sympy没问题使eq2_flux.rhs中出现“铋”

当我使用eq2.rhs尝试完全相同的操作时,“铋”永远不会替代它应该使用的庞大块。用眼睛看,我应该得到-J_e(某物)-J_v(某物)-铋* Y / T。

请注意,我打印了每个eq.rhs的类型并且它们匹配。因此,我对所发生的事情一无所知,并想知道Sympy是否无法用与它能够执行的表达式非常相似的表达式来代替“铋”的相同块。

针对可能要替换的表达式应按原样显示的评论,这是一个与我的情况等效的示例,但有效:

x, y, z, v = sy.symbols('x y z v')
test = x + y + (v/2.0)*z
print(test.subs(z, 3.0/5 *v))

在这种情况下,可以正确替换z。

我在eq2_flux中添加了“ + Y”,并且替换仍然有效,但是在这种情况下,eq2_flux并不是常数乘以铋。我正确地得到“ -Y *铋+ Y”。至少可以说非常令人困惑。

1 个答案:

答案 0 :(得分:2)

您不应假设subs可以匹配表达式中不存在的内容,例如:

In [54]: (x**3).subs(x**2, 1) 
Out[54]: 
 3
x 

在某些情况下它可以工作,例如

In [55]: (x**4).subs(x**2, 1)
Out[55]: 1

但是这种替换通常总会是片状的,所以我不会依赖它。

请记住,您需要确保subs的第一个参数是表达式树中的文字节点。然后,确保潜艇将找到它的所有实例并替换它们。在您的情况下,我们可以使用

In [114]: F = T/(L_ee*L_vv-L_ev**2)

In [115]: eq2.rhs.subs(bismuth_exp/F, bismuth/F)
Out[115]: 
 ⎛                                                              ⎛             2⎞⎞ 
 ⎜                                                    Y⋅bismuth⋅⎝Lₑₑ⋅Lᵥᵥ - Lₑᵥ ⎠⎟ 
-⎜Jₑ⋅(-Lₑₛ⋅Lᵥᵥ + Lₑᵥ⋅Lₛᵥ) + Jᵥ⋅(-Lₑₑ⋅Lₛᵥ + Lₑₛ⋅Lₑᵥ) + ──────────────────────────⎟ 
 ⎝                                                                T             ⎠ 
──────────────────────────────────────────────────────────────────────────────────
                                               2                                  
                                  Lₑₑ⋅Lᵥᵥ - Lₑᵥ                                   

In [116]: signsimp(_.apart(bismuth)).collect([J_e, J_v])
Out[116]: 
Jₑ⋅(Lₑₛ⋅Lᵥᵥ - Lₑᵥ⋅Lₛᵥ) + Jᵥ⋅(Lₑₑ⋅Lₛᵥ - Lₑₛ⋅Lₑᵥ)   Y⋅bismuth
─────────────────────────────────────────────── - ─────────
                              2                       T    
                 Lₑₑ⋅Lᵥᵥ - Lₑᵥ  

看起来像您期望的形式。