将Cython中的numpy数组传递给需要动态分配数组的C函数 [英] Passing numpy arrays in Cython to a C function that requires dynamically allocated arrays

查看:247
本文介绍了将Cython中的numpy数组传递给需要动态分配数组的C函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些具有以下声明的C代码:

I have some C code that has the following declaration:

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

因此,a是一个恒定的2D数组,b是一个2D数组,而c是一个1D数组,它们都是动态分配的. bc在传递给myfunc之前不需要特别指定任何内容,应将其理解为输出信息.出于此问题的目的,不允许更改myfunc的声明.

So a is a constant 2D array, b is a 2D array, and c is a 1D array, all dynamically allocated. b and c do not need to be anything specifically before they are passed to myfunc, and should be understood as output information. For the purposes of this question, I'm not allowed to change the declaration of myfunc.

问题1:如何将给定的numpy数组a_np转换为具有此C函数所需格式的数组a,以便可以在Cython中使用以下命令调用此C函数: a?

Question 1: How do I convert a given numpy array a_np into an array a with the format required by this C function, so that I can call this C function in Cython with a?

问题2:下面的bc的声明正确无误,还是C函数需要采用其他某种格式才能将它们理解为2D和1D数组? (分别)?

Question 2: Are the declarations for b and c below correct, or do they need to be in some other format for the C function to understand them as a 2D and 1D array (respectively)?

我的尝试:

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中运行

Then in iPython I run

import pyximport; pyximport.install()
import mytest

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

The line with the definition of a gives me the error message Cannot convert Python object to 'double **'. I don't get any error messages regarding b or c, but since I'm unable to run the C function at this time, I'm not sure the declarations of b and c are written correctly (that is, in a way that will enable the C function to output a 2D and a 1D array, respectively).

其他尝试:我也尝试按照解决方案此处进行操作,但这没有我不能使用myfunc声明中的双星号类型的数组.解决方案此处不适用于我的任务,因为我无法更改myfunc的声明.

Other attempts: I've also tried following the solution here, but this doesn't work with the double-asterisk type of arrays I have in the myfunc declaration. The solution here does not apply to my task because I can't change the declaration of myfunc.

推荐答案

在cython中创建一个辅助数组

要从numpy数组中获取double**,可以在* .pyx文件中创建指针的帮助器数组.此外,您必须确保numpy数组具有正确的内存布局. (这可能涉及创建副本)

Create a helper array in cython

To get a double** from a numpy array, you can create a helper-array of pointers in your *.pyx file. Further more, you have to make sure that the numpy array has the correct memory layout. (It might involve creating a copy)

如果您的C函数期望fortran顺序(一个列表中的所有x坐标,另一列表中的所有y坐标,第三列表中的所有z坐标,如果您的数组a对应于3D空间中的点列表)

If your C-function expects fortran order (all x-coordinates in one list, all y coordinates in another list, all z-coordinates in a third list, if your array a corresponds to a list of points in 3D space)

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订单

如果您的C函数期望C阶([x1,y1,z1]是第一个列表,[x2,y2,z2]是第二个3D点列表):

C-order

If your C-function expects C-order ([x1,y1,z1] is the first list, [x2,y2,z2] the second list for a list of 3D points):

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)

这篇关于将Cython中的numpy数组传递给需要动态分配数组的C函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆