SWIG:将一个二维numpy数组传递给C函数f(double a [])

3

我正在使用SWIG和numpy.i将一个C库暴露给Python。我尝试包装的函数需要一系列double数组作为参数:

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

一些数组实际上是二维的,其范围由ncoordnelem参数给出。正是这些二维数组让我感到困扰,因为numpy.i似乎只支持形式为int n1int n2double * arr或其各种排列方式(而我的C函数不想要那些额外的整数),或者double arr [ANY] [ANY]。后者看起来很有前途,因为多维C数组只是一块连续的内存块,所以应该与函数期望的兼容。但是当我尝试时:

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

SWIG(或者更准确地说,运行在 SWIG 输出上的 gcc)报错:

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

在这里,SWIG针对这些参数生成了无效的C代码。

我想做的事情是否可行?我猜我可以使用%inplace和%rename创建一个包装函数,该函数会接受(不必要的)数组维度,然后调用真实函数。比上面使用就地数组的方法更好的是,如果我可以将这些数组作为输出参数返回(它们的维数很容易根据ncoordnelem计算)。

或者,已经存在快速(即不是astLib中的那个)python接口到libwcs,因此我不必这样做吗?

编辑:我刚刚发现pywcs(它有一个如此明显的名称,以至于我应该在最初的搜索中找到它),它解决了我的根本问题。

编辑2:我猜,一个接受2D numpy数组并传递其扁平视图的包装器将绕过问题,因为1D数组似乎起作用。尽管如此,这最终需要大量文件来进行简单的包装器(.i、_wrap.c、来自swig的.py和另一个.py,以进一步包装SWIG函数以解决维度问题)。

1个回答

1

我还缺少一本关于使用 numpy.i 的好的教程。据我了解,您可以选择以下两种方式:

  • 传递动态大小的数组,其中您将尺寸作为函数参数进行传递。如果您的函数行为不同,请编写一个包装器(例如IN_ARRAY2INPLACE_ARRAY2)。
  • 传递固定大小的数组(例如IN_ARRAY2INPLACE_ARRAY2)。
  • 返回数组时(例如ARGOUT_ARRAY1),您必须在从Python中调用它时传递大小。在下面的示例中,您将编写oo = func3(20)。原因似乎是因为Python需要分配内存,所以它需要知道大小。

例如,您的.i文件可能如下所示:

...
%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);

当然,您可以将它们组合起来 - 请查看文档以获取更多信息。

所以结论是,由于固定大小的数组基本上不会被使用,因此没有办法通过SWIG传递多维数组,除非同时传递所有长度或编写每个这样函数的包装器?当我在变长1D数组中使用[ANY]语法表示我不关心长度(因为它可以通过其他方式得知)时,这是否是对SWIG语法的滥用? - amaurea
据我所知,2D [ANY][ANY] 不起作用 - 可能 1D 情况不同(如 C 字符串)。你不能传递一个 numpy 2D 数组并在 C++ 中获得一个 1D 数组。在 Python 中使用 ´´numpy.ravel()`` 来展平你的数组。 - Dietrich
非常好。我不明白为什么不行,因为二维数组和一维数组只是查看相同平面内存块的不同方式。但我可以接受ravel。 - amaurea
double* xx 怎么能用作二维数组呢?难道不应该是 double** xx 吗? - Schroeder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接