Comment passer un numpy array dans une fonction cffi et comment en faire sortir un?

je développe un algorithme audio utilisant Python et Numpy. Maintenant je veux accélérer cet algorithme en implémentant une partie en C. dans le passé,j'ai fait ceci à l'aide de cython. Maintenant je veux faire la même chose en utilisant le nouveau cffi.

a des fins de test, j'ai écrit une fonction C triviale:

void copy(float *in, float *out, int len) {
    for (int i=0; i<len; i++) {
        out[i] = in[i];
    }
}

maintenant je veux créer deux tableaux vides et les faire traiter par cette fonction. J'ai trouvé une façon de le faire que:

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)

Cependant, j'aimerais améliorer ce code:

  1. Est-il possible d'accéder directement au sous-jacente float tampons des tableaux numpy sans les copier?
  2. ffi.buffer est très pratique pour convertir rapidement au contenu d'un C tableau d'un tableau Numpy. Existe-t-il un moyen équivalent pour convertir rapidement un tableau numpy en un tableau C sans copier les éléments individuels?
  3. Pour certaines applications, float_in[0:16] = arr_in[0:16] est un moyen pratique d'accéder à des données. À l'opposé, arr_out[0:16] = float_out[0:16] ne fonctionne pas. Pourquoi pas?
22
demandé sur bastibe 2013-04-29 14:22:26

3 réponses

ctypes l'attribut de ndarray peut interagir avec le module ctypes, par exemple, ndarray.ctypes.data est l'adresse des données du tableau, vous pouvez le convertir en un float * pointeur, puis passez le pointeur à la fonction 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

pour votre question 3:

je pense que ffi tableau ne fournit pas de numpy les informations nécessaires pour accéder à l'intérieur de la mémoire tampon. Alors num PY essayer de le convertir en un nombre flottant qui a échoué.

la meilleure solution que je peux penser est Convertir à la liste de la première:

float_in[0:16] = list(arr_in[0:16])
20
répondu HYRY 2013-04-30 00:26:00

les données d'un numpy array sont accessibles via son interface array:

import numpy as np
import cffi
ffi = cffi.FFI()

a = np.zeros(42)
data = a.__array_interface__['data'][0]
cptr = ffi.cast ( "double*" , data )

maintenant vous avez un type de pointeur cffi, que vous pouvez passer à votre routine de copie. notez que c'est une approche de base; les tableaux numpy peuvent ne pas contenir leurs données dans la mémoire plate, donc si votre ndarray est structuré, vous devrez considérer sa forme et ses pas. Mais si tout est plat, c'est suffisant.

13
répondu Kay F. Jahnke 2013-05-06 07:13:26

une mise à jour de ceci: les versions modernes de CFFI ont ffi.from_buffer(), qui transforme n'importe quel objet buffer (comme un tableau de numpy) en char * pointeur FFI. Vous pouvez maintenant faire directement:

cptr = ffi.cast("float *", ffi.from_buffer(my_np_array))

ou directement comme argument à l'appel (le char * est joué automatiquement float *):

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16)
7
répondu Armin Rigo 2016-08-31 07:33:06