Reputation: 555
My goal is to use SWIG with C and Python to create a function that takes a NumPy array as input and returns a different NumPy array. The returned array is of some unspecified size that depends on the input array. Unfortunately when I try to run my code I get an empty array returned. Here is a "minimal" example that shows the problem. I run this code via:
python setup.py build_ext --inplace
python test.py
The files of interest are copied below. Please let me know if you know how to make this code return a nonempty NumPy array. Thanks!
cancelterms.c:
#include "cancelterms.h"
void cancel(double complex* vec, int m, int n, double complex sum[])
{
// Some code that processes vec.
// This is just an example. In practice the following lines will depend on vec.
sum[0] = 1.0;
sum[1] = 2.5;
sum[2] = 3.6;
}
cancelterms.h:
#include <stdlib.h>
#include <stdio.h>
#include <complex.h>
void cancel(double complex* vec, int m, int n, double complex sum[]);
cancelterms.i:
%module cancelterms
%{
/* Put header files here or function declarations like below */
#define SWIG_FILE_WITH_INIT
#include "cancelterms.h"
%}
%include "numpy.i"
%include <complex.i>
%numpy_typemaps(double complex, NPY_CDOUBLE, int)
%init %{
import_array();
%}
%apply (double complex* INPLACE_ARRAY2, int DIM1, int DIM2) {(double complex* vec, int m, int n)}
%apply (double complex ARGOUT_ARRAY1[ANY]) {(double complex sum[])}
%include "cancelterms.h"
setup.py:
# Import necessary modules.
from distutils.core import setup, Extension
import numpy as np
try:
numpy_include = np.get_include()
except AttributeError:
numpy_include = np.get_numpy_include()
example_module = Extension('_cancelterms', sources=['cancelterms.c', 'cancelterms.i'], include_dirs = [numpy_include])
setup(name='cancelterms', ext_modules=[example_module], py_modules=["cancelterms"])
test.py:
import cancelterms
import numpy as np
a=np.array([[1.0j,2.0j,3.0j,4.0j,5.0j,6.0j],[-1.0j,-2.0j,-3.0j,6.0j,7.0j,8.0j]])
print cancelterms.cancel(a)
Unfortunately numpy.i is too large to paste here, but I use the standard numpy.i file from the numpy github repository with the small modification that I add double complex to the list of types.
Upvotes: 3
Views: 1535
Reputation: 3043
The ...[ANY]
typemaps are for arrays with hard-coded dimensions. This is stated clearly in the numpy.i docs for input arrays, but applies to the others as well.
For instance, they could be used as:
%apply (double complex ARGOUT_ARRAY1[ANY]) {(double complex sum[5])}
if your function took an array of size 5 (allocated by the caller / in the wrapper code).
The point is that SWIG has no way of knowing what size the argout array sum
will be. It is pure coincidence that your code compiles and runs at all. Have a look at the generated wrapper code (search for 'wrap_cancel'), and you will see what is going on.
There are also the following typemaps:
( DATA_TYPE* ARGOUT_ARRAY1, int DIM1 )
( DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1 )
In your case the function cancel
allocates the memory for the array sum
, assuming the caller has some way of figuring out the size. There are no predefined typemaps for this case.
This is similar to the case where the function just returns a double complex *
, and as stated in the docs for numpy.i:
If you run into a situation where a function or method is returning a pointer to an array, your best bet is to write your own version of the function to be wrapped, either with %extend for the case of class methods or %ignore and %rename for the case of functions.
Upvotes: 1