在 Swig 中通过 ref 返回动态数组

Posted

技术标签:

【中文标题】在 Swig 中通过 ref 返回动态数组【英文标题】:Return dynamic arrays by ref in Swig 【发布时间】:2016-07-06 10:48:33 【问题描述】:

我正在使用 swig 在 c++ 中包装一些代码以在 Python 中使用。 在对输入数组进行一些计算后,我有一个获取数组并返回 2 个动态数组(该函数通过 ref 获取它们)的函数。 我的问题是输出数组的大小未指定,因为大小取决于输入数组。 我的功能看起来像:

void arrayManipulate(int* inArray, int inLen, int resolution, int* &outArray1, int &outLen1, int* &outArray2, int &outLen2)

我使用 numpy.i 将输入数组转换为 numpy 数组。 但是如果我想使用 numpy 来返回带有 ARGOUT 的数组,它就不起作用,因为它假设输出数组的大小是已知的。

模块.i:

%module minimal
%
#include "minimal.h"
#include "numpy/arrayobject.h"
%

%include numpy.i
%init %
inport_array();
%
%apply (int* INARRAY1, int DIM1) (int* inArray, int inLen)
%apply (int* ARGOUT_ARRAY1, int DIM1) (int* &outArray1, int &outLen1), (int* &outArray2, int &outLen2)
%include "minimal.h"

如果我尝试编译它,我会收到以下错误:

File minimal_wrap.cxx: IntelliSense: a value of type "int" could not be assigned to entity od type "int *"
File minimal_wrap.cxx: IntelliSense: a value of type "int *" could not be assigned to entity od type "int **"

如果我从 minimum.i 和 minimum.h(从函数)中删除所有“&”符号,它会编译,但 python 除外以给出输出数组的维度:

TypeError: arrayManipulate takes exactly 4 arguments (2 given)

我想在 python 中使用它,例如:

import minimal
import numpy as np
arr1, arr2 = minimal.arrayManipulate(np.asarray([1,2,3]),100)

我怎样才能让它工作?

【问题讨论】:

看来您需要ARGOUTVIEW_ARRAY1 类型映射。 将您的签名更改为(int* inArray, int inLen, int resolution, int** outArray1, int* outLen1, int** outArray2, int *outLen2) 并使用ARGOUTVIEW_ARRAY1 甚至更好的ARGOUTVIEWM_ARRAY1。返回一个带有托管数据的 NumPy 数组。 【参考方案1】:

这里有一个答案,它使用双指针而不是 *&。你可以制作一个简单的包装函数来支持这个原型

请注意,返回的数组是分配的,并且类型映射会生成一个代理,以确保在 Python 中删除数组时删除。它们是受管理的

头文件(test.h):

#pragma once

void fun(int* inArray, int inLen, int resolution,
     int** outArray1, int* outLen1,
     int** outArray2, int* outLen2);

源文件(test.cpp):

#include "test.h"
#include <malloc.h>

void fun(int* inArray, int inLen, int resolution, 
     int** outArray1, int* outLen1,
     int** outArray2, int* outLen2) 

  int _outLen1 = resolution*inLen;
  int _outLen2 = resolution*inLen;
  int* _outArray1 = (int*)malloc(_outLen1*sizeof(int));
  int* _outArray2 = (int*)malloc(_outLen2*sizeof(int));

  for (int i = 0 ; i < inLen ; i++) 
    for (int j = 0 ; j < resolution ; j++) 
      _outArray1[i*resolution+j] = resolution*inArray[i];
      _outArray2[i*resolution+j] = resolution*inArray[i];
    
  

  // Assign outputs
  *outLen1 = _outLen1;
  *outLen2 = _outLen2;
  *outArray1 = _outArray1;
  *outArray2 = _outArray2;

接口定义文件(test.i)

%module example
%
  #define SWIG_FILE_WITH_INIT
  #include "test.h"
%

%include "numpy.i"

%init
%
  import_array();
%

%apply (int* IN_ARRAY1, int DIM1) (int* inArray, int inLen)

%apply (int** ARGOUTVIEWM_ARRAY1, int* DIM1) (int** outArray1, int* outLen1)
%apply (int** ARGOUTVIEWM_ARRAY1, int* DIM1) (int** outArray2, int* outLen2)

%include "test.h"

在 Python 中

import numpy as np
import example
a = np.ones(27,dtype=np.int32)
h = example.fun(a,2) # h contains the two outputs

为了支持例如size_t,在 numpy.i 中搜索此部分

%numpy_typemaps(unsigned long long, NPY_ULONGLONG, int)
%numpy_typemaps(float             , NPY_FLOAT    , int)
%numpy_typemaps(double            , NPY_DOUBLE   , int)

并添加以下内容

%numpy_typemaps(signed char       , NPY_BYTE     , size_t)
%numpy_typemaps(unsigned char     , NPY_UBYTE    , size_t)
%numpy_typemaps(short             , NPY_SHORT    , size_t)
%numpy_typemaps(unsigned short    , NPY_USHORT   , size_t)
%numpy_typemaps(int               , NPY_INT      , size_t)
%numpy_typemaps(unsigned int      , NPY_UINT     , size_t)
%numpy_typemaps(long              , NPY_LONG     , size_t)
%numpy_typemaps(unsigned long     , NPY_ULONG    , size_t)
%numpy_typemaps(long long         , NPY_LONGLONG , size_t)
%numpy_typemaps(unsigned long long, NPY_ULONGLONG, size_t)
%numpy_typemaps(float             , NPY_FLOAT    , size_t)
%numpy_typemaps(double            , NPY_DOUBLE   , size_t)

这添加了更多类型映射以支持使用 size_t 而不是 int 进行索引。

【讨论】:

这对我有用。谢谢你。如果我希望维度参数 (outLen1) 的类型与大型数组的 int - long 或 size_t 不同,我该怎么做? 在numpy.i中添加几行。所有类型映射都是使用宏创建的。查看文件

以上是关于在 Swig 中通过 ref 返回动态数组的主要内容,如果未能解决你的问题,请参考以下文章

通过动态分配创建数组后,在C中通过realloc改变内存大小时出现问题

带有 SWIG 未知长度数组的 NumPy C 扩展

动态类对象 动态数组

动态数组作为纹理GLSL

在 scrollIntoView 的动态长度数组中使用 Refs

Echarts通过Ajax动态获取后端数据(饼状图,柱状图)