Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a Numpy array into a cffi function and how to get one back out?

I am developing an audio algorithm using Python and Numpy. Now I want to speed up that algorithm by implementing a part of it in C. In the past, I have done this using cython. Now I want to do the same thing using the new cffi.

For testing purposes, I wrote a trivial C function:

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

Now I want to create two numpy arrays and have those be processed by this function. I figured out a way to do that:

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) 

However, I would like to improve this code:

  1. Is there a way to directly access the underlying float buffers of the numpy arrays without copying them?
  2. ffi.buffer is very convenient for quickly converting to contents of a C array to a Numpy array. Is there an equivalent way for quickly converting a numpy array into a C array without copying the individual elements?
  3. For some applications, float_in[0:16] = arr_in[0:16] is a convenient way of accessing data. The opposite, arr_out[0:16] = float_out[0:16] does not work however. Why not?
like image 452
bastibe Avatar asked Apr 29 '13 10:04

bastibe


People also ask

How do I save a NumPy array to machine learning?

You can save your NumPy arrays to CSV files using the savetxt() function. This function takes a filename and array as arguments and saves the array into CSV format. You must also specify the delimiter; this is the character used to separate each variable in the file, most commonly a comma.

How do I save a NumPy array in .NPY format?

Save in npy format using Numpy save() To save this array to . npy file we will use the . save() method from Numpy. Running this line of code will save your array to a binary file with the name 'ask_python.


2 Answers

The ctypes attribute of ndarray can interact with the ctypes module, for example, ndarray.ctypes.data is the data address of the array, you can cast it to a float * pointer, and then pass the pointer to the C function.

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 

For your question 3:

I think ffi array doesn't provide numpy the necessary information to access it's inner buffer. So numpy try to convert it to a float number which failed.

The best solution I can thinks is convert it to list first:

float_in[0:16] = list(arr_in[0:16]) 
like image 108
HYRY Avatar answered Sep 19 '22 11:09

HYRY


An update to this: modern versions of CFFI have ffi.from_buffer(), which turns any buffer object (like a numpy array) to a char * FFI pointer. You can now do directly:

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

or directly as arguments to the call (the char * is casted automatically to float *):

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16) 
like image 28
Armin Rigo Avatar answered Sep 18 '22 11:09

Armin Rigo