SWIG:将 2d numpy 数组传递给 C 函数 f(double a[])

Posted

技术标签:

【中文标题】SWIG:将 2d numpy 数组传递给 C 函数 f(double a[])【英文标题】:SWIG: Passing a 2d numpy array to a C function f(double a[]) 【发布时间】:2014-02-21 18:48:01 【问题描述】:

我正在使用带有 numpy.i 的 SWIG 向 python 公开一个 C 库。我试图包装的函数采用一系列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(它的名字很明显,我应该在我最初的搜索中找到它),它解决了我的潜在问题。

Edit2:我猜一个包含 2d numpy 数组并传递它的扁平视图的包装器会解决这个问题,因为 1d 数组似乎可以工作。尽管如此,对于一个简单的包装器(.i、_wrap.c、来自 swig 的 .py 和一个额外的 .py 来进一步包装 SWIG 函数以解决维度问题),最终还是需要大量文件。

【问题讨论】:

【参考方案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);

当然,您可以将这些组合在一起 - 请查看 the Docs 了解更多信息

【讨论】:

因此得出的结论是,由于基本上从不使用固定大小的数组,因此无法通过 SWIG 传递多维数组而不传递所有长度或为每个此类函数编写包装器?当我对不关心长度的可变长度一维数组使用 [ANY] 语法时(因为它通过其他方式知道),这是对 SWIG 语法的滥用吗? 据我了解 2D [ANY][ANY] 不起作用 - 可能是 1D 大小写不同(如 C 字符串)。您不能传递一个 numpy 二维数组并在 C++ 中获取一个一维数组。使用 ´´numpy.ravel()` 在 python 中展平你的数组 很好。我不明白为什么不这样做,因为二维数组和一维数组只是查看同一个平面内存块的不同方式。但我可以忍受 ravel。 如何将double* xx 用作二维数组?那不应该是double** xx吗?

以上是关于SWIG:将 2d numpy 数组传递给 C 函数 f(double a[])的主要内容,如果未能解决你的问题,请参考以下文章

将 2d numpy 数组传递给 C++ 时出现 TypeError

使用 SWIG 将 numpy 数组元素(int)传递给 c++ int

如何将复数从 python numpy 传递给 c(目前正在尝试使用 SWIG)

在 python swig 中读取 c++ 2d 数组

将简单的 java 数组传递给原始的 c-array swig

使用 SWIG 的几个 numpy 数组