Cómo convertir matrices numpy a vector <int> & (referencia) con SWIG

10

Mi meta:

Cree 3 arreglos numpy en python (2 de ellos se inicializarán con valores específicos), luego envíe los tres a través de swig en una función c ++ como referencias de vectores (esto es para evitar copiar sobre los datos y perder eficiencia). Una vez en la función c ++, agregue 2 de las matrices y coloque su suma en la tercera matriz.

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)

Salida:

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

He probado todas las directivas comentadas% apply y% template encontradas en vec_ref.i, pero no funcionaron.

¿Hay algunos tipos de letra que debería incluir, que no estoy?

Alteridad
fuente
3
Eso no es posible. En C ++, solo puede crear referencias a objetos que realmente existen. Sin embargo, las matrices numpy no contienen a std::vector.
pschill
Relacionado: stackoverflow.com/questions/51466189/…
Gabriel Devillers

Respuestas:

3

Estoy de acuerdo con @pschill: no es posible obtener un std :: vector sin copiar datos.

Una alternativa es usar el std::span plantilla de clase (introducida en C ++ 20), o una spanplantilla de clase similar definida en una biblioteca.

Creación de un std::span<int>proporcionaría una vista de los datos existentes en una numpymatriz, y proporcionar muchas funciones miembro convenientes (tales como operator[], iteradores, front(), back(), etc.) en C ++.

Crear un lapso nunca copiaría datos de la matriz numpy.

NicholasM
fuente
Gracias por proporcionar lo que veo como la mejor alternativa (aparte de construir mi propia clase).
Otredad
Si realmente quisiera usar (y modificar) un std :: vector en mi función C ++ sin copiar, ¿qué alternativas tendría? Puntero sin procesar a std :: vector? shared_ptr a std :: vector?
Gabriel Devillers
@GabrielDevillers, si entiendo su pregunta, si existe un vector y desea modificarlo en su función, recomendaría usar una referencia al vector: std::vector<T>& v
NicholasM
@NicholasM quise decir en una API que quiero ajustar usando SWIG. Lo pregunto porque entiendo que SWIG no puede ajustar la referencia no constante a los vectores.
Gabriel Devillers
Oh, lo siento. Le sugiero que cree una nueva pregunta que se centre en su caso específico.
NicholasM
0

Puede consultar la biblioteca de faiss de Facebook, que logra lo que desea lograr, de una manera más elegante.

Específico de Python: interfaz de puntero numpy array <-> C ++ (vector)

Puedes ver el código en su página de Github .

王永欣
fuente