Swig C ++:インターフェースベクター<クラスオブジェクト*>


8

基本的に私はPythonで値の異なるデータ型の辞書(float / int / bool / char / list)を含むタプル/リストを作ろうとしています。

私はこれを次のコードから取得しています:

(<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> >)

この形式で出力を取得したい:

({'I':1.0、 'B':2.0、 'C':3.0、 'dert _':[1.2、2.3、3.4、4.5、5.6]})

私はこのクラスオブジェクトポインター(bunch *)を処理できず、解決策を見つけることができませんでした。私はネットを調べましたが、私の場合に有効な解決策が見つかりませんでした。

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))

さまざまなデータ型で機能するようにコードstackoverflow.com/questions/59712985/…を変更しました。BUtは今それをインターフェースすることができません。
ninjakx

1
typemap(out)for を作成したいようですBunch。代わりになぜform_p戻るstd::vector<Bunch *>std::vector<Bunch>ですか?Swigはこれらのポインターを解放しないため、メモリーをリークします。
インディアナカーニック

回答が問題の解決に役立った場合は、賞金を無駄にしないでください
インディアナカーニック

@ Kerndog73:選ばれなかった場合に賞金の50%しか授与されず、残りが無駄になっていることは知らなかった。
ninjakx

回答:


4

質問は本当にこれに要約されます:クラスがあり、それを(ラップされたオブジェクトではなく)ネイティブPythonオブジェクトに変換したいとします。SWIGは自動的にラップされたオブジェクトを生成しますが、C ++の型をネイティブのPythonの型に変換する必要はありません。


Bunchタイプマップをもう少し読みやすくするために、これは単純化されていると想定しています。あなたはこれをあなたのBunch非常に簡単に適応できるはずです。あるいは、Pythonに渡す前に、クラスをこの単純な構造体に変換することもできます。

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

Bunch makeBunch();

の実装は次のとおりですmakeBunch

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

エラーチェックを省略して、簡潔かつ簡潔にしています。

%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);
}

これを自分でコンパイルして実行すると、期待どおりの結果が得られます(まあ、十分近いです!)。

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

タイプマップは必ずしも必要ではありません。代わりに、ラップされたオブジェクトを使用できます。型マップを削除し、そのように公開するstd::vector<float>ようにしてください。

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

その後Bunch、ラップされたオブジェクトを介してアクセスできます。

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

信頼できる情報源:


この質問に答えることができます:stackoverflow.com/questions/59712985/…その答えもこれと同じです。その質問を閉じたいと思います。
ninjakx

@ninjakxその質問を閉じたい場合は、単に閉じてください(または削除してください)。
インディアナカーニック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.