Reputation: 10744
I have code in C
, which I would like to use in python
, I used SWIG to wrap the C-code, and got successfully a python module imported in my python code.
Now I have the following code:
import flame
import numpy as np
data = np.random.rand(3,2).astype(np.float32, copy=False)
N = 3
M = 2
print data
flameobject = flame.Flame_New()
flame.Flame_SetDataMatrix( flameobject, data, N, M, 0 )
and this gives error:
TypeError: in method 'Flame_SetDataMatrix', argument 2 of type 'float *[]'
I understand that I should pass a float array pointer
to the method, but how can I convert my Numpy multi-dimensional array into the correct type?
Upvotes: 5
Views: 2308
Reputation: 10744
Ok for everyone that might face the same problem as I did, here is how I finally solved it.
First I changed the header in the .h
file and the .c
file of the function from
void Flame_SetDataMatrix( Flame *self, float *data[], int N, int M, int T );
to
void Flame_SetDataMatrix( Flame *self, float *data, int N, int M, int T );
After that, I added
%apply (float* IN_ARRAY2, int DIM1, int DIM2) {
(float *data, int N, int M)
};
To the interface file (flame.i
). This makes it possible to call the function in Python like this: flame.Flame_SetDataMatrix( flameobject, data, T)
, where data is a numpy array with two dimensions.
The "problem" now is that the array that arrives in the C function is in the wrong format, because we want a double array (which in this case is a pointer to a pointer to a float).
The solution is to convert this array, which is wrapped in a single dimension, to reconstruct the double array in the c code like this:
//n = number of rows, m= number of columns columns
void Flame_SetDataMatrix( Flame *self, float *data, int n, int m, int dt )
{
//convert data to float** for later use
int i=0, j=0;
float ** data2 = (float**) calloc( n, sizeof(float*) );
for (i=0; i<n; i++){
data2[i] = calloc( m, sizeof(float) );
for (j=0; j<m; j++){
//the data is in a single array row after row, so i*columns+j
data2[i][j] = data[i * m + j];
}
}
In the end I could use the same "trick" to also get a two dimensional float array back into a numpy array, which I did have to reschape but in numpy that is easy.
Hope it will help someone.
Upvotes: 1
Reputation: 3043
There is SciPy documentation on exactly this: How to pass numpy arrays to C code via SWIG (and vice versa). Have a look here.
Basically, there is a swig interface file numpy.i
that you use in the following way. In your swig interface file you include:
%{
#define SWIG_FILE_WITH_INIT
%}
%include "numpy.i"
%init %{
import_array();
%}
and then add in your interface file, before mentioning your C functions:
%apply ( float* IN_ARRAY2, int DIM1, int DIM2 ) {
(float* your_array_parameter_name, int N_parameter_name, int M_parameter_name)
};
This works for ordinary C float
arrays. I am not quite sure what a float* []
is. You may need to write your own typemaps for this, for which you can use the utility macros provided by numpy.i
. But it is all explained in the numpy.i documentation mentioned above, or in the relevant swig typemap docs
Upvotes: 1