2013-07-25 55 views
25

在这个网站上有很多关于在cython中使用numpy的问题,特别有用的问题是Simple wrapping of C code with cython通过Cython传递和返回numpy数组到C++方法

但是,cython/numpy接口API seems to have changed a bit,特别是确保传递内存连续数组。

什么是用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) 

此代码编译,但并不一定是最优的。你有什么建议来改进上面的代码片段吗?

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

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! 

+5

你仍然需要进口'作为numpy的在np'你'.pyx'文件使用numpy的功能('cimport numpy的作为np' [ “用于导入关于numpy模块的特殊编译时信息”](http://docs.cython.org/src/tutorial/numpy.html#adding-types))。 – jorgeca

+0

@jorgeca我想你的评论回答OP的问题... –

+1

@SaulloCastro我发布它作为评论,因为我认为这是一个小的障碍,但我不知道什么是写这些接口的最佳方式。 – jorgeca

回答

17

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

您可以进行一些简化代码的文体修改。 (1)不需要在1D和2D阵列之间进行整形。当你知道你的数据的内存布局(C顺序与fortran顺序,striding等)时,你可以看到数组只是你要用C++编制索引的一块内存,所以numpy的ndim不会'无论在C++方面 - 它只是看到那个指针。 (2)使用Cython的地址运算符&,可以使用&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 
+1

说,这可以用Cython中的类型化的memoryview来完成,而不是传递数组?我不确定这是否会节省一些内存开销等? – krishnab