【问题标题】:Manipulate Numpy array inside C with SWIG使用 SWIG 在 C 中操作 Numpy 数组
【发布时间】:2018-09-06 13:04:37
【问题描述】:

尝试将 Numpy 数组传递给 C 方法并在那里修改其内容,这是否可能?我们的想法是尽可能少地复制数据(速度和内存原因)。

目前正在尝试这样的事情:

test.c

void testMethod(int** values) {
  // code
  *values = other_pointer;
}

test.i

/* File : test.i */
%module test
%{
  #define SWIG_FILE_WITH_INIT
%}
%include "numpy.i"

%init %{
    import_array();
%}

%{
extern void testMethod(int** values);
%}

%apply (int **ARGOUT_ARRAY1) {int **values};
extern void testMethod(int** values);

我修改了 numpy.i 文件添加:

%typemap(in,
         fragment="NumPy_Fragments")
  (DATA_TYPE **ARGOUT_ARRAY1)
  (PyArrayObject* array=NULL, int is_new_object=0, DATA_TYPE* temp=NULL)
{
    array = obj_to_array_contiguous_allow_conversion($input,
                                                   DATA_TYPECODE,
                                                   &is_new_object);
    temp = (DATA_TYPE*) array_data(array);
    $1 = &temp;
}
%typemap(argout)
  (DATA_TYPE** ARGOUT_ARRAY1)
{
    $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum);
}

运行它:

input = numpy.array([1,2,3])
test.testMethod(input)

有效,即它可以编译,我可以在 C 中打印数组的内容,但输入的内容保持不变。

【问题讨论】:

    标签: python c numpy swig


    【解决方案1】:

    要回答我自己的问题,一种有点老套的方法是将类型映射更改为这样的:

    %typemap(in,
             fragment="NumPy_Fragments")
      (DATA_TYPE **ARGOUT_ARRAY1)
      (PyArrayObject* array=NULL, int is_new_object=0, PyArrayObject_fields* temp=NULL)
    {
        array = obj_to_array_contiguous_allow_conversion($input,
                                                       DATA_TYPECODE,
                                                       &is_new_object);
        if (!array) SWIG_fail;
        temp = (PyArrayObject_fields*)array;
        $1 = (DATA_TYPE**) &temp->data;
    }
    %typemap(argout)
      (DATA_TYPE** ARGOUT_ARRAY1)
    {
        $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum);
    }
    

    @Edit:经过一些测试后,如果我们重用 Python input 数组,上述方法会起作用,但会产生 Segmentation Fault 异常。解决方法是将映射类型从ARGOUT_ARRAY1更改为INPLACE_ARRAY1

    【讨论】:

    • 使用INPLACE_ARRAYARGOUTVIEW_ARRAY 的类型映射在numpy.i 标头中定义。它们都“通过引用”工作。
    • @JensMunk 但是 1) 他们需要 C 方法签名来接受 data_type* arg 而不是 data_type** arg 2) 需要方法签名来获取指针和长度。正确的?或者有不同的使用方式吗?
    • 单个指针足以修改输入数组的内容,INPLACE_ARRAY。对于输出,ARGOUTVIEW_ARRAY 提供了一个双指针,python 数组正在引用驻留在 C 代码中的数组。如果数组在 C 中更新,驻留在 Python 中的 numpy 数组也会更新。
    • 我明白了,ARGOUTVIEW_ARRAY 正在做的事情与我写的非常相似,但他们不是仍然要求 C 方法采用void method (int** array, int size) 的形式吗?我使用的方法不采用size,我无法修改它们。这就是我自己编写没有维度参数的映射的部分原因。
    • 是和不是。如果你在 Python 中创建一个 NumPy 数组,它总是有一个大小,如果没有这个大小,C 程序就无法判断它是否超出范围。您可以编写一个带有额外参数的包装器,该参数被硬编码为大小并使用 SWIG 来包装包装器。我通常更喜欢在C端使用ARGOUTVIEWM_ARRAYmalloc。这将创建一个托管数组,当在 Python 中清除 NumPy 数组时,该数组会被正确清除
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多