我有一个名为J_sym的sympy.Matrix,我想自动装配(最好使用cython后端);相应的符号存储在list_args列表中。
然而,我遇到的问题是显然有些情感功能不受支持,在我的情况下特别是同情.Max和sympy.Heaviside。
具体来说,如果我尝试
J_num_autowrap = autowrap(J_sym, backend="cython", args=list_args)
我得到以下内容:
[...]
wrapped_code_10.c(4): warning C4013: 'Heaviside' undefined; assuming extern returning int
wrapped_code_10.c(4): warning C4013: 'Max' undefined; assuming extern returning int
[...]
: fatal error LNK1120: 2 unresolved externals
[...]
failed with exit status 1120
(当一个lambdifies只使用numpy时会出现类似的问题;但是有一个人可以很容易地为这些函数传递一个字典。)
现在,似乎"助手" autowrap的论据应该提供一个解决方案;但是,我无法确定如何正确使用它。文档字符串本身是绝对神秘的,我发现只有这个链接的例子:
https://github.com/sympy/sympy/issues/10572
我不确定如何在这里正确使用帮助者 - 有人可以帮忙吗?
如果我沿着这些方向尝试:
J_num_autowrap = autowrap(J_sym, backend="cython", args=list_args, helpers=("Max", max(x,y), [x,y]))
如果未声明x,y,我会得到(a)错误 - 如何使用自由变量执行此操作?并且(b)如果我在声明x和y为同情符号之后也这样做,我只会得到错误"关系的真值不能确定"。
(上面的链接提到无论如何都不可能传递多个帮助器 - 即使在我看来这是在1.0中修复的。我仍然得到" ValueError:没有足够的值来解压缩(预计3,得到2)"当试图传递2个(乱码)辅助元组时。不确定状态 - 也许我在这里运气不好。)
如果有任何替代方法可以从我的矩阵中生成C代码,我将非常感谢该方向的任何提示。
答案 0 :(得分:2)
作为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几乎不会改变结果。
你想要帮助 Max和Heaviside。这就是你遇到open issue的地方:autowrap中有一个错误,它使得不可能使用多个助手。 Documentation表示格式类似于
helpers=[("Max", ..., [x, y]), ("Heaviside", ..., [x])]
但是on this line autowrap做了一个方便一个帮助的东西(我们不必把它放在一个列表中),但对于多个(额外的包装层)是致命的:
helpers = [helpers] if helpers else ()
当然,随后的解包for name_h, expr_h, args_h in helpers
失败了。
ufuncify
正确处理helpers
参数。不幸的是,ufuncify
最终会为除NumPy之外的所有后端调用autowrap
,因此错误仍然发生在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
然后自动装带对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
这种替换的实际程度取决于你的符号表达方式。