gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 00:28:13 25 4
gpt4 key购买 nike

我想将 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

我的函数原型(prototype)是:

cdef void test_array(Py_ssize_t nrows, Py_ssize_t ncols, double **x, unsigned char **output) nogil

当我编译时,我收到一条错误消息“无法获取 Python 对象的地址”并指向 &input[0]。该语法适用于一维数组,但我不确定二维数组的语法是什么。我也试过 &input[0][0] 但这也是错误的。

最佳答案

不清楚你想达到什么目的:

答:如果它应该是一个纯cython函数那么你应该使用typed memory view ,这意味着你的函数签名应该是

cdef void test_array(double[:,:] x, unsigned char[:,:] output) nogil:

没有nrowsncols,因为类型化的内存 View 有这些信息(类似于std::vector)。

B: array_test 实际上是一个 c 函数的包装器,它需要 double **unsigned char ** ,那你应该看看这个SO-question .


其实,我想解释一下,为什么你的尝试没有奏效。

首先,为什么 &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 类型的 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] 创建它们,如何处理它在 above mentioned 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"!

现在,inputcolumn 共享同一内存,内存中 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

关于python - cython:将 2D numpy 数组传递给 cdef 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46714147/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com