考虑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)
。
答案 0 :(得分:1)
max
是内置的Python函数,它试图立即评估,因此错误(它无法确定n
和m
中的哪一个更大当它们是象征性的时候)。您可能需要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**2
与x**2*y**0
匹配。由于替换函数的数学值取决于表达式的形式,因此这是有问题的,因为SymPy试图变得聪明。您实际上可以n
和m
与Wild('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))
也许有人会找到更好的解决方案......