Swig C ++: Schnittstellenvektor <Klassenobjekt *>

8

Grundsätzlich versuche ich, ein Tupel / eine Liste zu haben, die ein Wörterbuch mit verschiedenen Datentypen von Werten (float / int / bool / char / list) in Python enthält.

Ich erhalte dies aus dem folgenden Code:

(<f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4954bdde10> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4954bdde40> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch
*' at 0x7f495668be70> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4952d09a50> >)

Ich möchte die Ausgabe in dieser Form erhalten:

({'I': 1,0, 'B': 2,0, 'C': 3,0, 'dert _': [1,2, 2,3, 3,4, 4,5, 5,6]})

Ich kann mit diesem Klassenobjektzeiger (Haufen *) nicht umgehen und konnte keine Lösung dafür finden. Ich habe im Internet gesucht, aber keine funktionierende Lösung für meinen Fall gefunden.

f_p.cpp:

#include <iostream>
#include "f_p.h"
#define CPP_14 0

std::vector<Bunch*> form_p(const double *array, int x, int y)  {

    std::vector<Bunch*> v;
    Bunch *b1 = new Bunch(5);
    b1->set_I_B_C(1.0, 2.0, 3.0);
    b1->set_dert_({1.2, 2.3, 3.4, 4.5, 5.6});

    float *_dert = b1->get_dert_();
    for(int i=0; i<5; i++) {
        std::cout << _dert[i] << std::endl;
    }

    v.push_back(b1);
    v.push_back(b1); 
    v.push_back(b1); 
    v.push_back(b1); 

    return v;
}

f_p.h:

#ifndef F_P_H
#define f_P_H
#include <memory> 
#include <vector>
#include <memory> 
#include <algorithm>
#include <tuple>
#include <initializer_list>

class Bunch {
    private:
        unsigned int start;
        unsigned int end;
        float I;
        float B;
        float C;
        bool isPos;
        std::unique_ptr<float[]> dert_;
    public:

        explicit Bunch(size_t width) {
            #if CPP_14
            this->dert_ = std::make_unique<float[]>(width);
            #else
            this->dert_ = std::unique_ptr<float[]>(new float[width]);
            #endif
            std::fill_n(this->dert_.get(), width, -1.0);
        }

        void set_I_B_C(float I, float B, float C) {
            this->I = I;
            this->B = B;
            this->C = C;
        }

        std::tuple<float, float, float> get_I_B_C() const {
            return std::make_tuple(this->I, this->B, this->C);
        }

        float* get_dert_() const {
            return this->dert_.get();
        }

        void set_dert_(std::initializer_list<float> l) {
            int i = 0;
            for (auto e: l){
                dert_[i++] = e;
            }
        }
};
/* Define function prototype */
std::vector<Bunch*> form_p(const double *array, int x, int y)  ;
#endif

f_p.i:

%module f_p
#define SWIGPYTHON_BUILTIN

%{
  #include "numpy/arrayobject.h"
  #define SWIG_FILE_WITH_INIT  /* To import_array() below */
  #include "f_p.h"
%}
%include "std_map.i"
%import "std_deque.i" 
%import "std_vector.i" 

%template (mapiv) std::map<char,float>;
%template () std::vector<Bunch*>;
%include "numpy.i"

%init %{
import_array();
%}

%apply (double* IN_ARRAY2, int DIM1, int DIM2) {
  (const double* array, int x, int y)
}

%include "f_p.h"

build.sh:

rm *.o f_p_wrap.cpp _f_p.so f_p.py
rm -rf __pycache__

g++ -O3 -march=native -fPIC -c f_p.cpp
swig -python -c++ -o f_p_wrap.cpp f_p.i

# Next, compile the wrapper code:

g++ -O3 -march=native -w -fPIC -c $(pkg-config --cflags --libs python3) -I /home/antpc/anaconda3/lib/python3.7/site-packages/numpy/core/include f_p.cpp f_p_wrap.cpp

g++ -std=c++11 -O3 -march=native -shared f_p.o f_p_wrap.o -o _f_p.so -lm

test_sample.py:

from f_p import form_p
import numpy as np
x = np.random.randn(3, 4)
print(form_p(x))
Ninjakx
quelle
Ich habe meinen Code stackoverflow.com/questions/59712985/… so geändert, dass er für verschiedene Datentypen funktioniert. Aber jetzt nicht in der Lage, es zu verbinden.
Ninjakx
1
Es sieht so aus, als ob Sie nur ein typemap(out)für erstellen möchten Bunch. Warum form_pkehrt std::vector<Bunch *>statt statt std::vector<Bunch>? Swig wird diese Zeiger nicht freigeben, sodass Sie Speicher verlieren.
Indiana Kernick
Wenn eine Antwort bei der Lösung Ihres Problems geholfen hat, lassen Sie das Kopfgeld nicht verschwenden
Indiana Kernick
@ Kerndog73: Ich wusste nicht, dass es nur 50% des Kopfgeldes vergibt, wenn es nicht ausgewählt wird und der Rest verschwendet wird.
Ninjakx

Antworten:

4

Die Frage läuft wirklich darauf hinaus: Sie haben eine Klasse und möchten sie in ein natives Python-Objekt (anstatt in ein umschlossenes Objekt) konvertieren. SWIG generiert automatisch umschlossene Objekte, aber Sie müssen sich alle Mühe geben, um C ++ - Typen in native Python-Typen zu konvertieren.


Ich gehe davon aus, dass dies vereinfacht ist Bunch, um die Typkarte etwas lesbarer zu machen. Sie sollten dies Bunchganz einfach an Ihre Bedürfnisse anpassen können. Alternativ können Sie Ihre Klasse in diese einfache Struktur konvertieren, bevor Sie sie an Python weitergeben.

struct Bunch {
    float i, b, c;
    std::vector<float> dert;
};

Bunch makeBunch();

Hier ist die Implementierung von makeBunch.

Bunch makeBunch() {
    return {1.0, 2.0, 3.0, {1.2, 2.3, 3.4, 4.5, 5.6}};
}

Ich habe die Fehlerprüfung weggelassen, um sie kurz und prägnant zu halten.

%typemap(out) Bunch {
    $result = PyDict_New();
    PyDict_SetItem($result, PyBytes_FromString("I"), PyFloat_FromDouble($1.i));
    PyDict_SetItem($result, PyBytes_FromString("B"), PyFloat_FromDouble($1.b));
    PyDict_SetItem($result, PyBytes_FromString("C"), PyFloat_FromDouble($1.c));
    PyObject *dert = PyList_New($1.dert.size());
    for (size_t i = 0; i != $1.dert.size(); ++i) {
        PyList_SetItem(dert, i, PyFloat_FromDouble($1.dert[i]));
    }
    PyDict_SetItem($result, PyBytes_FromString("dert_"), dert);
}

Wenn ich dies selbst kompiliere und ausführe, erhalte ich die erwarteten Ergebnisse (na ja, nah genug!).

>>> import test
>>> test.makeBunch()
{'I': 1.0, 'C': 3.0, 'B': 2.0, 'dert_': [1.2000000476837158, 2.299999952316284, 3.4000000953674316, 4.5, 5.599999904632568]}

Die Typkarte ist nicht unbedingt erforderlich. Sie können stattdessen einfach umschlossene Objekte verwenden. Entfernen Sie die Typzuordnung und stellen Sie sicher, dass Sie sie std::vector<float>wie folgt belichten .

%include "std_vector.i"
%template(FloatVector) std::vector<float>;

Dann können Sie Bunchüber ein umschlossenes Objekt zugreifen .

>>> import test
>>> bunch = test.makeBunch()
>>> bunch
<test.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x10b6daba0> >
>>> bunch.i
1.0
>>> bunch.b
2.0
>>> bunch.c
3.0
>>> bunch.dert
<test.FloatVector; proxy of <Swig Object of type 'std::vector< float,std::allocator< float > > *' at 0x10b6dadb0> >
>>> for d in bunch.dert:
...     print(d)
...
1.20000004768
2.29999995232
3.40000009537
4.5
5.59999990463

Einige seriöse Quellen:

Indiana Kernick
quelle
Können Sie diese Frage beantworten: stackoverflow.com/questions/59712985/… die Antwort darauf ist auch die gleiche wie diese. Ich möchte diese Frage schließen.
Ninjakx
@ninjakx Wenn Sie diese Frage schließen möchten, schließen Sie sie einfach (oder löschen Sie sie).
Indiana Kernick