27

在这个网站上有很多关于在 cython 中使用 numpy 的问题,一个特别有用的问题是Simple wrapping of C code with cython

但是,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)

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

X_c = ...(2)在运行时调用它时抛出和“np is not defined on line ”)。确切的测试代码和错误信息如下:

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!

4

1 回答 1

20

你基本上是对的。首先,希望优化不应该是一个大问题。理想情况下,大部分时间都花在 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
于 2013-08-11T21:12:48.673 回答