sympy 中的 subs、replace 和 xreplace 有什么区别?
我一直在使用 subs 来替换符号。我正在与某人讨论,他们建议在大多数情况下使用替换而不是替换。然后我也偶然发现了 xreplace。
对于我的应用程序,我用表达式替换变量。为此,是否推荐其中之一?各自的主要用途是什么?一般推荐哪一款?
所有引用和示例基础知识均归功于官方文档,但试图进行直接而彻底的比较
潜艇 | 更换 | x替换 | |
---|---|---|---|
签名 |
|
|
|
文档字符串 | 在符号化参数后用表达式中的旧值替换新值。 | 用 value 替换 self 的匹配子表达式。 | 替换表达式中出现的对象。 |
“另请参阅”链接简介 | 替换对象本身定义的子表达式。 | 替换能够进行类似通配符的匹配、匹配解析和条件替换 | expr树中的精确节点替换;还能够使用匹配规则 |
替换设计 | 逻辑替换 | 查询或规则匹配 | 图案替换 |
接受替换映射 | True dict 或新:旧对 |
错误 一次一个,尽管它可能有复杂的逻辑 |
真实 模式和替换的字典 |
对于单个表达式,
subs
替换真正的等价项,提取子表达式并替换它们,而 replace
和 xreplace
匹配文字模式 - 例如,查看它们如何匹配 x**2
>>> (x**2 + x**4).subs(x**2, y) # logical/mathematical replacement
y**2 + y
>>> (x**2 + x**4).xreplace({x**2: y}) # pattern replacement (multiple)
x**4 + y
>>> (x**2 + x**4).replace(x**2, y) # pattern replacement (single)
x**4 + y
但是,虽然
subs
和 xreplace
具有相当简单的可接受参数,但 replace
具有非常复杂的语法,替换了一些表达式(请参阅警告!)、类型、模式或过滤器 .. 并进一步使用第一个参数修改第二个替换参数可以从表达式到可调用的格式,它还可以传递匹配本身或匹配的参数!
按类型替换
>>> (x**2 + x**4).replace(Pow, lambda a,b: Pow(a, b+1)) # unpacks Pow args
x**5 + x**3
>>> (x**2 + x**4).replace(Pow, lambda a,b: tan(a)**(b+1))
tan(x)**5 + tan(x)**3
>>> (x**2 + x**4).replace(Number, lambda: 10) # make every number 10
2*x**10
按图案替换
>>> (x**2 + x**4).replace(Wild('a', exclude=[Pow, 4]), lambda a: y)
y**4 + y**y
替换为可调用过滤器
>>> (x**2 + x**4).replace(lambda expr: expr**2 == x**2, lambda a: y)
y**4 + y**2
>>> (x**2 + x**4).replace(lambda expr: expr%2==0, lambda a: Pow(y, a))
x**(y**2) + x**(y**4)
rewrite(*args, deep=True, **hints)
使用定义的规则重写 self。
重写将一个表达式转换为另一个表达式,这在数学上是等效的,但在结构上是不同的。例如,您可以将三角函数重写为复指数或将组合函数重写为伽玛函数。
>>> expr = cos(x) + I*sin(x)
>>> expr.rewrite(exp)
exp(I*x)
>>> expr.rewrite(sin, exp)
exp(I*x)/2 + cos(x) - exp(-I*x)/2
match(pattern, old=False)
(和matches
助手)>>> (x**2 + x**4).match(Wild('n')**4 + (Wild('m')**2))
{n_: x, m_: x}
subs 文档特别指出,
.evalf()
也支持替换,并且在替换后进行数值评估时,这会考虑传递的精度,可能会得到更预期的结果
>>> (1/x).evalf(subs={x: 3.0}, n=21)
0.333333333333333333333
>>> (1/x).subs({x: 3.0}).evalf(21)
0.333333333333333314830
Wild
Wild
可以意外地匹配very - 请查看我对使用“exact=False”时expr.replace()的实际行为是什么?!
在进行模式匹配时,请进一步注意对顺序和真实表示的敏感性 - 发生这种有点不明显的行为是因为
replace
将传递的表达式视为 pattern,当涉及其他符号时,这可能不是完全匹配!
>>> (x**2 + x**4).match(Wild('n')**2 + (Wild('m')**4))
{n_: x**2, m_: sqrt(x)}
>>> (x**2 + x**4).match(Wild('n')**4 + (Wild('m')**2))
{n_: x, m_: x}
>>> srepr(x**2 + x**4)
"Add(Pow(Symbol('x'), Integer(4)), Pow(Symbol('x'), Integer(2)))"
>>> (x**2 + x**4 - y**3).replace(x**2 + x**4, y) # fails
x**4 + x**2 - y**3
>>> (x**2 + x**4 - y**3).replace(x**4 + x**2, y) # closer
x**4 + x**2 - y**3
>>> srepr(x**2 + x**4 - y**3) # actually of the form Add(a, b, c)
"Add(Pow(Symbol('x'), Integer(4)), Pow(Symbol('x'), Integer(2)), Mul(Integer(-1), Pow(Symbol('y'), Integer(3))))"