SWIGでnumpy配列をvector <int>&(参照)に変換する方法


10

私の目標:

Pythonで3つのnumpy配列を作成し(そのうち2つは特定の値で初期化されます)、3つすべてをswigを介して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"

Makefile

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ディレクティブをすべて試しましたが、機能しませんでした。

含めるべきではないタイプマップはありますか?


3
それは可能ではありません。C ++では、実際に存在するオブジェクトへの参照しか作成できません。ただし、numpy配列にはは含まれませんstd::vector
pschill

回答:


3

@pschillに同意します。データをコピーせずにstd :: vectorを取得することはできません。

1つの代替方法は、std::spanクラステンプレート(C ++ 20で導入)またはspanライブラリで定義された同様のクラステンプレートを使用することです。

作成は、std::span<int>提供するのビューの既存のデータnumpy配列を、そして提供する多くの便利なメンバ関数(例えばoperator[]、イテレータ、front()back()C ++で、など)。

スパンを作成して、numpy配列からデータがコピーされることはありません


(自分のクラスを構築することを除いて)私が最良の選択肢であると思うものを提供してくれてありがとう。
その他

コピーせずにC ++関数でstd :: vectorを本当に使用(および変更)したい場合、どのような代替手段がありますか?std :: vectorへの生のポインタ?shared_ptrをstd :: vectorに?
Gabriel Devillers

@GabrielDevillers、私はあなたの質問を理解していれば、ベクターが存在し、あなたがあなたの関数でそれを変更したい場合は、私が使用することをお勧めします参照ベクトルた: std::vector<T>& v
NicholasM

@NicholasM私はSWIGを使用してラップしたいAPIを意味しました。SWIGがベクターへの非const参照をラップできないことを理解しているので、私は尋ねています。
Gabriel Devillers

あ、ごめんなさい。特定のケースに焦点を当てた新しい質問を作成することをお勧めします。
NicholasM

0

Facebook faissライブラリを参照すると、より洗練された方法で目的の機能を実現できます。

Python固有:numpy配列<-> C ++ポインターインターフェイス(ベクター)

Githubページでコードを確認できます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.