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
符号 w1
从 Wild
匹配中排除 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)
我对这些问题进行了很多搜索,老实说,找不到适合我的情况的内容。
我正在使用 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
符号 w1
从 Wild
匹配中排除 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)