[英]cython: pass a 2D numpy array to cdef function
I want to pass a 2D numpy array to a cdef function, where the dimensions of the array can vary. 我想将2D numpy数组传递给cdef函数,该数组的尺寸可以变化。 Here's what I tried:
这是我尝试过的:
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)
where my test_array function is: 我的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
and my function prototype is: 我的函数原型是:
cdef void test_array(Py_ssize_t nrows, Py_ssize_t ncols, double **x, unsigned char **output) nogil
When I compile, I get an error saying " Cannot take address of Python object" and pointing to &input[0]
. 编译时,出现错误消息“无法获取Python对象的地址”,并指向
&input[0]
。 That syntax works for a 1D array, but I'm not sure what the syntax is for a 2d array. 该语法适用于一维数组,但是我不确定二维数组的语法是什么。 I also tried
&input[0][0]
but that's wrong too. 我也尝试了
&input[0][0]
但这也是错误的。
It is not clear what you would like to achieve: 目前尚不清楚您要实现什么目标:
A: if it should be a pure cython function then you should use typed memory view , that means your function signature should be 答:如果它应该是纯cython函数,则应使用类型化的内存视图 ,这意味着您的函数签名应为
cdef void test_array(double[:,:] x, unsigned char[:,:] output) nogil:
There are no nrows
, ncols
because the typed memory views have this information (similar to std::vector
). 没有
nrows
, ncols
因为类型化的内存视图具有此信息(类似于std::vector
)。
B: array_test
is actually a wrapper for a c-function, which expects double **
and unsigned char **
, then you should take a look at this SO-question . B:
array_test
实际上是c函数的包装,它期望double **
和unsigned char **
,然后您应该看一下这个SO问题 。
Actually, I would like to explain, why your attempts didn't work. 实际上,我想解释一下,为什么您的尝试不起作用。
First, why didn't &input[0]
work? 首先,为什么
&input[0]
不起作用? The real question is what is 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'>
so input
is a numpy.ndarray
that means a python object, and cython refuses to take its address. 所以
input
是一个numpy.ndarray
,表示一个python对象,而cython拒绝使用其地址。 The same is the case for the input[0,0]
- it is a python object. input[0,0]
也是这种情况-这是一个python对象。 No luck so far. 到目前为止没有运气。
To get it work, you need the input
to be a cython-numpy array (I don't know how to express it better - take a look at the example): 为了使其正常工作,您需要将
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
The important part: input
is no longer considered/interpreted as a python object but as of type cython-type np.ndarray[double, ndim=2]
and this is what makes the syntax &input[0,0]
possible in the first place. 重要部分:
input
不再被视为/解释为python对象,而是cython类型的np.ndarray[double, ndim=2]
,这使得语法&input[0,0]
可能。
Maybe a more precise way to see it like: cimport numpy
gives us additional tools in handling of numpy arrays so we can access internals which are not accessible in pure python. 也许是一种更精确的查看方式:
cimport numpy
为我们提供了处理numpy数组的其他工具,因此我们可以访问纯python中无法访问的内部函数。
However, &input[0,0]
is not of type double **
but of type double *
, because numpy.ndarray
is just a continuous chunk of memory and only the operator [i,j]
mocks the feeling of 2d: 但是,
&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
There are no pointers to rows, but you could create them via cdef double *ptr2=&input[row_id,0]
, how it could be handled is discussed in the above mentioned question . 没有指向行的指针,但是您可以通过
cdef double *ptr2=&input[row_id,0]
创建它们,在上述问题中讨论了如何处理它。
To say that numpy.ndarray
is just a continuous piece of memory is a simplification - numpy.ndarray
is quite a complicated beast! 说
numpy.ndarray
只是一块连续的内存是一种简化numpy.ndarray
是相当复杂的野兽! Please consider the following example: 请考虑以下示例:
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"!
Now, here input
and column
share the same memory and in the memory input[1][0]
is saved after input[0][1]=column[0]
and only then input[1][1]=column[1]
. 现在,这里的
input
和column
共享相同的内存,在input[0][1]=column[0]
之后, input[1][0]
被保存,然后input[1][1]=column[1]
input[1][0]
被保存在内存中input[1][1]=column[1]
。 ptr[1]
takes the memory cell next to input[0][1]
and this is input[1][0]=3
and not input[1][1]=4
. ptr[1]
在input[0][1]
旁边接存储单元,这是input[1][0]=3
而不是input[1][1]=4
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.