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?


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

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.


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 .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.