SymPy:如何实现对几个 "look-alike" 项的一般替换?

SymPy: how to implement a general substitution for several "look-alike" terms?

我对这些问题进行了很多搜索,老实说,找不到适合我的情况的内容。

我正在使用 SymPy 库来执行大型计算,它一直运行得非常好。然而,我最近的结果变得太复杂了。因此,我开始实现更多的定义和符号,以便执行多个替换并将表达式缩小到更可行的形式。我已经能够做到这一点,'manually',对于很多术语来说,这些术语太过特殊以至于不允许任何类型的自动化。但是,如果我可以 运行 这个简单的替换规则,我的表达中有一个特定的贡献家族可以大大简化。

设A为我的完整表达。在 this image, the dots represent already simplified terms and the summation represents the general setup behind my query. My goal is to rewrite it like this.

T_k 只是表示通用术语;实际上,它们是由几个字面值 Symbols 组成的。在我的代码中,rho 字母与单个变量 Symbol 类型相关联。因此,话虽如此,我的问题可以举例如下:

# sympy symbols: rho, a, b, c, d
# sympy functions: f, g, h
A = (a * b) * f(rho) + (c * d) * g(rho) + (a * c * d * b) * h(rho)

# apply some clever substitution method ???
A.subs(???)
  >>> f(a * b) * rho + g(c * d) * rho + h(a * c * d * b) * rho

当然,在上面的例子中,我可以“手工”完成。问题出在有很多这样的术语时。我尝试使用 lambda 表达式来实现我的目标,但无法实现。这个想法是:对于任何通用 lambda t,我可以尝试为每个符号函数 (# f, g, h) 输入映射 {t * f(rho) : f(t) * rho},但不关心特定的伴随项。

我试着定义,例如,genSub_f = lambda t: A.subs(t * f(rho), f(t) * rho)。但是,为了进行替换,我必须调用 genSub_f(a * b),这可行,但它不切实际,因为必须保留有关与 [=20= 一起使用的符号组合的先验知识].如何进行?

您可以为此使用 Wild 符号,但是有几种方法可以获得您想要的输出。

一个复杂的问题是您似乎不想应用替换 f(a*b)*rho -> f(a*b*rho)。有几种方法可以实现这一点,但首先我会给出一个确实会导致这种替换的答案:

from sympy import *
rho, a, b, c, d = symbols("rho, a, b, c, d")
f, g, h = symbols("f, g, h", cls=Function)
A = (a * b) * f(rho) + (c * d) * g(rho) + (a * c * d * b) * h(rho)

w1, w2 = symbols("w1, w2", cls=Wild)

for ff in [f, g, h]:
    A = A.replace(w1*ff(w2), w2*ff(w1))

print(A)  # f(a*b*rho) + g(c*d*rho) + h(a*b*c*d*rho)

那么排除替换 rho*f(a*b) -> f(a*b*rho) 呢?

一种方法是通过像这样定义 Wild 符号 w1Wild 匹配中排除 rho(我们还必须排除替代 1*f(...) -> ...*f(1)).这会产生您想要的输出:

A = (a * b) * f(rho) + (c * d) * g(rho) + (a * c * d * b) * h(rho)

w1 = Wild("w1", exclude=[rho, 1])  # exclude unwanted substitutions
w2 = Wild("w2")

for ff in [f, g, h]:
    A = A.replace(w1*ff(w2), w2*ff(w1))

print(A)  # rho*f(a*b) + rho*g(c*d) + rho*h(a*b*c*d)

但是,另一种实现所需输出的方法是使用 match 而不是 replace。这样您就不必明确排除 rho(使用这种方法,替换是手动完成的,因此无需担心避免 'double' 应用替换规则):

A = (a * b) * f(rho) + (c * d) * g(rho) + (a * c * d * b) * h(rho)

w1, w2, w3 = symbols("w1, w2, w3", cls=Wild)

for ff in [f, g, h]:
    m = A.match(w1*ff(w2) + w3)
    if m:
        A = m[w2]*ff(m[w1]) + m[w3]  # manual replacement

print(A)  # rho*f(a*b) + rho*g(c*d) + rho*h(a*b*c*d)