Bagaimana mengkonversi array numpy ke vektor <int> & (referensi) dengan SWIG

10

Tujuanku:

Buat 3 numpy array dalam python (2 dari mereka akan diinisialisasi dengan nilai-nilai spesifik), lalu kirim ketiganya melalui swig ke fungsi c ++ sebagai referensi vektor (ini untuk menghindari penyalinan data dan kehilangan efisiensi). Setelah berada di fungsi c ++, tambahkan 2 array dan masukkan jumlahnya dalam array ke-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)

Keluaran:

---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 > > &'

Saya telah mencoba semua komentar terapkan% berlaku dan arahan template% ditemukan di vec_ref.i, tetapi mereka tidak berhasil.

Apakah ada beberapa typemaps yang harus saya masukkan dan bukan saya?

Keberbedaan
sumber
3
Itu tidak mungkin. Di C ++, Anda hanya bisa membuat referensi ke objek yang benar-benar ada. Namun, array numpy tidak mengandung a std::vector.
pschill
Terkait: stackoverflow.com/questions/51466189/…
Gabriel Devillers

Jawaban:

3

Saya setuju dengan @pschill: tidak mungkin mendapatkan std :: vector tanpa menyalin data.

Salah satu alternatif adalah dengan menggunakan std::spantemplat kelas (diperkenalkan dalam C ++ 20), atau spantemplat kelas serupa yang didefinisikan dalam pustaka.

Membuat std::span<int>akan memberikan pandangan data yang ada dalam numpyarray, dan menyediakan banyak fungsi anggota yang nyaman (seperti operator[], iterator, front(), back(), dll) di C ++.

Membuat rentang tidak akan pernah menyalin data dari array numpy.

Nicholas
sumber
Terima kasih telah memberikan apa yang saya lihat sebagai alternatif terbaik (selain membangun kelas saya sendiri).
Otherness
Jika saya benar-benar ingin menggunakan (dan memodifikasi) std :: vector dalam fungsi C ++ saya tanpa menyalin, alternatif apa yang akan saya miliki? Pointer mentah ke std :: vector? shared_ptr ke std :: vector?
Gabriel Devillers
@GabrielDevillers, jika saya mengerti pertanyaan Anda, jika ada vektor dan Anda ingin memodifikasinya dalam fungsi Anda, saya akan merekomendasikan menggunakan referensi ke vektor: std::vector<T>& v
NicholasM
@NicholasM yang saya maksud di API yang ingin saya bungkus menggunakan SWIG. Saya bertanya karena saya mengerti bahwa SWIG tidak dapat membungkus referensi non-const ke vektor.
Gabriel Devillers
Oh maaf. Saya sarankan Anda membuat pertanyaan baru yang berfokus pada kasus spesifik Anda.
NicholasM
0

Anda dapat merujuk ke perpustakaan faiss Facebook, yang mencapai apa yang ingin Anda capai, dengan cara yang lebih elegan Oleh:

Khusus python: array numpy <-> C ++ pointer interface (vektor)

Anda dapat melihat kode di halaman Github -nya .

王永欣
sumber