我想将2D numpy数组传递给cdef函数,其中数组的尺寸可以变化。这是我试过的:
cimport numpy as cnp
input = numpy.array([[3.34, 2.2],[1.1, -0.6]])
input = input[:,:].astype(np.double)
cdef int nrows = 2
cdef int ncols = 2
# output of function
cdef cnp.ndarray[cnp.uint8_t, ndim=2] output = np.zeros((2,2), dtype=np.uint8)
test_array(nrows, ncols, &input[0], <unsigned char**>output.data)
我的test_array函数是:
cdef void test_array(Py_ssize_t nrows, Py_ssize_t ncols, double **x, unsigned char **output) nogil:
output[0][0]=1
output[1][0]=0
output[1][1]=1
output[0][1]=0
我的函数原型是:
cdef void test_array(Py_ssize_t nrows, Py_ssize_t ncols, double **x, unsigned char **output) nogil
当我编译时,我收到一条错误,上面写着“无法获取Python对象的地址”并指向&input[0]
。该语法适用于一维数组,但我不确定二维数组的语法是什么。我也试过&input[0][0]
,但这也错了。
答案 0 :(得分:3)
目前尚不清楚您希望实现的目标:
A:如果它应该是纯粹的cython函数,那么你应该使用typed memory view,这意味着你的函数签名应该是
cdef void test_array(double[:,:] x, unsigned char[:,:] output) nogil:
没有nrows
,ncols
,因为输入的内存视图包含此信息(类似于std::vector
)。
B: array_test
实际上是c函数的包装器,它需要double **
和unsigned char **
,那么你应该看看这个{ {3}}
实际上,我想解释一下,为什么你的尝试不起作用。
首先,为什么&input[0]
没有工作?真正的问题是什么是input[0]
:
import numpy as np
input=np.zeros((3,3))
type(input[0])
<type 'numpy.ndarray'>
type(input[:,0])
<type 'numpy.ndarray'>
type(input[0,0])
<type 'numpy.float64'>
所以input
是一个numpy.ndarray
,意思是一个python对象,而cython拒绝接受它的地址。 input[0,0]
的情况也是如此 - 它是一个python对象。到目前为止没有运气。
要使它工作,你需要input
成为一个cython-numpy数组(我不知道如何更好地表达它 - 看看这个例子):
import numpy as np
cimport numpy as np #that the way it is usually imported
def try_me():
cdef np.ndarray[double, ndim=2] input = np.array([[3.34, 2.2],[1.1, -0.6]])
cdef double *ptr1=&input[0,0]
cdef double *ptr2=&input[1,0]
print ptr1[0], ptr2[1] #prints 3.34 and -0.6
重要的部分:input
不再被视为/解释为python对象,而是类型为cython-type np.ndarray[double, ndim=2]
,这使得语法&input[0,0]
成为可能地点。
可能更精确地看待它:cimport numpy
为处理numpy数组提供了额外的工具,因此我们可以访问纯python中无法访问的内部。
但是,&input[0,0]
不是double **
类型,而是double *
类型,因为numpy.ndarray
只是一个连续的内存块,只有运算符[i,j]
嘲笑2d的感觉:
How it feels:
A[0] -> A00 A01 A02
A[1] -> A10 A11 A12
The real layout in the memory:
A00 A01 A02 A10 A11 A12
没有指向行的指针,但您可以通过cdef double *ptr2=&input[row_id,0]
创建它们,SO-question中讨论了如何处理它们。
要说numpy.ndarray
只是一段连续的记忆是一种简化 - numpy.ndarray
是一个非常复杂的野兽!请考虑以下示例:
import numpy as np
cimport numpy as np
def try_me2():
cdef np.ndarray[double, ndim=2] input = np.array([[1.0, 2.0],
[3.0, 4.0]])
cdef np.ndarray[double, ndim=1] column = input[:,1]
cdef double *ptr = &column[0]
print column #prints column "2 4"
print ptr[0],ptr[1] #prints "2 3" and not "2 4"!
现在,此处input
和column
共享相同的内存,内存input[1][0]
会在input[0][1]=column[0]
之后保存,然后才会input[1][1]=column[1]
。 ptr[1]
获取input[0][1]
旁边的内存单元格,这是input[1][0]=3
而不是input[1][1]=4
。