SWIG를 사용하여 numpy 배열을 vector <int> & (reference)로 변환하는 방법


10

내 목표:

파이썬에서 3 개의 numpy 배열을 생성 한 다음 (두 개는 특정 값으로 초기화됩니다) 세 가지를 모두 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"

메이크 파일

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를 얻을 수 없습니다.

한 가지 대안은 std::span클래스 템플릿 (C ++ 20에 도입) 또는 이와 유사한 것을 사용하는 것입니다.span 라이브러리에 정의 된 클래스 템플릿을 사용하는 것입니다.

를 만들면 배열 기존 데이터를 std::span<int> 수 있고 여러 편리한 멤버 함수 (예 : 반복자 ,,numpyoperator[]front()back() C ++에서, 등).

범위를 만들면 numpy 배열에서 데이터를 복사 하지 않습니다 .


(내 자신의 클래스를 구축하는 것 외에) 최고의 대안으로 보이는 것을 제공해 주셔서 감사합니다.
Otherness

복사하지 않고 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 라이브러리를 참조 할 수 있습니다.

파이썬 특정 : numpy array <-> C ++ 포인터 인터페이스 (벡터)

Github 페이지 에서 코드를 볼 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.