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

查看:31
本文介绍了将 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是一个常量二维数组,b是一个二维数组,而c是一个一维数组,都是动态分配的.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 中用 a 调用这个 C 函数吗?

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 函数能够分别输出二维和一维数组).

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天全站免登陆