我有一些在SciPy中运行的数字代码。它涉及多项式指数的复杂有理函数,因此计算量很大;我已经用C语言编写了它,并使用ctypes调用它。最重要的用例是作为scipy.integrate.quad的集成,但我偶尔也需要直接调用它。
我的功能的“自然”签名是
double f(double x, double y, double z){}
ctypes documentation建议使用的和相应的Python
import ctypes
so = ctypes.CDLL('/path/to/f.so')
f = so.f
f.restype = ctypes.c_double
f.argtypes = (ctypes.c_double, ctypes.c_double, ctypes.c_double)
然而,无论如何将其称为被积函数SciPy requires a certain function signature
double f(int n, double args[n]){}
在Python代码中指定为
import ctypes
so = ctypes.CDLL('/path/to/f.so')
f = so.f
f.restype = ctypes.c_double
f.argtypes = (ctypes.c_int, ctypes.c_double)
要在执行积分时传递参数y
和z
,它们会作为名为quad
的元组传递给args
。
scipy.integrate.quad(f, lowerlimit, upperlimit, args=(y,z))
这使得不清楚如何直接致电f
。我天真的尝试是
f(3, (x,y,z))
但是这会产生参数2的类型错误。几个变体同样无法工作。这并不奇怪; ctypes期望一个函数调用只有一个整数参数,后跟一个双参数。
我完全不知道quad
如何y
和z
进入f
。我试着查看SciPy源代码,但我必须承认我试图跟踪Python中的调用到C语言中的丢失。
我可以编写另一个函数作为直接调用或集成的包装器,但只使用一个表单似乎更优雅,至少,我想了解SciPy调用的工作原理。
如何直接调用f
的SciPy被学习形式,传递所有三个参数x
,y
和z
?
我正在使用Python 3.4.3,NumPy 1.11.2和SciPy 0.18.1。
修改:请注意,可以通过更改其argtypes来调用f
:
f.argtypes = (ctypes.c_int, 3*ctypes.c_double)
f(3, (3*ctypes.c_double)(x, y, z))
我仍然很好奇SciPy正在做什么。一直来回设置argtypes仍然是不优雅和不方便,充其量。
编辑2 请注意,在上一次修改之后,此问题现在基本上与this one重复,并在右栏中弹出了这个问题。
答案 0 :(得分:2)
您无法在Python级别修复此问题。文档https://docs.scipy.org/doc/scipy/reference/tutorial/integrate.html#faster-integration-using-ctypes陈述
使用函数签名double在C中编写一个被积函数 f(int n,double args [n])
在您的情况下,您必须在C级别添加一个
的函数double f_for_scipy(int n, double args[n]) {
return f(args[0], args[1], args[2]);
}
并将其提供给四元组。
答案 1 :(得分:0)
我不知道这对ctypes
情况是否有帮助,但在调用Python integrad时,这些scipy
函数会将自由变量与args连接起来。换句话说
def bar(x,y,z):
return np.sin(x*y*z)
In [43]: quad(bar,0,1, args=(1,2))
Out[43]: (0.7080734182735712, 7.861194120923578e-15)
当评估为0.5时,(x,)+args
:
In [49]: bar(*(.5,)+(1,2))
Out[49]: 0.8414709848078965
In [50]: bar(.5,1,2)
Out[50]: 0.8414709848078965
使用c
签名:
f_for_scipy(int n, double args[n])
n
是参数的数量,args[n]
是指向数组的指针。
我正在使用cython
及其扩展类型
https://cython.readthedocs.io/en/latest/src/tutorial/cdef_classes.html
Passing a cython function vs a cython method to scipy.integrate
答案 2 :(得分:0)
您需要具有正确的函数签名,但类型Python argtypes应为POINTER(c_double)
。 C中的数组衰减到函数参数中的指针:
C示例(Windows)
#include <stdio.h>
__declspec(dllexport) double f(int n, double args[])
{
double sum = 0;
int nn;
for(nn = 0; nn < n; ++nn)
{
printf("args[%d] = %ld\n",nn,args[nn]);
sum += args[nn];
}
return sum;
}
ctypes示例
>>> from ctypes import *
>>> dll = CDLL('x')
>>> dll.f.restype = c_double
>>> dll.f.argtypes = c_int,POINTER(c_double)
>>> L=[1.1,2.2,3.3,4.4,5.5]
>>> args = (c_double*len(L))(*L)
>>> dll.f(len(args),args)
args[0] = 1.100000
args[1] = 2.200000
args[2] = 3.300000
args[3] = 4.400000
args[4] = 5.500000
16.5