multiplicar - python matrices tutorial
¿Cómo pasar una matriz Numpy a una función cffi y cómo recuperar una? (3)
Estoy desarrollando un algoritmo de audio usando Python y Numpy. Ahora quiero acelerar ese algoritmo implementando una parte de él en C. En el pasado, lo he hecho usando cython . Ahora quiero hacer lo mismo usando el nuevo cffi .
Para propósitos de prueba, escribí una función trivial en C:
void copy(float *in, float *out, int len) {
for (int i=0; i<len; i++) {
out[i] = in[i];
}
}
Ahora quiero crear dos matrices numpy y que sean procesadas por esta función. Descubrí una manera de hacer eso:
import numpy as np
from cffi import FFI
ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("/path/to/copy.dll")
float_in = ffi.new("float[16]")
float_out = ffi.new("float[16]")
arr_in = 42*np.ones(16, dtype=np.float32)
float_in[0:16] = arr_in[0:16]
C.copy(float_in, float_out, 16)
arr_out = np.frombuffer(ffi.buffer(float_out, 16*4), dtype=np.float32)
Sin embargo, me gustaría mejorar este código:
- ¿Hay alguna forma de acceder directamente a los buffers subyacentes de las matrices numpy sin copiarlos?
-
ffi.buffer
es muy conveniente para convertir rápidamente el contenido de una matriz C a una matriz Numpy. ¿Existe una forma equivalente de convertir rápidamente una matriz numpy en una matriz C sin copiar los elementos individuales? - Para algunas aplicaciones,
float_in[0:16] = arr_in[0:16]
es una forma conveniente de acceder a los datos. Sinarr_out[0:16] = float_out[0:16]
, lo contrario,arr_out[0:16] = float_out[0:16]
no funciona. Por qué no?
El atributo ctypes
de ndarray puede interactuar con el módulo ctypes, por ejemplo, ndarray.ctypes.data
es la dirección de datos de la matriz, puede convertirla en un puntero float *
y luego pasar el puntero a la función C.
import numpy as np
from cffi import FFI
ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("ccode.dll")
a = 42*np.ones(16, dtype=np.float32)
b = np.zeros_like(a)
pa = ffi.cast("float *", a.ctypes.data)
pb = ffi.cast("float *", b.ctypes.data)
C.copy(pa, pb, len(a))
print b
Para su pregunta 3:
Creo que ffi array no proporciona la información necesaria para acceder a su búfer interno. Así que muchos intentan convertirlo en un número flotante que ha fallado.
La mejor solución que puedo pensar es convertirlo primero a la lista:
float_in[0:16] = list(arr_in[0:16])
Se puede acceder a los datos en una matriz numpy a través de su interfaz de matriz:
import numpy as np
import cffi
ffi = cffi.FFI()
a = np.zeros(42)
data = a.__array_interface__[''data''][0]
cptr = ffi.cast ( "double*" , data )
ahora tiene un tipo de puntero cffi, que puede pasar a su rutina de copia. tenga en cuenta que este es un enfoque básico; Es posible que las matrices numpy no contengan sus datos en una memoria plana, por lo tanto, si su ndarray está estructurada, tendrá que considerar su forma y sus pasos. Si todo es plano, sin embargo, esto es suficiente.
Una actualización de esto: las versiones modernas de CFFI tienen ffi.from_buffer()
, que convierte cualquier objeto de búfer (como una matriz numpy) en un puntero char *
FFI. Ahora puedes hacerlo directamente:
cptr = ffi.cast("float *", ffi.from_buffer(my_np_array))
o directamente como argumentos a la llamada (el char *
se lanza automáticamente para float *
):
C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16)