如何模式匹配并更改表达式中所有出现的子表达式?

时间:2017-07-19 02:21:48

标签: python sympy

使用sympy,我需要将所有exp(C+anything)替换为C*exp(anything)。因为exp(C)是常量,所以我只写为C

我可以在表达式中出现exp一次。但如果有一个实例,不要怎么做。

例如,对于一个实例,与x+exp(C_0+3*x)+3*y中一样,我需要将其更改为x+C_0*exp(3*x)+3*y

对于一个例子,这似乎在一些试验和错误之后起作用

from sympy import *
x,y,C_0 = symbols('x y C_0')
expr=x+exp(C_0+3*x)+3*y
#first check if exp is in the expression
if  any([isinstance(a, exp) for a in preorder_traversal(expr)]):
    p_1=Wild('p1');p_2=Wild('p_2');p_3=Wild('p_3')
    r=(p_1+exp(C_0+p_2)+p_3).matches(expr)
    expr.subs(exp(C_0+r[p_2]),C_0*exp(r[p_2]))

哪个给出了

C_0*exp(3*x) + x + 3*y

但是我需要更改为x+exp(C_0+3*x)+3*y+exp(C_0+30*x+y)的{​​{1}}之类的内容我不能为每种可能的情况进行特殊模式匹配。我需要一种方法来更改所有出现次数

在Mathematica中,我按照以下步骤进行操作

x+C_0*exp(3*x)+3*y+C_0*exp(30*x+y)

哪个给出了

Mathematica graphics

我实际上更愿意告诉Python只需将expr = x + Exp[c + 3*x]*3*y + 3*y + Exp[c + 30*x + y] expr /. Exp[c + any_] :> (c Exp[any]) 更改为exp(C+anything)而无需为整个表达式提供模式,因为这可能会以多种方式发生变化。

我确信上面的内容也可以在python / sympy中使用。有任何提示怎么做?

1 个答案:

答案 0 :(得分:1)

我会在表达式中查找函数exp,检查其参数是否为Add,然后C_0Add的参数。然后构建一个替换exp的东西。请考虑以下事项:

from sympy import *
x, y, C_0 = symbols('x y C_0')
expr = x + exp(C_0+3*x) + 3*y + exp(y+C_0+30*x) - exp(x+y-C_0) + exp(x*y)

exp_sum = [(a, a.args[0].args) for a in preorder_traversal(expr) if a.func == exp and a.args[0].func == Add]
exp_sum = [p for p in exp_sum if C_0 in p[1]]

new_exp = [C_0*exp(Add(*[x for x in p[1] if x != C_0])) for p in exp_sum]

for (old, new) in zip(exp_sum, new_exp):
    expr = expr.subs(old[0], new)

最初,exp_sum包含exp(Add(...))形式的所有部分。之后,它被过滤为包含C_0的总和。通过获取非C_0的所有加数,添加它们,应用exp并乘以C_0来形成新的指数。然后替换发生。

为了澄清这个过程,以下是上面例子中exp_sum的内容:元组列表(指数和内部的加数):

 [(exp(C_0 + 3*x), (C_0, 3*x)), (exp(C_0 + 30*x + y), (C_0, y, 30*x))]

这是new_exp

 [C_0*exp(3*x), C_0*exp(30*x + y)]

最后,expr在最后:

 C_0*exp(3*x) + C_0*exp(30*x + y) + x + 3*y + exp(x*y) - exp(-C_0 + x + y)

请注意,exp(-C_0 ...)不受更改的影响;它不是模式的一部分。