sympy:使用Wild符号作为函数

时间:2016-05-30 01:18:34

标签: python python-3.x sympy

考虑python / sympy中的以下表达式:

from sympy.abc import x, y
expression = 3*x**2*y**1 + x**2*y**3

现在我想通过模式匹配将x**n*y**m替换为max(n,m)

from sympy import Wild
n = Wild('n')
m = Wild('m')
expression = expression.replace(x**n*y**m,max(n,m))

但是,我得到TypeError

Traceback (most recent call last):
   File "wild.py", line 15, in <module>
     expression = expression.replace(x**n*y**m,max(n,m))
   File "/usr/lib/python3/dist-packages/sympy/core/relational.py", line 103, in __nonzero__
     raise TypeError("cannot determine truth value of\n%s" % self)
TypeError: cannot determine truth value of
    m_ > n_

问题显然是在匹配表达式时,sympy不会将Wild符号的值转换为匹配值,而是将其转发给max - 函数。有没有办法让这项工作?

请注意,这是我所遇到的更一般问题的一个简单示例,因此一个不能很好地概括的解决方法并不是很有帮助。我特别希望有一个使用表达式匹配的解决方案。

更新:根据三明治的建议并将max(n,m)替换为(m+n+abs(m-n))/2,但我在实际程序中使用的功能要复杂得多。 关于三明治提到的问题,replace从表达式树的底部开始执行替换:如果我使用exact=True并定义f = sympy.Function('f'),则以下工作(除了我必须处理有些情况分开):

expression = expression.replace(x**n*y**m,f(n,m),exact=True)
但是,它仍然不适用于max(n,m)

2 个答案:

答案 0 :(得分:1)

max是内置的Python函数,它试图立即评估,因此错误(它无法确定nm中的哪一个更大当它们是象征性的时候)。您可能需要SymPy Max函数,它具有符号效果。您在答案中定义的my_func实际上是Max的基本实现。

<击>
In [14]: expression = expression.replace(x**n*y**m, Max(n,m))

In [15]: expression
Out[15]: 4

<击>

这似乎不起作用(答案4是错误的)。问题是它将x**2x**2*y**0匹配。由于替换函数的数学值取决于表达式的形式,因此这是有问题的,因为SymPy试图变得聪明。您实际上可以nmWild('n', exclude=[x, 0])不匹配,但是有一个问题与x**2*y x**2*y**1不匹配。

所以我建议将表达式转换为多项式并完全替换。希望这能很好地概括到你实际在做什么

In [18]: Poly(expression, x, y)
Out[18]: Poly(x**2*y**3 + 3*x**2*y, x, y, domain='ZZ')

In [19]: Poly(expression, x, y).terms()
Out[19]: [((2, 3), 1), ((2, 1), 3)]

In [20]: sum(max(pows)*coeff for pows, coeff in Poly(expression, x, y).terms())
Out[20]: 9

答案 1 :(得分:0)

好的,我已经找到了一个解决方案,但是它非常漂亮,但这可能与我对编写与sympy很好地交互的函数知之甚少这一事实有关。

首先我导入所有相关内容:

import sympy
from sympy.abc import x, y, a, b,z
from sympy import Wild
from sympy import Function

然后我定义了自己的函数,它将返回最大值,这里返回的max(x,y)可以用更复杂的函数替换:

class my_func(Function):
  @classmethod
  def eval(cls, x, y):
    if x.is_Number and y.is_Number:
      return max(x,y)

我想要修改的表达式是:

3*x**2*y**1 + x**2*y**3

我定义了必要的百搭符号和一个临时功能,暂时用于替换而不进行评估:

n = Wild('n')
m = Wild('m')
k = Wild('k')
f = Function('f')
expression = expression.replace(x,f(1,0),exact=True)
expression = expression.replace(y,f(0,1),exact=True)
expression = expression.replace(f(1,0)**n,f(n,0),exact=True)
expression = expression.replace(f(0,1)**n,f(0,n),exact=True)
expression = expression.replace(k*f(0,m)*f(n,0),k*f(n,m),exact=True)

这些替代品可以解决我的问题中出现的所有情况。在最后一步中,我将f替换为进行评估的my_func

expression = expression.replace(f(n,m),my_func(n,m))

也许有人会找到更好的解决方案......