2013-04-29 10 views
21

Opracowuję algorytm audio za pomocą Pythona i Numpy. Teraz chcę przyspieszyć ten algorytm, wprowadzając jego część w C. W przeszłości, I have done this using cython. Teraz chcę zrobić to samo, używając nowego cffi.Jak przekazać tablicę Numpy do funkcji cffi i jak ją odzyskać?

Dla celów testowych napisałem trywialny C funkcję:

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

Teraz chcę utworzyć dwa numpy tablice i mają te są przetwarzane przez tę funkcję. ja wymyśliliśmy sposób, aby to zrobić:

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) 

Jednak chciałbym, aby poprawić ten kod:

  1. Czy istnieje sposób, aby uzyskać bezpośredni dostęp do podstawowych buforów obrocie tablic numpy bez kopiowania im?
  2. ffi.buffer jest bardzo wygodny do szybkiego przekształcenia zawartości tablicy C w tablicę Numpy. Czy istnieje równoważny sposób szybkiego przekształcenia tablicy numpy w tablicę C bez kopiowania poszczególnych elementów?
  3. Dla niektórych aplikacji wygodnym sposobem uzyskania dostępu do danych jest float_in[0:16] = arr_in[0:16]. Przeciwnie, arr_out[0:16] = float_out[0:16] nie działa jednak. Dlaczego nie?

Odpowiedz

19

Cechą ndarray ctypes może wchodzić w interakcje z modułem ctypes np ndarray.ctypes.data jest adres danych z tablicy, można oddać go do float * wskaźnik, a następnie przekazać wskaźnik do funkcji 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 

Dla Pytanie 3:

myślę tablica FFI nie przewiduje numpy niezbędnych informacji, aby uzyskać dostęp to bufor wewnętrzny. Tak numpy spróbuj przekonwertować go do liczby zmiennoprzecinkowej, która nie powiodła się.

Najlepszym rozwiązaniem mogę myśli jest przekonwertować go do listy pierwszy:

float_in[0:16] = list(arr_in[0:16]) 
12

dane w numpy tablicy można uzyskać poprzez jego interfejs tablica:

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

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

teraz masz cffi typ wskaźnika, który można przekazać do procedury kopiowania. zauważ, że jest to podstawowe podejście; Numpy tablice mogą nie zawierać danych w pamięci płaskiej, więc jeśli twój ndarray jest zbudowany, będziesz musiał wziąć pod uwagę jego kształt i kroki. Jeśli wszystko jest w porządku, to wystarczy.

+0

+1 dla wspomnieć postępy – Matthias

6

Aktualizacja do tego: nowoczesne wersje CFFI mają ffi.from_buffer(), która zamienia dowolny obiekt bufora (np. Tablicę numpy) na wskaźnik FFI char *. Teraz można zrobić bezpośrednio:

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

lub bezpośrednio jako argumenty do rozmowy (char * jest automatycznie oddanych do float *):

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16) 
Powiązane problemy