同情力量评估Mul(tiplication)

时间:2014-03-28 03:51:39

标签: python sympy

在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进行评估呢?我已经尝试了simplifyexpand等的所有组合,以及我能想到的每种选项组合。但没有什么能让它们随处可见。我甚至可以用.args[0]提取总和的前半部分并尝试简化/扩展它。没事!

更糟糕的是,我的实际用例涉及许多嵌套表达式,如

>>> b*expand((x+y)*a)
b*(x*a + y*a)

发生了什么事?我怎样才能使它工作?什么是神奇的词?

2 个答案:

答案 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代码库以了解如何使用它)。