4

我试图编译一个包含 UndefinedFunction 的表达式,该表达式提供了一个实现。(或者:一个包含符号的表达式,表示对外部数值函数的调用)

有没有办法做到这一点?使用 autowrap 或 codegen 还是手动编辑生成的文件?

以下天真的示例不起作用:

import sympy as sp
import numpy as np
from sympy.abc import *
from sympy.utilities.lambdify import implemented_function
from sympy.utilities.autowrap import autowrap, ufuncify

def g_implementation(a):
    """represents some numerical function"""
    return a*5

# sympy wrapper around the above function
g = implemented_function('g', g_implementation)

# some random expression using the above function
e = (x+g(a))**2+100

# try to compile said expression
f = autowrap(e, backend='cython')
# fails with "undefined reference to `g'"

编辑:

我有几个大的 Sympy 表达式

表达式是自动生成的(通过微分等)

表达式包含一些调用一些数值函数的“实现的未定义函数”(即 NOT Sympy 表达式)

必须评估某些输入的表达式的最终脚本/程序将经常被调用。这意味着评估 Sympy 中的表达式(通过 evalf)绝对不可行。即使及时编译(lambdify、autowrap、ufuncify、numba.jit)也会产生过多的开销。

基本上我想为这些表达式创建一个二进制 python 扩展,而不必在 C 中手动实现它们,我认为这太容易出错了。

操作系统是 Windows 7 64 位

4

2 回答 2

1

您可能想看看这个关于 SymPy lambdas 序列化(由 lambdify 生成)的答案。

这不完全是您所要求的,但可能会缓解您的启动性能问题。然后lambdify-ied函数将主要只计算执行时间。

你也可以看看Theano。它与 SymPy 有很好的集成。

于 2016-02-05T03:18:58.137 回答
0

好的,我希望这可以解决问题,如果不让我知道,我会再试一次。

我将使用表达式的编译版本与表达式进行Cython比较lambdified

from sympy.utilities.autowrap import autowrap
from sympy import symbols, lambdify

def wraping(expression):
    return autowrap(expression, backend='cython')

def lamFunc(expression, x, y):
    return lambdify([x,y], expr)

x, y = symbols('x y')
expr = ((x - y)**(25)).expand()
print expr


binary_callable = wraping(expr)
print binary_callable(1, 2)

lamb = lamFunc(expr, x, y)
print lamb(1,2)

输出:

x**25 - 25*x**24*y + 300*x**23*y**2 - 2300*x**22*y**3 + 12650*x**21*y**4 - 53130*x**20*y**5 + 177100*x**19*y**6 - 480700*x**18*y**7 + 1081575*x**17*y**8 - 2042975*x**16*y**9 + 3268760*x**15*y**10 - 4457400*x**14*y**11 + 5200300*x**13*y**12 - 5200300*x**12*y**13 + 4457400*x**11*y**14 - 3268760*x**10*y**15 + 2042975*x**9*y**16 - 1081575*x**8*y**17 + 480700*x**7*y**18 - 177100*x**6*y**19 + 53130*x**5*y**20 - 12650*x**4*y**21 + 2300*x**3*y**22 - 300*x**2*y**23 + 25*x*y**24 - y**25

-1.0
-1

如果我计算执行时间,自动包装函数的速度会快 10 倍(取决于问题,我还观察到因素只有两个的情况):

%timeit binary_callable(12, 21)
100000 loops, best of 3: 2.87 µs per loop

%timeit lamb(12, 21)
100000  loops, best of 3: 28.7 µs per loop

所以这里wraping(expr)包装你的表达式expr并返回一个包装的对象binary_callable。您可以随时使用它来进行数值评估。

编辑:我已经在 Linux/Ubuntu 和 Windows 操作系统上完成了这项工作,似乎都可以正常工作!

于 2015-08-27T12:19:29.220 回答