Como converter matrizes numpy em vetor <int> & (referência) com SWIG

10

Meu gol:

Crie 3 matrizes numpy em python (2 delas serão inicializadas com valores específicos) e, em seguida, envie todas as três por meio de swig para uma função c ++ como referência de vetor (isto é para evitar a cópia dos dados e a perda de eficiência). Uma vez na função c ++, adicione 2 das matrizes e coloque sua soma na 3ª 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)

Resultado:

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

Eu tentei todas as diretivas% apply e% template comentadas encontradas em vec_ref.i, mas elas não funcionaram.

Existem alguns mapas de tipo que eu deveria incluir e que não sou?

Alteridade
fonte
3
Isso não é possível. No C ++, você só pode criar referências a objetos que realmente existem. No entanto, matrizes numpy não contêm a std::vector.
Psgill
Relacionados: stackoverflow.com/questions/51466189/...
Gabriel Devillers

Respostas:

3

Concordo com o @pschill: não é possível obter um vetor std :: sem copiar dados.

Uma alternativa é usar o std::spanmodelo de classe (introduzido no C ++ 20) ou um spanmodelo de classe semelhante definido em uma biblioteca.

Criando um std::span<int>proporcionaria uma vista de dados existentes numa numpymatriz, e proporcionam muitas funções membro conveniente (tal como operator[], iterators, front(), back(), etc.) em C ++.

Criar um intervalo nunca copiaria dados da matriz numpy.

NicholasM
fonte
Obrigado por fornecer o que considero a melhor alternativa (além de criar minha própria classe).
Otherness
Se eu realmente quisesse usar (e modificar) um std :: vector na minha função C ++ sem copiar, que alternativas eu teria? Ponteiro bruto para std :: vector? shared_ptr para std :: vector?
Gabriel Devillers
@ GabrielDevillers, se eu entendi a sua pergunta, se um vetor existe e você deseja modificá-lo em sua função, eu recomendaria o uso de uma referência ao vetor: std::vector<T>& v
NicholasM
@ NicolasM eu quis dizer em uma API que eu quero quebrar usando SWIG. Estou perguntando porque entendo que o SWIG não pode agrupar referências não constantes a vetores.
Gabriel Devillers
Oh, desculpe. Sugiro que você crie uma nova pergunta que se concentre no seu caso específico.
NicholasM
0

Você pode consultar a biblioteca de faisses do Facebook, que alcança o que deseja alcançar, de uma maneira mais elegante Por:

Específico para Python: matriz numpy <-> interface de ponteiro C ++ (vetor)

Você pode ver o código na página do Github .

王永欣
fonte