作为 Max 问题的解决方法,您可以使用
helpers=("Max", (abs(x+y) + abs(x-y))/2, [x, y])
表达方式(abs(x+y) + abs(x-y))/2
在数学上等价于max(x, y)
并且不会引起任何投诉autowrap
。一个完整的例子:
from sympy import *
from sympy.utilities.autowrap import autowrap
x, y = symbols('x y')
f = autowrap(Max(2*x, y+1), args=[x, y], backend="cython", helpers=("Max", (abs(x+y) + abs(x-y))/2, [x, y]))
print([f(5, 6), f(1, 2)]) # outputs 10 and 3
相似地,Heaviside(x)
是相同的(x + abs(x))/(2*x)
-- 但当 x=0 时后一个表达式为 NaN。更丑陋但安全的版本是(x + abs(x))/(2*abs(x) + 1e-300)
添加 1e-300 几乎不会改变结果。
多个助手的问题
您需要帮手both马克斯和赫维赛德。这就是你点击的地方开放问题 https://github.com/sympy/sympy/issues/10572:autowrap 中存在一个错误,导致无法使用多个助手。文档 http://docs.sympy.org/latest/modules/utilities/autowrap.html#sympy.utilities.autowrap.autowrap建议格式如下
helpers=[("Max", ..., [x, y]), ("Heaviside", ..., [x])]
But 在这条线上 https://github.com/sympy/sympy/blob/master/sympy/utilities/autowrap.py#L506autowrap 所做的事情对于一个助手来说很方便(我们不必将其放入列表中),但对于多个助手来说是致命的(额外的一层包装):
helpers = [helpers] if helpers else ()
自然,接下来的拆包for name_h, expr_h, args_h in helpers
fails.
多个助手的解决方法
The ufuncify
把手helpers
论证正确。很遗憾,ufuncify
最终打电话autowrap
对于除 NumPy 之外的所有后端,因此错误仍然发生在 autowrap 中。但如果你愿意使用 NumPy 后端,这是一个解决方案:
from sympy.utilities.autowrap import ufuncify
x, y = symbols('x y', real=True)
my_helpers = [("Max", abs(x+y)/2 + abs(x-y)/2, [x, y]), ("Heaviside", (x + abs(x)) / (2*abs(x) + 1e-300), [x])]
f = ufuncify([x,y], Max(2*x, y+1) + Heaviside(x-4), backend="numpy", helpers=my_helpers)
print([f(5, 6), f(1, 2)]) $ outputs 11 and 3
减少到一名助手
如果您可以更改表达式以消除 Max 和 Heaviside 之一(甚至两者),则可以使用 Cython 后端。例如,也许您只需要 Max(x, 0),因此您定义了一个 Python 函数“正部分”:
pos = lambda x: (x+abs(x))/2
那么autowrap就没有问题了pos
,你只需要帮助Heaviside:
f = autowrap(pos(9-x-y) + Heaviside(x-4), args = [x, y], backend = "cython", helpers=("Heaviside", (x + abs(x)) / (2*abs(x) + 1e-300), [x]))
print([f(5, 6), f(1, 2)]) # outputs 1 and 6
这种替换的实用性取决于您的符号表达式是如何获得的。