Pasar y devolver arrays numpy a métodos C++ a través de Cython
Hay muchas preguntas sobre el uso de numpy en cython en este sitio, una particularmente útil es Simple envoltura de código C con cython.
Sin embargo, la api de interfaz cython/numpy parece haber cambiado un poco, en particular para garantizar el paso de matrices contiguas de memoria.
¿Cuál es la mejor manera de escribir una función wrapper en cython que:
- toma una matriz numpy que es probable pero no necesariamente contigua
- llamadas un método de clase C++ con la firma
double* data_in, double* data_out
- devuelve una matriz numpy del
double*
que el método escribió?
Mi intento está abajo:
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)
Este código compila pero no es necesariamente óptimo. ¿Tiene alguna sugerencia para mejorar el fragmento de código anterior?
and (2) lanza y "np no está definido en línea X_c = ...
") cuando lo llama en tiempo de ejecución.
El código de prueba exacto y el mensaje de error son los siguientes:
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!
1 answers
Básicamente lo has hecho bien. Primero, esperemos que la optimización no sea un gran problema. Idealmente, la mayor parte del tiempo se pasa dentro de su kernel de C++, no en el código de envoltura de cythnon.
Hay algunos cambios estilísticos que puede hacer que simplificarán su código. (1) No es necesario remodelar entre matrices 1D y 2D. Cuando conoce el diseño de memoria de sus datos (orden C vs. orden fortran, zancadas, etc.), puede ver la matriz como solo un trozo de memoria que va a indexar tú mismo en C++, así que el ndim de numpy no importa en el lado de C++ 's es solo ver ese puntero. (2) Usando la dirección del operador de cython &
, puede obtener el puntero al inicio de la matriz de una manera un poco más limpia no no es necesario un cast explícito using usando &X[0,0]
.
Así que esta es mi versión editada de tu fragmento original:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-11 21:12:48