通过Cython将numpy数组传递给C++方法并返回

Mic*_*ert 25 python arrays numpy cython

在这个网站上有很多关于在cython中使用numpy的问题,一个特别有用的问题是使用cython 简单包装C代码.

但是,cython/numpy接口api 似乎有所改变,特别是在确保内存连续数组的传递方面.

在cython中编写包装函数的最佳方法是:

  • 采用一个可能但不一定是连续的numpy数组
  • 使用签名调用C++类方法 double* data_in, double* data_out
  • 返回double*该方法写入的numpy数组?

我的尝试如下:

cimport numpy as np
import numpy as np # as suggested by jorgeca

cdef extern from "myclass.h":
    cdef cppclass MyClass:
        MyClass() except +
        void run(double* X, int N, int D, double* Y)

def run(np.ndarray[np.double_t, ndim=2] X):
    cdef int N, D
    N = X.shape[0]
    D = X.shape[1]

    cdef np.ndarray[np.double_t, ndim=1, mode="c"] X_c
    X_c = np.ascontiguousarray(X, dtype=np.double)

    cdef np.ndarray[np.double_t, ndim=1, mode="c"] Y_c
    Y_c = np.ascontiguousarray(np.zeros((N*D,)), dtype=np.double)

    cdef MyClass myclass
    myclass = MyClass()
    myclass.run(<double*> X_c.data, N, D, <double*> Y_c.data)

    return Y_c.reshape(N, 2)
Run Code Online (Sandbox Code Playgroud)

此代码编译但不一定是最佳的.您对改进上面的代码段有什么建议吗?

(2)X_c = ...在运行时调用它时抛出并且"np未在行上定义".确切的测试代码和错误消息如下:

import numpy as np
import mywrapper
mywrapper.run(np.array([[1,2],[3,4]], dtype=np.double))

# NameError: name 'np' is not defined [at mywrapper.pyx":X_c = ...]
# fixed!
Run Code Online (Sandbox Code Playgroud)

Rob*_*bon 18

你基本上做对了.首先,希望优化不应该是一个大问题.理想情况下,大部分时间都花在C++内核中,而不是在cythnon包装器代码中.

您可以进行一些风格上的更改,以简化您的代码.(1)不需要在1D和2D阵列之间进行重塑.当你知道数据的内存布局(C顺序与fortran顺序,跨越等)时,你可以看到数组只是你要用C++编写索引的一块内存,所以numpy的ndim不会在C++方面很重要 - 它只是看到了指针.(2)使用cython的address-of运算符&,你可以用一种更清晰的方式得到指向数组开头的指针 - 没有必要使用显式转换&X[0,0].

这是我原始代码段的编辑版本:

cimport numpy as np
import numpy as np

cdef extern from "myclass.h":
    cdef cppclass MyClass:
        MyClass() except +
        void run(double* X, int N, int D, double* Y)

def run(np.ndarray[np.double_t, ndim=2] X):
    X = np.ascontiguousarray(X)
    cdef np.ndarray[np.double_t, ndim=2, mode="c"] Y = np.zeros_like(X)

    cdef MyClass myclass
    myclass = MyClass()
    myclass.run(&X[0,0], X.shape[0], X.shape[1], &Y[0,0])

    return Y
Run Code Online (Sandbox Code Playgroud)