简体   繁体   中英

SWIG: Passing a 2d numpy array to a C function f(double a[])

I'm using SWIG with numpy.i to expose a C library to python. The function I'm trying to wrap takes a series of double arrays as arguments:

int wcsp2s(struct wcsprm *wcs, int ncoord, int nelem, const double pixcrd[], double imgcrd[], double phi[], double theta[], double world[], int stat[]);

where some of the arrays are actually two-dimensional, with the extent given by the ncoord and nelem arguments. It's these two-dimensional arrays I'm having trouble with, since numpy.i only seems to support things of the form int n1 , int n2 , double * arr or various permutations (and my C function does not want those extra integers), or double arr[ANY][ANY] . The latter looked promising, as a multidimensional C array is just a contiguous block of memory, and so should be compatible with what the function expects. But when I try

%apply (double INPLACE_ARRAY2[ANY][ANY]) {(double imgcrd[]),(double world[])};

SWIG (or rather gcc running on SWIG's output) complains:

wcs_wrap.c:3770:7: error: expected expression before ‘,’ token

Here SWIG has generated invalid C code for those arguments.

Is what I'm trying to do here possible? I guess I could use %inplace and %rename to create a wrapper function that does take in the (unnecessary) dimensions of the arrays, and then calls the real function. Even better than the approach above with inplace arrays would be if I could return these arrays as output arguments (their dimensions are easy to calculate based on ncoord and nelem .

Or perhaps a fast (ie not the one in astLib) python interface to libwcs already exists, so I don't have to do this?

Edit: I just discovered pywcs (which has such an obvious name that i should have found it during my initial search), which solves my underlying problem.

Edit2: I guess a wrapper that takes in a 2d numpy arrays ans passes on a flattened view of it would get around the problem, since 1d arrays seem to work. Still, that ends up requiring a large amount of files for a simple wrapper (.i, _wrap.c, .py from swig and an additional .py to further wrap the SWIG functions to fix the dimensionality problem.

I am also missing a good cookbook for using numpy.i . As far as I understand, you can either:

  • pass arrays of dynamic size, where you pass the dimensions as function parameters as well. If your function behaves differently, write a wrapper (eg, IN_ARRAY2 or INPLACE_ARRAY2 ).
  • pass arrays of fixed size (eg, IN_ARRAY2 or INPLACE_ARRAY2 ).
  • When returning arrays (eg, ARGOUT_ARRAY1 ), you have to pass the size when calling it from python. In the example below, you would write oo = func3(20) . The reason seems to be since python needs to allocate the memory, it needs to know about the size,

For example, your .i -file could look like his:

...
%include "numpy.i"

%init %{
  import_array();
%}

// Pass  array of dynamic size:
%apply (double* INPLACE_ARRAY2, int DIM1, int DIM2) {(double *xx, int xx_n, int xx_m)};
void func1(double *xx,int xx_n, int xx_m);

// Pass array of fixed size:
%apply (int *INPLACE_ARRAY2[ANY][ANY]) { (double yy[4][4]) };
void func2(double yy[4][4]);

// Return a dynamic 1D array:
%apply (double* ARGOUT_ARRAY1, int DIM1) {(double* out, int out_n)}
void func3(double* out, int out_n);

Of course you can combine these - check the Docs for more information

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM