So konvertieren Sie Numpy-Arrays mit SWIG in den Vektor <int> & (Referenz)

10

Mein Ziel:

Erstellen 3 numpy Arrays in Python (2 von ihnen werden mit bestimmten Werten initialisiert werden), dann alle drei von ihnen in eine c ++ Funktion als Vektor durch swig senden Referenzen (dies ist , um die Daten zu vermeiden Kopieren über und verlieren Effizienz). Fügen Sie in der c ++ - Funktion 2 der Arrays hinzu und geben Sie ihre Summe in das 3. Array ein.

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)

Ausgabe:

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

Ich habe alle auskommentierten Direktiven% apply und% template in vec_ref.i ausprobiert, aber sie haben nicht funktioniert.

Gibt es einige Typkarten, die ich einschließen sollte, die ich nicht bin?

Anderssein
quelle
3
Das ist doch nicht möglich. In C ++ können Sie nur Verweise auf tatsächlich vorhandene Objekte erstellen. Numpy-Arrays enthalten jedoch kein a std::vector.
Pschill
Siehe auch
Gabriel Devillers

Antworten:

3

Ich stimme @pschill zu: Es ist nicht möglich, einen std :: vector zu erhalten, ohne Daten zu kopieren.

Eine Alternative ist die Verwendung der std::spanKlassenvorlage (eingeführt in C ++ 20) oder einer ähnlichenspan Klassenvorlage, die in einer Bibliothek definiert ist.

Ein Erstellen std::span<int>würde eine schaffen Ansicht vorhandenen Daten in einem numpyArray und bieten viele praktische Elementfunktionen (wie zum Beispiel operator[], Iteratoren front(), back()usw.) in C ++.

Das Erstellen eines Bereichs würde niemals Daten aus dem Numpy-Array kopieren.

NicholasM
quelle
Vielen Dank für die Bereitstellung der meiner Meinung nach besten Alternative (abgesehen vom Aufbau meiner eigenen Klasse).
Anderssein
Welche Alternativen hätte ich, wenn ich wirklich einen std :: vector in meiner C ++ - Funktion ohne Kopieren verwenden (und ändern) wollte? Roher Zeiger auf std :: vector? shared_ptr to std :: vector?
Gabriel Devillers
@GabrielDevillers, wenn ich Ihre Frage verstehe, wenn ein Vektor existiert und Sie ihn in Ihrer Funktion ändern möchten, würde ich empfehlen, einen Verweis auf den Vektor zu verwenden: std::vector<T>& v
NicholasM
@NicholasM Ich meinte in einer API, dass ich mit SWIG umbrechen möchte. Ich frage, weil ich verstehe, dass SWIG keine nicht konstanten Verweise auf Vektoren umschließen kann.
Gabriel Devillers
Oh, das tut mir leid. Ich würde vorschlagen, dass Sie eine neue Frage erstellen, die sich auf Ihren speziellen Fall konzentriert.
NicholasM
0

Sie können auf elegantere Weise auf die Facebook-Faiss-Bibliothek verweisen, die das erreicht, was Sie erreichen möchten.

Python-spezifisch: numpy array <-> C ++ Zeigerschnittstelle (Vektor)

Sie können den Code auf seiner Github-Seite sehen .

王永欣
quelle