在sympy中分布加法的乘法似乎并没有评估乘法。
我已经创建了一个sympy.Symbol
的子类,它知道如何通过其他东西来增加自己。作为一个最小的工作示例,让我们假装子类只是吃掉乘以它的任何东西:
from sympy import *
class Gobbler(Symbol):
_op_priority = 1.0e200
def __mul__(self, other):
return Gobbler('gob('+self.name+'*'+str(other)+')')
def __rmul__(self, other):
return Gobbler('gob('+self.name+'*'+str(other)+')')
x = Gobbler('x')
y = Gobbler('y')
a = Symbol('a')
b = Symbol('b')
[是的,_op_priority
是荒谬的。但是把它改成更可敬的数字~10.0并没有改变任何东西。]我可以运行
>>> x*a
gob(x*a)
>>> x*a + y*a
gob(x*a) + gob(y*a)
在我到达
之前,一切都很自然>>> expand((x+y)*a)
x*a + y*a
为什么这些不被狼吞虎咽?!结果看起来与我在之前的提示中输入的结果完全一样,但没有任何反应。
Gobblers现在是Mul
中的因子,其中两个是Add
中的术语。那么我如何才能对这些Mul
进行评估呢?我已经尝试了simplify
,expand
等的所有组合,以及我能想到的每种选项组合。但没有什么能让它们随处可见。我甚至可以用.args[0]
提取总和的前半部分并尝试简化/扩展它。没事!
更糟糕的是,我的实际用例涉及许多嵌套表达式,如
>>> b*expand((x+y)*a)
b*(x*a + y*a)
发生了什么事?我怎样才能使它工作?什么是神奇的词?
答案 0 :(得分:0)
嗯,这不是我所希望的,但我认为解决方案必然涉及通过表达并强制应用程序。应用此类应用程序就像应用simplify
一样,所以它不会太意外或繁重。以下内容足以满足我的目的,但更通用的表达式可能需要更多特殊情况。找到了基本思想here, in the tutorial,并涉及通过表达式树递归:
def gobbleExpr(expr):
if isinstance(expr, Gobbler):
return expr
if isinstance(expr, Mul):
args = list(o if o.is_Atom or isinstance(o, Gobbler)
else gobbleExpr(o)
for o in expr.args)
gobbler = prod(t for t in args if isinstance(t, Gobbler))
others = prod(o for o in args if not isinstance(o, Gobbler))
if gobbler==1:
return others
else:
return gobbler.__mul__(others)
if isinstance(expr, Add):
return sum(gobbleExpr(arg) for arg in expr.args)
return expr
所以现在我可以做类似
的事情>>> expand(b*(x+y)*a)
x*a*b + y*a*b
>>> gobbleExpr(_)
gob(gob(x*1)*a*b) + gob(gob(y*1)*a*b)
所以唯一剩下的东西是Gobbler
彼此添加,我在别处处理。
答案 1 :(得分:0)
Mul没有打电话__mul__
(__mul__
仅在您使用*
时被调用,因为它的Python运算符重载)。 SymPy目前还没有提供一种在Mul上发送的方式,尽管它在我们的TODO列表中。阻碍它的主要原因是我们不确定如何做到这一点。您的解决方案可能是最好的方法(除了我提到的更正)。
您还可以设置_op_priority
(搜索SymPy代码库以了解如何使用它)。