我有一个“sympy.subs
substitutes too much”问题。
基本上,我已经定义了从sympsi Operator
类继承的costum sympy类。我们称其中之一为Tree
。该树又包含例如符号,并具有与之关联的某些代数规则,这些规则我已通过__add__
等定义。
然后我使用包含这些Tree
对象的数学表达式。例如:
x = symbols('x')
y = symbols('y')
z = symbols('z')
tree1 = Tree(x, y)
cool_quantity = x + y + tree1
我现在想替换其中一个符号,例如x
,带有另一个符号,例如z
:
cool_quantity_subs = cool_quantity.subs({x: z})
问题:我注意到,当我这样做时,替换也完成了[[inside Tree对象(请参见下面的最小工作示例)。我认为原因是通过从sympy.Expr继承将属性定义为自由符号。
问题:有没有办法仅在“顶层”进行符号替换?那就是替换表达式中直接包含的所有符号,而不替换自定义对象中的所有符号?
完整的最小工作示例
(不幸的是,必须运行sympsi,但是我认为问题对于使用自定义类的sympy来说是通用的。也许比我更了解sympy的人可以提出这样一个自定义的示例从本地sympy类继承的树类):from sympy import symbols
from sympsi import Operator
class Tree(Operator):
@property
def a(self):
return self.args[0]
@property
def b(self):
return self.args[1]
def __new__(cls, *args, **hints):
return Operator.__new__(cls, *args, **hints)
x = symbols('x')
y = symbols('y')
z = symbols('z')
tree1 = Tree(x, y)
cool_quantity = x + y + tree1
cool_quantity_subs = cool_quantity.subs({x: z})
print(cool_quantity)
# x + y + Tree(x,y)
print(cool_quantity_subs)
# y + z + Tree(z,y)
from functools import reduce
def special_subs(expr, to_rep, to_sub):
terms = []
for term in expr.args:
if term == to_rep:
term = to_sub
elif not isinstance(term, Tree):
if len(term.args)>0:
term = special_subs(term, to_rep, to_sub)
terms.append(term)
return expr.func(*terms)
应用于此问题中的最小工作示例
from sympy import symbols from sympsi import Operator from functools import reduce class Tree(Operator): @property def a(self): return self.args[0] @property def b(self): return self.args[1] def __new__(cls, *args, **hints): return Operator.__new__(cls, *args, **hints) x = symbols('x') y = symbols('y') z = symbols('z') tree1 = Tree(x, y) cool_quantity = x + y + tree1 cool_quantity_subs = cool_quantity.subs({x: z}) cool_quantity_special_subs = special_subs(cool_quantity, x, z) print(cool_quantity) # x + y + Tree(x,y) print(cool_quantity_subs) # y + z + Tree(z,y) print(cool_quantity_special_subs) # y + z + Tree(x,y)