Niki van Stein
Niki van Stein

Reputation: 10744

How to convert numpy ndarray to C float *[]

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

Answers (2)

Niki van Stein
Niki van Stein

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

m7thon
m7thon

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

Related Questions