【发布时间】:2017-06-01 10:55:07
【问题描述】:
我有以下问题:
我想使用自动换行来生成 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 限制...?)
与上述部分相关:
- 是否可以编译以数组形式接受参数的函数。
有没有办法生成接受 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,但在这里可能是一个问题。无论如何,似乎不是正确的方法。)
- 各种数组类型的对象,用要包装的表达式中的符号填充。
例如
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
这实际上是在自动换行示例中使用的;但是,以(对我而言)直观的方式,使用方程式作为要包装的表达式。此外,它在那里的使用方式对我来说似乎并不可行:我想要 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 的代码,但我感觉有点迷茫……
所以我仍在寻找解决方案,并乐于接受任何意见。
【问题讨论】:
-
C 编译器必须能够接受的maximum number of arguments 是 127(但他们可以接受更多)。我认为数组参数将是解决方案,但我对 Sympy 知之甚少。
-
Fortran doesn't appear to have a built in limit,但我认为 f2py 生成了一个 C 包装函数,所以可能不是您的问题的解决方案。