Comment convertir des tableaux numpy en vecteur <int> & (référence) avec SWIG

10

Mon but:

Créez 3 tableaux numpy en python (2 d'entre eux seront initialisés avec des valeurs spécifiques), puis envoyez-les tous les trois via swig dans une fonction c ++ en tant que références vectorielles (ceci afin d'éviter de copier les données et de perdre en efficacité). Une fois dans la fonction c ++, ajoutez 2 des tableaux et mettez leur somme dans le 3e tableau.

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)

Production:

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

J'ai essayé toutes les directives% apply et% template commentées dans vec_ref.i, mais elles n'ont pas fonctionné.

Existe-t-il des types de typographie que je devrais inclure, dont je ne suis pas?

Altérité
la source
3
Ce n'est pas possible. En C ++, vous ne pouvez créer que des références à des objets qui existent réellement. Cependant, les tableaux numpy ne contiennent pas de a std::vector.
pschill
Connexe: stackoverflow.com/questions/51466189/…
Gabriel Devillers

Réponses:

3

Je suis d'accord avec @pschill: il n'est pas possible d'obtenir un std :: vector sans copier les données.

Une alternative consiste à utiliser le std::spanmodèle de classe (introduit en C ++ 20), ou un spanmodèle de classe similaire défini dans une bibliothèque.

Création d' une std::span<int>fournirait une vue des données existantes dans un numpytableau, et de fournir de nombreuses fonctions pratiques membres ( par exemple operator[], itérateurs, front(), back(), etc.) en C ++.

La création d'une étendue ne copiera jamais les données du tableau numpy.

NicholasM
la source
Merci d'avoir fourni ce que je considère être la meilleure alternative (en plus de créer ma propre classe).
Altérité
Si je voulais vraiment utiliser (et modifier) ​​un vecteur std :: dans ma fonction C ++ sans copier, quelles alternatives aurais-je? Pointeur brut vers std :: vector? shared_ptr à std :: vector?
Gabriel Devillers
@GabrielDevillers, si je comprends votre question, si un vecteur existe et que vous souhaitez le modifier dans votre fonction, je vous recommande d'utiliser une référence au vecteur: std::vector<T>& v
NicholasM
@NicholasM Je voulais dire dans une API que je veux encapsuler avec SWIG. Je demande parce que je comprends que SWIG ne peut pas encapsuler une référence non constante aux vecteurs.
Gabriel Devillers
Oh pardon. Je vous suggère de créer une nouvelle question qui se concentre sur votre cas spécifique.
NicholasM
0

Vous pouvez vous référer à la bibliothèque Facebook faiss, qui réalise ce que vous voulez réaliser, d'une manière plus élégante Par:

Spécifique à Python: tableau numpy <-> interface de pointeur C ++ (vecteur)

Vous pouvez voir le code sur sa page Github .

王永欣
la source