将Cython中的Numpy阵列传递到需要动态分配阵列的C函数



我有一些c代码,其中具有以下声明:

int myfunc(int m, int n, const double **a, double **b, double *c);

因此,a是常数2D数组,b是2D数组,而c是1D数组,所有这些数组都动态分配。bc不需要在传递给myfunc之前具体做任何事物,应将其理解为输出信息。出于这个问题的目的,我不允许更改myfunc的声明。

问题1:如何使用此C函数所需的格式将给定的numpy数组a_np转换为阵列a,以便我可以使用a在Cython中调用此C函数?p> 问题2:在正确的bc的声明中,是否需要以其他格式以其他格式来理解它们为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)

然后在ipython中我运行

import pyximport; pyximport.install()
import mytest

带有a定义的行给我错误消息Cannot convert Python object to 'double **'。我没有收到有关bc的任何错误消息,但是由于我目前无法运行C函数,因此我不确定bc的声明是否正确编写(也就是说,以某种方式将使C函数分别输出2D和1D数组)。

其他尝试:我也尝试在此处遵循该解决方案,但这与我在myfunc声明中具有的双手类型的数组类型不起作用。这里的解决方案不适用于我的任务,因为我无法更改myfunc的声明。

在Cython中创建一个助手数组

要从Numpy数组获得double**,您可以在 *.pyx文件中创建指针的辅助阵列。此外,您必须确保Numpy阵列具有正确的内存布局。(它可能涉及创建副本)

fortran Order

如果您的c功能期望fortran订单(一个列表中的所有x坐标,另一个列表中的所有y坐标,则第三个列表中的所有z坐标物,如果您的数组A A ARRAY A对应于3D空间中的点列表)

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)

C-order

如果您的c功能期望C-订单([x1,y1,z1]是第一个列表,[x2,y2,z2] 3D列表的第二个列表):

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)

回复1:您可以使用数组开始的位置通过Cython将Numpy Array传递到C(请参阅下面的代码)。

回复2:您的声明看起来正确,但我不使用这种明确内存管理的方法。您可以使用numpy声明cdef -ED数组。

使用

cdef double[:,::1] a = np.random.random([p, q])
cdef double[:,::1] b = np.empty([p, q])
cdef double[::1] b = np.empty(q)

然后将&a[0](数组开始的位置)传递给您的C函数。::1是确保连续性。

这是杰克·范德帕拉斯(Jake Vanderplas)的博客:https://jakevdp.github.io/blog/2012/08/08/memoryview-benchmarks/

最后,通常一个人在Cython中创建功能并在Python中称为功能,因此您的Python代码将是:

import pyximport; pyximport.install()
import mytest
mytest.mywrappedfunc()

其中mywrappedfunc是Python(def而不是cdef)函数,该功能可以在上面显示的数组声明中定义。

最新更新