2013-04-29 3 views
21

나는 Python과 Numpy를 사용하여 오디오 알고리즘을 개발 중이다. 이제 알고리즘을 C로 구현하여 알고리즘 속도를 높이고 싶습니다. 과거에는 I have done this using cython이었습니다. 이제 새로운 cffi을 사용하여 동일한 작업을 수행하려고합니다. Numpy 배열을 cffi 함수로 전달하는 방법과이를 다시 얻는 방법은 무엇입니까?

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

가 지금은 두 NumPy와 배열을 생성하고 그가이 기능에 의해 처리 될 갖고 싶어 :

는 테스트를 위해, 나는 사소한 C의 기능을 썼다.
  1. 직접 복사하지 않고 NumPy와 배열의 기본 부동 소수점 버퍼에 액세스 할 수있는 방법이 있나요 : 나는이 코드를 개선하고자하는, 그러나

    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) 
    

    : 나는 그렇게 할 수있는 방법을 알아 냈어 그들?

  2. ffi.buffer은 C 배열의 내용으로 Numpy 배열로 신속하게 변환하는 데 매우 편리합니다. 개별 요소를 복사하지 않고도 numpy 배열을 C 배열로 신속하게 변환 할 수있는 동일한 방법이 있습니까?
  3. 일부 응용 프로그램의 경우 편리한 데이터 액세스 방법은 float_in[0:16] = arr_in[0:16]입니다. 반대로, arr_out[0:16] = float_out[0:16]하지만 작동하지 않습니다. 왜 안돼? ndarray의

답변

19

ctypes 속성이하는 ctypes 모듈과 상호 작용, 예를 들면, ndarray.ctypes.data 배열의 데이터 어드레스, 당신은 float * 포인터 을 캐스팅하고 C 함수 포인터를 통과 할 수있다. 질문 3

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 

:

나는 FFI 배열이 내부 버퍼의 액세스하는 데 필요한 정보를 NumPy와 제공하지 않습니다 생각합니다. 그래서 numpy는 실패한 float 번호로 변환하려고 시도합니다.

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

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

지금 당신이 cffi이 : 그것은 배열 인터페이스의를 통해

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

데이터를 NumPy와 배열에 액세스 할 수 있습니다 내가 할 수있는 생각

가장 좋은 방법은 첫 번째 목록로 변환입니다 포인터 유형. 복사 루틴에 전달할 수 있습니다. 이것은 기본적인 접근 방법입니다. numpy 배열은 평면 메모리에 데이터를 포함 할 수 없으므로 ndarray가 구조화되어 있으면 모양과 스트라이드를 고려해야합니다. 그것이 전부 편평한 경우에, 이것은, 충분하다.

+0

한 진보를 언급에 대해 – Matthias

6

업데이트 : CFFI의 최신 버전은 ffi.from_buffer()이며, 이는 버퍼 객체 (예 : numpy 배열)를 char * FFI 포인터로 바꿉니다. 이제 직접 수행 할 수 있습니다 직접

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

또는 호출에 인수합니다 (char *float *에 자동으로 주조되어있다)과 같이

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16) 
관련 문제