2013-07-25 18 views
25

Istnieje wiele pytań na temat korzystania z numpy w cytoncie na tej stronie, szczególnie przydatna jest Simple wrapping of C code with cython.Przekazywanie i zwracanie numpy tablic do C++ metod przez Cython

Jednak interfejs cython/numpy api seems to have changed a bit, w szczególności z zapewnieniem przekazywania szeregujących pamięci macierzy.

Jaki jest najlepszy sposób napisać funkcję otoki w Cython że:

  • zajmuje numpy tablicę, która może, ale niekoniecznie sąsiaduje
  • wywołuje C++ metody klasy z podpisem double* data_in, double* data_out
  • zwraca tablicę numpy z double*, do której napisała metoda?

Moja próba jest poniżej:

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) 

Ten kod kompiluje ale niekoniecznie jest optymalna. Czy masz jakieś sugestie dotyczące ulepszenia powyższego fragmentu?

i (2) rzuty i "np nie jest zdefiniowany na linii X_c = ...") podczas wywoływania go w czasie wykonywania. Dokładny kod testowania i komunikat o błędzie są następujące:

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

Trzeba jeszcze 'import numpy jak np' w pliku' .pyx' używać funkcji NumPy ('cimport numpy jak np' [ "służy do importowania specjalnych informacji o czasie kompilacji na temat modułu numpy" (http://docs.cython.org/src/tutorial/numpy.html#adding- typeses)). – jorgeca

+0

@jorgeca Zgaduję, że twój komentarz odpowiada na pytanie OP ... –

+1

@SaulloCastro Powiedziałem to jako komentarz, ponieważ uważałem, że jest to mała przeszkoda, ale nie wiem, jaki jest najlepszy sposób napisania tych interfejsów. – jorgeca

Odpowiedz

17

pan w zasadzie miał rację. Po pierwsze, mam nadzieję, że optymalizacja nie powinna być wielkim problemem. Idealnie, większość czasu spędza się wewnątrz jądra C++, a nie w kodzie opakowania cythnona.

Istnieje kilka zmian stylistycznych, które można wprowadzić, które uprości kod. (1) Zmiana kształtu między tablicami 1D i 2D nie jest konieczna. Kiedy znasz układ pamięci swoich danych (kolejność C w porównaniu z kolejnością fortranów, krokowanie itp.), Możesz zobaczyć tablicę jako tylko fragment pamięci, który zamierzasz indeksować się w C++, więc ndim nie robi tego " są ważne po stronie C++ - po prostu widzimy ten wskaźnik. (2) Używając adresu operatora cythonu - &, możesz dostać wskaźnik do początku tablicy w nieco czystszy sposób - bez wyraźnej obsady - używając &X[0,0].

Więc to jest moja edytowany wersja oryginalnego fragmentu:

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

Powiedzmy, czy można to zrobić z wpisanym widokiem pamięci w Cython, zamiast przekazywać tablicę? Nie byłem pewien, czy to zaoszczędziłoby trochę na pamięci, itp.? – krishnab

Powiązane problemy