首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将2D Cython指针返回到Python数组

将2D Cython指针返回到Python数组
EN

Stack Overflow用户
提问于 2020-05-29 11:07:35
回答 1查看 506关注 0票数 2

我目前正在将指针的指针从Cython传递给C:

代码语言:javascript
运行
复制
    #convert the input Python 2D array to a memory view
    cdef double[:,:] a_cython= np.asarray(a,order="C")
    #define a pointer of a pointer with dimensions of a
    cdef double** point_to_a = <double **>malloc(N * sizeof(double*))
    #initialize the pointer
    if not point_to_a: raise MemoryError
    #try:
    for i in range(N):
        point_to_a[i] = &a_cython[i, 0]

    #pass this double pointer to a C function
    logistic_sigmoid(&point_to_a[0], N,M)

其中a是一个numpy数组,其维度为N x Mpoint_to_a是一个指针的Cython指针,该指针指的是Cython a_cython。由于Python的输入a是二维数组,所以我认为这是将信息直接传递给C的最佳方法。不过,我现在正试图将point_to_a重新转换为一个numpy数组,但我还有点挣扎。

我正在考虑各种解决办法。我想探讨是否有可能在整个过程中保持一个N维数组,因此我在Cython中试验了这种方法:

代码语言:javascript
运行
复制
    #define a integer array for dimensions
    cdef np.npy_intp dims[2]
    dims[0]=  N
    dims[1] = M
    #create a new memory view and PyArray_SimpleNewFromData to deal with the pointer
    cdef np.ndarray[double, ndim=2] new_a =  np.PyArray_SimpleNewFromData(2, &dims[0], np.NPY_DOUBLE, point_to_a)

但是,当我将new_a转换为np.array为array = np.asarray(new_a)时,只有0的数组。你有什么想法吗?

非常感谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-29 12:23:52

一旦您使用int** (或类似的),您的数据就处于所谓的间接内存布局中。Cython的类型化内存视图支持间接内存布局(参见Cython: understanding a typed memoryview with a indirect_contignuous memory layout),但是实现此接口的类不多。

numpy的ndarray不实现间接内存布局--它们只支持直接内存布局(例如int*类型的指针,而不是int**),因此将int**传递给numpy数组没有好处。

好的是,因为您与a_cython共享了内存,因此已经就地更新了这些值。您可以通过返回类型化内存视图的base-object来获得底层的numpy数组,即

代码语言:javascript
运行
复制
return a_cython.base # returns 2d-numpy array.

根本不需要复制内存!

然而,内存管理也存在一些问题(例如,您需要释放point_to_a)。

在您的情况下,这可能是一个过分的选择,但我利用这个机会无耻地插入了我的indirect_buffer库:因为间接内存布局缓冲区的替代方案很少,而且不时需要一个缓冲区,所以我创建了一个缓冲区,以避免编写相同的代码。

使用indirect_buffer,您的函数如下所示:

代码语言:javascript
运行
复制
%%cython
#just an example for a c-function
cdef extern from *:
    """
    void fillit(int** ptr, int N, int M){
       int cnt=0;
       for(int i=0;i<N;i++){
          for(int j=0;j<M;j++){
            ptr[i][j]=cnt++;
          }
       }
    }
    """
    void fillit(int** ptr, int N, int M)

from indirect_buffer.buffer_impl cimport IndirectMemory2D
def py_fillit(a):
    #create collection, it is a view of a
    indirect_view=IndirectMemory2D.cy_view_from_rows(a, readonly=False)
    fillit(<int**>indirect_view.ptr, indirect_view.shape[0], indirect_view.shape[1])
    # values are updated directly in a

它现在可以使用,例如:

代码语言:javascript
运行
复制
import numpy as np
a=np.zeros((3,4), dtype=np.int32)
py_fillit(a)
print(a)
# prints as expected:
#  array([[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11]])

上面的版本做了很多正确的事情:内存管理、缓冲区锁定等等。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62084515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档