同情中的递归替换

drh*_*gen 7 python sympy

我有一个需要替换的多个变量的表达式.问题是要替换的一些表达式还包含需要替换的变量实例.

from sympy import *
from sympy.abs import a,b, x,y

expr = a + b
replace = [[a, x+y], [b, 2*a]]

expr.subs(replace) # 2*a + x + y, I want 3*x + 3*y
Run Code Online (Sandbox Code Playgroud)

如果替换列表的顺序正确,它将按顺序应用每个替换,但在我的实际应用程序中,我不知道哪个顺序是合适的:

expr.subs(reversed(replace)) # 3*x + 3*y
Run Code Online (Sandbox Code Playgroud)

我可以通过应用替代n次要么强制替代expr或者replace,但这似乎浪费计算:

result = expr
for _ in replace:
    # Applying n times
    result = result.subs(replace)
Run Code Online (Sandbox Code Playgroud)

我希望有一个recursive选项subs,但这似乎不存在.有更好的选择吗?

asm*_*rer 6

如果按正确顺序执行,则将以迭代方式执行替换(除非您使用subs(replacement, simultaneous=True),它会立即执行所有替换).

您的问题是正确订购替换品.你想要的是拓扑式的替代品.即,每次更换处于图中的节点,并且存在从一个边缘(old1, new1)(old2, new2)如果new1包含old2(即,应当先被替换).

SymPy拥有的实现topological_sortsympy.utilities.iterables.它采用顶点列表和边缘列表(顶点元组).说你有

replace = [(y, z + 1), (x, y + z), (z, a)]
Run Code Online (Sandbox Code Playgroud)

我们可以创建一个边缘列表

from itertools import combinations
edges = [(i, j) for i, j in permutations(replace, 2) if i[1].has(j[0])]
Run Code Online (Sandbox Code Playgroud)

对此进行排序

>>> from sympy import default_sort_key, topological_sort
>>> topological_sort([replace, edges], default_sort_key)
[(x, y + z), (y, z + 1), (z, a)]
Run Code Online (Sandbox Code Playgroud)

第三个论点topological_sort是用来打破关系的关键.由于SymPy对象没有在它们上定义的隐式排序(<并且通常会>提高TypeError),因此调用了一个排序键实现default_sort_key,它提供了SymPy对象的规范和一致(但任意)排序.

在404所示的情况下,会出现无限循环,topological_sort会提醒您有一个循环

>>> replace = [(x, y+1), (y, x+1)]
>>> edges = [(i, j) for i, j in permutations(replace, 2) if i[1].has(j[0])]
>>> topological_sort([replace, edges], default_sort_key)
Traceback (most recent call last):
  File "<ipython-input-51-72f3bfcfd4ad>", line 1, in <module>
    topological_sort([replace, edges], default_sort_key)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/sympy/utilities/iterables.py", line 882, in topological_sort
    raise ValueError("cycle detected")
ValueError: cycle detected
Run Code Online (Sandbox Code Playgroud)

老实说,这应该subs通过关键字参数直接实现.请参阅https://github.com/sympy/sympy/issues/6257.