Come convertire array numpy in vector <int> & (riferimento) con SWIG


10

Il mio obiettivo:

Crea 3 array numpy in Python (2 di questi verranno inizializzati con valori specifici), quindi inviali tutti e tre tramite swig in una funzione c ++ come riferimenti vettoriali (questo per evitare di copiare i dati e perdere efficienza). Una volta nella funzione c ++, aggiungi 2 degli array e metti la loro somma nel terzo array.

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)

Produzione:

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

Ho provato tutte le direttive% apply e% template commentate trovate in vec_ref.i, ma non hanno funzionato.

Ci sono alcune tipografie che dovrei includere tra quelle che non lo sono?


3
Non e possibile. In C ++, puoi solo creare riferimenti a oggetti che esistono realmente. Tuttavia, gli array intorpiditi non contengono a std::vector.
pschill

Risposte:


3

Sono d'accordo con @pschill: non è possibile ottenere uno std :: vector senza copiare i dati.

Un'alternativa è utilizzare il std::spanmodello di classe (introdotto in C ++ 20) o un spanmodello di classe simile definito in una libreria.

Creazione di un std::span<int>fornirebbe una vista di dati esistenti in una numpymatrice, e fornire molte funzioni membro convenienti (ad esempio operator[], iteratori, front(), back(), ecc) in C ++.

La creazione di un intervallo non copierebbe mai i dati dall'array numpy.


Grazie per aver fornito quella che vedo come la migliore alternativa (oltre a costruire la mia classe).
Alterità il

Se volessi davvero usare (e modificare) uno std :: vector nella mia funzione C ++ senza copiare, quali alternative avrei? Puntatore non elaborato a std :: vector? shared_ptr in std :: vector?
Gabriel Devillers,

@GabrielDevillers, se capisco la tua domanda, se esiste un vettore e vuoi modificarlo nella tua funzione, ti consiglio di usare un riferimento al vettore: std::vector<T>& v
NicholasM

@NicholasM Volevo dire in un'API che voglio avvolgere usando SWIG. Lo sto chiedendo perché capisco che SWIG non può racchiudere il riferimento non const ai vettori.
Gabriel Devillers il

Oh scusa. Ti suggerirei di creare una nuova domanda che si concentri sul tuo caso specifico.
NicholasM,

0

Puoi fare riferimento alla libreria delle faiss di Facebook, che raggiunge ciò che vuoi ottenere, in un modo più elegante Di:

Specifico per Python: numpy array <-> C ++ interfaccia del puntatore (vettoriale)

Puoi vedere il codice sulla sua pagina Github .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.