2013-07-25 56 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