Python 将Cython中的numpy数组传递给需要动态分配数组的C函数
我有一些具有以下声明的C代码:Python 将Cython中的numpy数组传递给需要动态分配数组的C函数,python,c,arrays,numpy,cython,Python,C,Arrays,Numpy,Cython,我有一些具有以下声明的C代码: int myfunc(int m, int n, const double **a, double **b, double *c); 因此,a是一个恒定的二维数组,b是一个二维数组,c是一个一维数组,都是动态分配的b和c在传递到myfunc之前,不需要特别指定,应该理解为输出信息。就本问题而言,我不允许更改myfunc的声明 问题1:如何将给定的numpy数组a\u np转换为具有此C函数所需格式的数组a,以便在Cython中使用a调用此C函数 问题2:下面的b
int myfunc(int m, int n, const double **a, double **b, double *c);
因此,a
是一个恒定的二维数组,b
是一个二维数组,c
是一个一维数组,都是动态分配的b
和c
在传递到myfunc
之前,不需要特别指定,应该理解为输出信息。就本问题而言,我不允许更改myfunc
的声明
问题1:如何将给定的numpy数组a\u np
转换为具有此C函数所需格式的数组a
,以便在Cython中使用a
调用此C函数
问题2:下面的b
和c
声明是否正确,或者它们是否需要采用其他格式,以便c函数(分别)将其理解为2D和1D数组
我的尝试:
myfile.pxd
cdef extern from "myfile.h":
int myfunc(int p, int q, const double **a, double **b, double *c)
mytest.pyx
cimport cython
cimport myfile
import numpy as np
cimport numpy as np
p = 3
q = 4
cdef:
double** a = np.random.random([p,q])
double** b
double* c
myfile.myfunc(p, q, a, b, c)
然后我在伊皮顿跑步
import pyximport; pyximport.install()
import mytest
定义为a
的行给出了错误消息无法将Python对象转换为'double**'
。我没有收到任何关于b
或c
的错误消息,但由于此时我无法运行c函数,我不确定b
和c
的声明是否正确写入(也就是说,以使c函数能够分别输出2D和1D数组的方式)
其他尝试:我也尝试了以下解决方案,但这不适用于我在
myfunc
声明中使用的双星号类型的数组。该解决方案不适用于我的任务,因为我无法更改myfunc
的声明答复1:您可以使用数组起始位置通过Cython将NumPy数组传递给C(请参见下面的代码)
回答2:您的声明似乎是正确的,但我不使用这种显式内存管理方法。您可以使用NumPy声明cdef
-ed数组
使用
然后将数组开头的位置&a[0]
传递给C函数。::1
用于确保连续性
Jake Vanderplas的博客是一个很好的参考:
最后,通常在Cython中创建函数并在Python中调用它们,因此您的Python代码如下:
import pyximport; pyximport.install()
import mytest
mytest.mywrappedfunc()
其中,
mywrappedfunc
是模块中定义的Python(def
而不是cdef
)函数,可以执行上面显示的数组声明。回复1:您可以使用数组的起始位置,通过Cython将NumPy数组传递给C(请参见下面的代码)
回答2:您的声明似乎是正确的,但我不使用这种显式内存管理方法。您可以使用NumPy声明cdef
-ed数组
使用
然后将数组开头的位置&a[0]
传递给C函数。::1
用于确保连续性
Jake Vanderplas的博客是一个很好的参考:
最后,通常在Cython中创建函数并在Python中调用它们,因此您的Python代码如下:
import pyximport; pyximport.install()
import mytest
mytest.mywrappedfunc()
其中,mywrappedfunc
是模块中定义的Python(def
而不是cdef
)函数,可以执行上面显示的数组声明。在cython中创建帮助器数组
要从numpy数组中获取double**
,可以在*.pyx文件中创建指针的助手数组。此外,还必须确保numpy阵列具有正确的内存布局。(可能涉及创建副本)
Fortran指令
如果C函数需要fortran顺序(如果数组a对应于三维空间中的点列表,则一个列表中的所有x坐标、另一个列表中的所有y坐标、第三个列表中的所有z坐标)
N,M=a.shape
#确保阵列a具有正确的内存布局(此处为F顺序)
cdef np.ndarray[double,ndim=2,mode=“fortran”]a_cython=
np.asarray(a,dtype=float,order=“F”)
#创建我们的助手数组
cdef double**点到点=malloc(M*sizeof(double*))
如果不是指向a:引发MemoryError
尝试:
#用指针填充数组
对于范围内的i(M):
指向a[i]=&a[0,i]
#调用需要双精度的C函数**
myfunc(…&指向[0],…)
最后:
免费(点到点)
C阶
如果您的C函数需要C顺序([x1,y1,z1]是第一个列表,[x2,y2,z2]是第二个列表,用于3D点列表):
N,M=a.shape
#确保阵列a具有正确的内存布局(此处为C顺序)
cdef np.ndarray[double,ndim=2,mode=“c”]a_cython=
np.asarray(a,dtype=float,order=“C”)
#创建我们的助手数组
cdef double**点到点=malloc(N*sizeof(double*))
如果不是指向a:引发MemoryError
尝试:
对于范围(N)中的i:
指向a[i]=&a[i,0]
#调用需要双精度的C函数**
myfunc(…&指向[0],…)
最后:
免费(点到点)
在cython中创建助手数组
要从numpy数组中获取double**
,可以在*.pyx文件中创建指针的助手数组。此外,还必须确保numpy阵列具有正确的内存布局。(可能涉及创建副本)
Fortran指令
如果C函数需要fortran顺序(如果数组a对应于三维空间中的点列表,则一个列表中的所有x坐标、另一个列表中的所有y坐标、第三个列表中的所有z坐标)
N,M=a.shape
#确保阵列a具有正确的内存布局(此处为F顺序)
cdef np.ndarray[double,ndim=2,mode=“fortran”]a_cython=
np.asarray(a,dtype=float,order=“F”)
#创建我们的助手数组
cdef double**点到点=malloc(M*sizeof(double*))
如果不是指向a:引发MemoryError
尝试:
N,M = a.shape
# Make sure the array a has the correct memory layout (here F-order)
cdef np.ndarray[double, ndim=2, mode="fortran"] a_cython =
np.asarray(a, dtype = float, order="F")
#Create our helper array
cdef double** point_to_a = <double **>malloc(M * sizeof(double*))
if not point_to_a: raise MemoryError
try:
#Fillup the array with pointers
for i in range(M):
point_to_a[i] = &a_cython[0, i]
# Call the C function that expects a double**
myfunc(... &point_to_a[0], ...)
finally:
free(point_to_a)
N,M = a.shape
# Make sure the array a has the correct memory layout (here C-order)
cdef np.ndarray[double, ndim=2, mode="c"] a_cython =
np.asarray(a, dtype = float, order="C")
#Create our helper array
cdef double** point_to_a = <double **>malloc(N * sizeof(double*))
if not point_to_a: raise MemoryError
try:
for i in range(N):
point_to_a[i] = &a_cython[i, 0]
# Call the C function that expects a double**
myfunc(... &point_to_a[0], ...)
finally:
free(point_to_a)