如何使用 SWIG 将 numpy 数组转换为 vector<int>&(参考)

Posted

技术标签:

【中文标题】如何使用 SWIG 将 numpy 数组转换为 vector<int>&(参考)【英文标题】:How to convert numpy arrays to vector<int>& (reference) with SWIG 【发布时间】:2019-10-21 22:23:58 【问题描述】:

我的目标:

在 python 中创建 3 个 numpy 数组(其中 2 个将使用特定值初始化),然后通过 swig 将所有三个数组作为向量 references 发送到 c++ 函数中(这是为了避免复制数据并降低效率)。一旦进入 c++ 函数,添加 2 个数组并将它们的总和放入第 3 个数组。

vec_ref.h

#include <vector>
#include <iostream>

void add_vec_ref(std::vector<int>& dst, std::vector<int>& src1, std::vector<int>& src2);

vec_ref.cpp

#include "vec_ref.h"
#include <cstring> // need for size_t
#include <cassert>

void add_vec_ref(std::vector<int>& dst, std::vector<int>& src1, std::vector<int>& src2) 
    std::cout << "inside add_vec_ref" << std::endl;
    assert(src1.size() == src2.size());
    dst.resize(src1.size());

    for (size_t i = 0; i < src1.size(); i++) 
        dst[i] = src1[i] + src2[i];
    

vec_ref.i

%module vec_ref
%
    #define SWIG_FILE_WITH_INIT
    #include "vec_ref.h"
%

%include "numpy.i"
%init %
import_array();
%

%include "std_vector.i"
%template(vecInt) std::vector<int>;
// %template(vecIntRef) std::vector<int> &; 

// %apply (std::vector<int> * INPLACE_ARRAY1, int DIM1) (std::vector<int> * dst, int a),(std::vector<int> * src1, int b),(std::vector<int> * src2, int c);
// %apply (std::vector<int> * INPLACE_ARRAY1) (std::vector<int> * dst),(std::vector<int> * src1),(std::vector<int> * src2);
// %apply (std::vector<int> & INPLACE_ARRAY1) (std::vector<int> & dst),(std::vector<int> & src1),(std::vector<int> & src2);
// %apply (std::vector<int> & INPLACE_ARRAY1, int DIM1) (std::vector<int> & dst, int a),(std::vector<int> & src1, int b),(std::vector<int> & src2, int c);

%include "vec_ref.h"

生成文件

all:
    rm -f *.so *.o *_wrap.* *.pyc *.gch vec_ref.py
    swig -c++ -python vec_ref.i
    g++ -O0 -g3 -fpic -c vec_ref_wrap.cxx vec_ref.h vec_ref.cpp -I/home/lmckeereid/tools/anaconda3/pkgs/python-3.7.3-h0371630_0/include/python3.7m/
    g++ -O0 -g3 -shared vec_ref_wrap.o vec_ref.o -o _vec_ref.so

tester.py

import vec_ref as vec
import numpy as np

a = np.array([1,2,3], dtype=np.intc)
b = np.array([4,5,6], dtype=np.intc)
c = np.zeros(len(a), dtype=np.intc)

print('---Before---\na:', a)
print('b:', b)
print('c:', c)

vec.add_vec_ref(c,a,b)

print('---After---\na:', a)
print('b:', b)
print('c:', c)

输出:

---Before---
a: [1 2 3]
b: [4 5 6]
c: [0 0 0]
Traceback (most recent call last):
  File "tester.py", line 12, in <module>
    vec.add_vec_ref(c,a,b)
TypeError: in method 'add_vec_ref', argument 1 of type 'std::vector< int,std::allocator< int > > &'

我已经尝试了在 vec_ref.i 中找到的所有已注释掉的 %apply 和 %template 指令,但它们都不起作用。

是否有一些我不应该包含的类型映射?

【问题讨论】:

这是不可能的。在 C++ 中,您只能创建对实际存在的对象的引用。但是,numpy 数组不包含std::vector 相关:***.com/questions/51466189/… 【参考方案1】:

我同意@pschill 的观点:不复制数据就无法获得 std::vector。

另一种方法是使用std::span class template(在C++20 中引入),或在库中定义的类似span 类模板。

创建std::span&lt;int&gt; 将提供numpy 数组中现有数据的视图,并提供many convenient member functions(例如operator[]、迭代器、front()back()等)在 C++ 中。

创建跨度将从 numpy 数组中复制数据。

【讨论】:

感谢您提供我认为最好的选择(除了建立我自己的课程)。 如果我真的想在我的 C++ 函数中使用(和修改)std::vector 而不进行复制,我还有什么选择?指向 std::vector 的原始指针? shared_ptr 到 std::vector ? @GabrielDevillers,如果我理解你的问题,如果一个向量存在并且你想在你的函数中修改它,我建议对向量使用 reference:@987654330 @ @NicholasM 我的意思是在我想使用 SWIG 包装的 API 中。我问是因为我知道 SWIG 不能包装对向量的非常量引用。 哦,对不起。我建议您针对您的具体案例创建一个新问题。【参考方案2】:

你可以参考Facebook faiss库,它实现了你想要实现的,更优雅的方式来自:

Python 特定:numpy 数组 C++ 指针接口(向量)

您可以在其Github page 上查看代码。

【讨论】:

以上是关于如何使用 SWIG 将 numpy 数组转换为 vector<int>&(参考)的主要内容,如果未能解决你的问题,请参考以下文章

将 ctypes int** 转换为 numpy 二维数组

将 C/C++ 向量快速转换为 Numpy 数组

使用 SWIG 将 C++ <vector> 包装为 python NumPy 数组

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

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

使用 SWIG 的几个 numpy 数组