Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何直接调用ctypes SciPy被积函数?_Python_Python 3.x_Scipy_Ctypes - Fatal编程技术网

Python 如何直接调用ctypes SciPy被积函数?

Python 如何直接调用ctypes SciPy被积函数?,python,python-3.x,scipy,ctypes,Python,Python 3.x,Scipy,Ctypes,我有一些数字代码要在SciPy中运行。它涉及多项式指数的复杂有理函数,因此计算成本相当高;因此,我已经用C编写了它,并使用ctypes调用它。最重要的用例是作为scipy.integrate.quad的被积函数,但我偶尔也需要直接调用它 我的函数的“自然”签名是 double f(double x, double y, double z){} 建议与相应的Python一起使用 import ctypes so = ctypes.CDLL('/path/to/f.so') f = so.f f.

我有一些数字代码要在SciPy中运行。它涉及多项式指数的复杂有理函数,因此计算成本相当高;因此,我已经用C编写了它,并使用ctypes调用它。最重要的用例是作为scipy.integrate.quad的被积函数,但我偶尔也需要直接调用它

我的函数的“自然”签名是

double f(double x, double y, double z){}
建议与相应的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)
不管怎样,把它称为被积函数

在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
,将它们作为名为
args
的元组传递到
quad

scipy.integrate.quad(f, lowerlimit, upperlimit, args=(y,z))
这就不清楚如何直接调用
f
。我天真的尝试失败了

f(3, (x,y,z))
但这会为参数2产生一个类型错误。一些变体也同样失败了。这并不奇怪;ctypes期望函数调用正好有一个整数参数,后跟一个双参数

我完全不知道
quad
是如何进入
y
z
f
。我试着查看SciPy源代码,但我必须承认,我在试图将调用从Python跟踪到C,再跟踪到Fortran时迷失了方向

我可以编写另一个函数作为直接调用或集成的包装器,但只使用一种形式似乎更为优雅,至少,我想了解SciPy调用是如何工作的

如何直接调用
f
的SciPy被积函数形式,传递所有三个参数
x
y
z

我使用的是Python 3.4.3、NumPy 1.11.2和SciPy 0.18.1


Edit:注意,可以通过更改其argtype来调用
f

f.argtypes = (ctypes.c_int, 3*ctypes.c_double)
f(3, (3*ctypes.c_double)(x, y, z))
不过,我还是很好奇SciPy在做什么。一直来回设置argtypes,充其量也是不雅观和不方便的



编辑2:请注意,在上一次编辑之后,这个问题现在基本上是的一个副本,它已在右侧列中弹出。您无法在Python级别解决此问题。文件说明

用C写一个函数签名为double的被积函数 f(整数n,双参数[n])

在您的情况下,您必须在C级别添加一个函数

double f_for_scipy(int n, double args[n]) {
    return f(args[0], args[1], args[2]);
}

然后将其馈送到quad。

您无法在Python级别修复此问题。文件说明

用C写一个函数签名为double的被积函数 f(整数n,双参数[n])

在您的情况下,您必须在C级别添加一个函数

double f_for_scipy(int n, double args[n]) {
    return f(args[0], args[1], args[2]);
}

我不知道这是否有助于
ctypes
的情况,但是当调用Python integrad时,这些
scipy
函数将自由变量与参数连接起来。换句话说

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
及其扩展类型来试验这类调用


我不知道这是否有助于
ctypes
的情况,但是在调用Python Integrated时,这些
scipy
函数将自由变量与参数连接起来。换句话说

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
及其扩展类型来试验这类调用


您需要有正确的函数签名,但是类型Python argtypes应该是
指针(c\u double)
。C中的数组衰减到函数参数中的指针:

C示例(Windows)


您需要有正确的函数签名,但是类型Python argtypes应该是
指针(c\u double)
。C中的数组衰减到函数参数中的指针:

C示例(Windows)


“你不能在Python级别解决这个问题。”为什么不呢?SciPy必须以某种方式调用函数及其所有参数。在保持quad的编译性能的同时,您无法修复它。当被积函数是一个编译过的C函数,它加载了ctypes并传递给quad时,整个过程都是用编译过的代码完成的。如果您传递一个Python可调用函数,这也会起作用,但性能会不那么有趣。然后应该使用“real”接口
f.argtypes=(ctypes.c_-double,ctypes.c_-double,ctypes.c_-double)
并调用
scipy.integrate.quad(lambda x,y,z:f(x,y,z),下限,上限,args=(y,z))
。这意味着Python将以一定代价正确地转换
x,y,z
参数;请参见上面的编辑。不过这并不漂亮,我仍然很好奇SciPy是如何调用函数的。SciPy“只是”将函数指针传递给已编译的四元例程。我很想知道为什么你的解决方案有效,你有一个指向ctypes文档的指针吗?您是否有任何方法来检查数值结果是否正确?“您无法在Python级别修复此问题。”为什么不?SciPy必须以某种方式调用函数及其所有参数。在保持quad的编译性能的同时,您无法修复它。当被积函数是一个编译过的C函数,它加载了ctypes并传递给quad时,整个过程都是用编译过的代码完成的。如果您传递一个Python可调用函数,这也会起作用,但性能会不那么有趣。然后应该使用“real”接口
f.argtypes=(ctypes.c\u double,ctypes.c\u doubl