Swig C ++: Vectơ xen kẽ <Đối tượng lớp *>


8

về cơ bản tôi đang cố gắng để có một tuple / list chứa một từ điển các loại giá trị dữ liệu khác nhau (float / int / bool / char / list) trong python.

Tôi nhận được điều này từ mã sau đây:

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

Tôi muốn nhận đầu ra ở dạng này:

({'Tôi': 1.0, 'B': 2.0, 'C': 3.0, 'dert _': [1.2, 2.3, 3.4, 4.5, 5.6]})

Tôi không thể đối phó với con trỏ đối tượng lớp này (bó *) và không thể tìm thấy bất kỳ giải pháp nào cho nó. Tôi đã tìm trên mạng nhưng không thể tìm thấy giải pháp nào cho trường hợp của mình.

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"

xây dựng

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

Tôi đã sửa đổi mã stackoverflow.com/questions/59712985/ của tôi để làm việc cho các loại dữ liệu khác nhau. BUt bây giờ không thể giao diện nó.
ninjakx

1
Có vẻ như bạn chỉ muốn tạo một typemap(out)cho Bunch. Tại sao form_ptrở lại std::vector<Bunch *>thay vì std::vector<Bunch>? Swig sẽ không giải phóng những con trỏ đó để bạn bị rò rỉ bộ nhớ.
Indiana Kernick

Nếu một câu trả lời giúp giải quyết vấn đề của bạn thì đừng để tiền thưởng bị lãng phí
Indiana Kernick

@ Kerndog73: Tôi không biết rằng nó chỉ thưởng 50% tiền thưởng khi không được chọn và phần còn lại bị lãng phí.
ninjakx

Câu trả lời:


4

Câu hỏi thực sự tập trung vào vấn đề này: bạn có một lớp và bạn muốn chuyển đổi nó thành một đối tượng Python nguyên gốc (chứ không phải là một đối tượng được bao bọc). SWIG tự động tạo các đối tượng được bao bọc nhưng bạn phải tìm cách chuyển đổi các loại C ++ thành các loại Python nguyên gốc.


Tôi giả sử điều này được đơn giản hóa Bunchđể làm cho sơ đồ kiểu dễ đọc hơn một chút. Bạn sẽ có thể thích ứng điều này với Bunchkhá dễ dàng. Ngoài ra, bạn có thể chuyển đổi lớp của mình sang cấu trúc đơn giản này trước khi chuyển nó sang Python.

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

Bunch makeBunch();

Đây là việc thực hiện makeBunch.

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

Tôi đã bỏ qua việc kiểm tra lỗi để giữ cho nó ngắn gọn và súc tích.

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

Khi tôi biên dịch và tự chạy nó, tôi nhận được kết quả mong đợi (tốt, đủ gần!).

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

Các bản đồ không cần thiết. Thay vào đó bạn chỉ có thể sử dụng các đối tượng được bọc. Xóa bản đồ loại và đảm bảo phơi bày std::vector<float>như vậy.

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

Sau đó, bạn có thể truy cập Bunchthông qua một đối tượng được bọc.

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

Một số nguồn uy tín:


Bạn có thể trả lời câu hỏi này không: stackoverflow.com/questions/59712985/ trên câu trả lời cho câu hỏi này cũng giống như câu hỏi này. Tôi muốn đóng câu hỏi đó.
ninjakx

@ninjakx Nếu bạn muốn đóng câu hỏi đó thì chỉ cần đóng nó (hoặc xóa nó).
Indiana Kernick
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.