schnauzbartS
schnauzbartS

Reputation: 31

swig generated python wrapper for c code - IN_ARRAY and ARGOUT from numpy.array()

I'm trying to generate a python wrapper for my C code with swig4. As I do not have any experience I'm having some issues converting a numpy-array to a c array and returning a numpy-array from a c array.

Here is my repository with all my code: https://github.com/FelixWeichselgartner/SimpleDFT

void dft(int *x, float complex *X, int N) {
    X = malloc(N * sizeof(float complex));
    float complex wExponent = -2 * I * pi / N;
    float complex temp;
    for (int l = 0; l < N; l++) {
        temp = 0 + 0 * I;
        for (int k = 0; k < N; k++) {
            temp = x[k] * cexp(wExponent * k * l) + temp;
        }
        X[l] = temp/N;
    }
}

This is what my C function looks like. int *x is a pointer to a integer array with the length N. float complex *X will be allocated by the function dft with the length of N.

/* File: dft.i */
%module dft

%{
    #define SWIG_FILE_WITH_INIT
    #include "dft.h"
%}

%include "numpy.i"

%init %{
    import_array();
%}

%apply (int * IN_ARRAY1, int DIM1) {(int *x, int N)}
%apply (float complex * ARGOUT_ARRAY1, int DIM1) {(float complex *X, int N)}

%include "dft.h"

This is what my swig file looks like. I guess the %apply part in the end is false, but I have no idea how to match this.

When I build my project by executing my build.sh file the created wrapper looks like this:

def dft(x, X, N):
    return _dft.dft(x, X, N)

Here I can see that swig did not recognize my %apply as I want it to look like this

def dft(x):
    # N is len(x)
    # do some stuff
    return X # X is a numpy.array() with len(X) == len(x)

I want to use it like this:

X = dft(x)

Obviously I get this error by executing:

File "example.py", line 12, in <module>
    X = dft(x)
TypeError: dft() missing 2 required positional arguments: 'X' and 'N'

Do I have to write my own typemap or is it possible for me to use numpy.i. And how would a typemap with an IN_ARRAY1 and ARGOUT_ARRAY1 in one function work.

Thanks for your help.

Upvotes: 1

Views: 344

Answers (1)

kwangsk
kwangsk

Reputation: 36

I was working on something similar and saw that this post had no answer. Then I realized that @schnauzbartS had already solved it and his codes are on his github (linked in the question), which is a good example.

I think a simple example people might find useful if the question is about how to typemap with IN_ARRAY1 and ARGOUT_ARRAY1 is this page:

%apply (double* IN_ARRAY1    , int DIM1) {(double* vec , int m)};
%apply (double* ARGOUT_ARRAY1, int DIM1) {(double* vec2, int n)};

Caveat: I struggled with my code a bit until I realized that IN_ARRAY from python has to be in the format of float32 not 64 (in my case it was float array). Not sure why. Another thing I found was that ARGOUT_ARRAY always needs the integer input for the size of array. So from my python end, I ended up with calling the function

myswigfunc(outarraysize,inarray,inarray2)

where outarraysize is for ARGOUT_ARRAY and the other inputs are IN_ARRAY_1 and _2 for example.

Upvotes: 1

Related Questions