Ale*_*lex 7 c python arrays numpy cython
我有一些C代码具有以下声明:
int myfunc(int m, int n, const double **a, double **b, double *c);
Run Code Online (Sandbox Code Playgroud)
所以a是一个恒定的二维数组,b是一个二维数组,并且c是一维数组,都是动态分配的. b并且c在传递之前不需要任何具体的东西myfunc,应该被理解为输出信息.出于这个问题的目的,我不允许更改声明myfunc.
问题1:如何将给定的numpy数组a_np转换为a具有此C函数所需格式的数组,以便我可以在Cython中调用此C函数a?
问题2:是的声明b和c下方正确的,或者他们需要在其他格式的C函数将其理解为一个二维和一维数组(分别)?
我的尝试:
myfile.pxd
cdef extern from "myfile.h":
int myfunc(int p, int q, const double **a, double **b, double *c)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
然后在iPython中我运行
import pyximport; pyximport.install()
import mytest
Run Code Online (Sandbox Code Playgroud)
带有定义的行a给出了错误消息Cannot convert Python object to 'double **'.我没有得到任何错误消息有关b或c,但因为我不能在这个时候运行的C函数,我不知道的声明b和c编写正确(即,在某种程度上,这将启用C功能分别输出2D和1D阵列).
其他尝试:我也尝试过这里的解决方案,但这不适用于我在myfunc声明中使用的双星号类型的数组.这里的解决方案不适用于我的任务,因为我无法更改声明myfunc.
要从double**numpy数组中获取a ,可以在*.pyx文件中创建一个辅助数组指针.此外,您必须确保numpy数组具有正确的内存布局.(可能涉及创建副本)
如果您的C函数需要fortran顺序(一个列表中的所有x坐标,另一个列表中的所有y坐标,第三个列表中的所有z坐标,如果您的数组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)
Run Code Online (Sandbox Code Playgroud)
如果你的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)
Run Code Online (Sandbox Code Playgroud)
回复 1:您可以使用数组开头的位置通过 Cython 将 NumPy 数组传递给 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)
Run Code Online (Sandbox Code Playgroud)
然后将&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()
Run Code Online (Sandbox Code Playgroud)
其中是模块中定义的mywrappedfuncPython(def而非)函数,可以执行上面所示的数组声明。cdef