简体   繁体   English

cython:将2D numpy数组传递给cdef函数

[英]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 ). 没有nrowsncols因为类型化的内存视图具有此信息(类似于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] . 现在,这里的inputcolumn共享相同的内存,在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM