sympy autowrap(cython):参数数量的限制,数组形式的参数?

时间:2017-06-01 10:55:07

标签: cython sympy

我有以下问题:

我想使用autowrap生成一个sympy矩阵的编译版本,其中包含包含sympy表达式的单元格。根据我的问题的规范,参数的数量会变得非常大。

我遇到了以下两个问题:

  • autowrap接受的参数数量似乎限制为509。

即,这有效:

import sympy
from sympy.utilities.autowrap import autowrap

x = sympy.symbols("x:509")
exp = sum(x)
cyt = autowrap(exp, backend="cython", args=x) 

这无法编译:

x = sympy.symbols("x:510")
exp = sum(x)
cyt = autowrap(exp, backend="cython", args=x) 

我收到的消息似乎不太明白:

[...] (Full output upon request)
Generating code
c:\users\[classified]\appdata\local\temp\tmp2zer8vfe_sympy_compile\wrapper_module_17.c(6293) : fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'f:\dd\vctools\compiler\utc\src\p2\hash.c', line 884)
 To work around this problem, try simplifying or changing the program near the locations listed above.
Please choose the Technical Support command on the Visual C++ 
 Help menu, or open the Technical Support help file for more information
LINK : fatal error LNK1257: code generation failed
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\link.exe' failed with exit status 1257

这有什么办法吗?我想使用我的程序版本,需要~1000个输入变量。 (我对C / cython一无所知。这是一个自动限制,一个C限制......?)

部分与上述有关:

  • 可以编译接受参数为array的函数。

有没有办法生成接受numpy数组作为输入的代码?我特意指的是所有参数的一个数组,而不是将参数作为列表提供。 (类似于使用DeferredVector的lambdify)。 ufuncify支持数组输入,但据我所知只是广播/矢量化函数。

我希望作为参数的数组可以绕过上面的第一个问题,这对我来说是最紧迫的。除此之外,我更喜欢数组输入,因为它看起来更快(不需要解压缩我作为输入到列表中的numpy数组),而且更直接和自然。

有没有人有什么建议我可以做什么? 还有,谁能告诉我f2py是否有类似的限制?如果可行的话,这对我来说也是一个选择,但我目前还没有把它设置为工作,并且在投入时间之前更愿意知道它是否有帮助。 谢谢!

编辑:

我和不同的候选人谈了一下,告诉autowrap输入参数是数组形式的东西,而不是数字列表。我将在此处记录我的步骤,以便为后人记录,并增加获得一些意见的机会:

  • sympy.DeferredVector

我使用lambdify是出于同样的目的,所以我想试一试。但是,警告

A = sympy.DeferredVector("A")
expression = A[0]+A[1]
cyt = autowrap(expression, backend="cython", args=A)

刚刚完全崩溃了我的操作系统 - 最后一个语句开始执行,(没有反馈),一切都变得很慢,然后没有更多的反应。 (只能推测,也许它与A没有形状信息这一事实有关,这似乎不会打扰lambdify,但这可能是一个问题。无论如何,似乎不是正确的方法。)

  • 所有类型的数组类型对象都填充了要包装的表达式中的符号。

e.g。

x0 ,x1 = sympy.symbols("x:2")
expression = x0 + x1
cyt = autowrap(expression, backend="cython", args=np.array([x0,x1]))

仍然需要解压缩的参数。用

替换最后一行
cyt = autowrap(expression, backend="cython", args=[np.array([x0,x1])])

给出消息

CodeGenArgumentListError: ("Argument list didn't specify: x0, x1 ", [InputArgument(x0), InputArgument(x1)])

这种方法的反复出现主题:在参数列表中使用sympy矩阵,元组等时也会发生。

  • sympy.IndexedBase

这实际上是在autowrap示例中使用的;然而,在(对我而言)直观的方式中,使用等式作为要包装的表达式。此外,它的使用方式对我来说似乎并不可行:我想要cythonize的表达式是一个矩阵,但它的单元格本身就是长表达式,我无法通过索引操作获得。

好处是我得到了一个最小的例子:

X = sympy.IndexedBase("X",shape=(1,1))
expression = 2*X[0,0]
cyt = autowrap(expression, backend="cython", args=[X])

实际编译,结果函数正确评估 - 传递2d-np.array时。

所以这似乎是最有希望的途径,尽管这种方法的进一步扩展我一直在尝试失败。

例如这个

X = sympy.IndexedBase("X",shape=(1,))
expression = 2*X[0]
cyt = autowrap(expression, backend="cython", args=[X])

让我

[...]\site-packages\sympy\printing\codeprinter.py", line 258, in _get_expression_indices " rhs indices in %s" % expr)
ValueError: lhs indices must match non-dummy rhs indices in 2*X[0]

即使我不知道它与上面的工作方式有什么不同。

粘贴到两个维度时会出现相同的错误消息,但会增加X的大小:

X = sympy.IndexedBase("X",shape=(2,2))
expression = 2*X[0,0]+X[0,1]+X[1,0]+X[1,1]
cyt = autowrap(expression, backend="cython", args=[X])

ValueError: lhs indices must match non-dummy rhs indices in 2*X[0, 0] + X[0, 1] + X[1, 0] + X[1, 1]

我试着窥探autowrap的代码,但我觉得有点迷失......

所以我仍然在寻找解决方案并为任何输入感到高兴。

1 个答案:

答案 0 :(得分:2)

将参数作为数组传递似乎可以正常工作

x = sympy.MatrixSymbol('x', 520, 1)

exp = 0
for i in range(x.shape[0]):
    exp += x[i]

cyt = autowrap(exp, backend='cython')

arr = np.random.randn(520, 1)
cyt(arr)
Out[48]: -42.59735861021934

arr.sum()
Out[49]: -42.597358610219345