2017-05-13 97 views
2

我有以下C++類,我希望使用SWIG在Python中進行封裝。使用SWIG封裝Python中的C++類

typedef std::map<std::string, double> ParamaterSet; 

class GPRegressor{ 
public: 
    double runRegression(const double *trainData, const double *trainTruth, int trainRows, int trainCols, 
          const double *testData, const double *testTruth, int testRows, int testCols, 
          const ParamaterSet &params); 

    GPRegressor(KernelType kernType = SQUARED_EXPONENTIAL); 
    ~GPRegressor(); 
    }; 

我寫了下面的SWIG接口文件,讓我numpy的數組傳遞到runRegression成員函數。

%module pyGP 
%{ 
#define SWIG_FILE_WITH_INIT 
#include "lib/typedefs.h" 
#include "lib/Kernels.h" 
#include "lib/GPRegressor.h" 
%} 

%include "numpy.i" 
%include "std_string.i" 
%include "std_map.i" 
%template(map_string_double) std::map<std::string, double>; 

%init %{ 
    import_array(); 
%} 

%apply (const double *arr, int dim1, int dim2) {(const double *data, int dimx, int dimy)} 
%apply (double *arr, int dim1, int dim2) {(double *data, int dimx, int dimy)} 

%include "lib/typedefs.h" 
%include "lib/Kernels.h" 
%include "lib/GPRegressor.h" 

我相信我已經正確地寫了SWIG typemaps讓我做到這一點。我寫了下面的Python測試代碼。

#!/usr/bin/python3 
import sys, os 
sys.path.append(os.path.realpath('../build')) 
import numpy as np 

from pyGP import * 

def runRegression(): 
    X = np.random.rand(30, 2) 
    Y = np.random.rand(30, 1) 
    X_s = np.random.rand(30, 2) 
    Y_s = np.random.rand(30, 1) 

    regressor = GPRegressor() 
    regressor.runRegression(X, Y, 30, 2, X_s, Y_s, 30, 1, {'a' : 0.0, 'b' : 0.0}) 

if __name__ == "__main__": 
    runRegression() 

但是,我收到以下錯誤,意味着我實際上犯了一個numpy數組的typemaps錯誤。

Traceback (most recent call last): 
    File "./demo.py", line 22, in <module> 
    runRegression() 
    File "./demo.py", line 18, in runRegression 
    regressor.runRegression(X, Y, 30, 2, X_s, Y_s, 30, 1, {'a' : 0.0, 'b' : 0.0}) 
    File "/home/jack/GitRepos/GaussianProcess/build/pyGP.py", line 337, in runRegression 
    return _pyGP.GPRegressor_runRegression(self, trainData, trainTruth, trainRows, trainCols, testData, testTruth, testRows, testCols, params) 
TypeError: in method 'GPRegressor_runRegression', argument 2 of type 'double const *' 

總之,我想知道,如果這樣,我將其包類,它的成員函數,這樣我可以通過numpy的陣列const double*其實是正確的。如果不是,約定是什麼?

編輯: - 我已經更新了SWIG文件包含以下內容:

%apply (double *IN_ARRAY2, int DIM1, int DIM2) {(const double *trainData, int trainCols, int trainRows)}; 
%apply (double *IN_ARRAY1, int DIM1) {(const double *trainTruth, int trainRows)}; 
%apply (double *IN_ARRAY2, int DIM1, int DIM2) {(const double *testData, int testCols, int testRows)}; 
%apply (double *IN_ARRAY1, int DIM1) {(const double *testTruth, int testRows)}; 

,並改變了被包函數的簽名如下:

double runRegression(const double *trainData, int trainCols, int trainRows, const double *trainTruth, 
        int trainTruthRows, const double *testData, int testCols, int testRows, 
        const double *testTruth, int testTruthRows, const ParamaterSet &params); 

使參數的排序與類型映射的排序相匹配。不過,我仍然收到以下錯誤:

Traceback (most recent call last): 
    File "./demo.py", line 23, in <module> 
    runRegression() 
    File "./demo.py", line 19, in runRegression 
    regressor.runRegression(X, 2, 30, Y, 30, X_s, 2, 30, Y_s, 30, {'a' : 0.0, 'b' : 0.0}) 
TypeError: runRegression() takes 6 positional arguments but 12 were given 
+0

你typemaps應該像'%申請(雙* IN_ARRAY2,詮釋DIM1, int DIM2){(const double * iData,int dimx,int dimy)};'注意如何使用IN_ARRAY2' –

+0

@Flexo它是。我會把它作爲答案。 –

回答

1

如果考慮在numpy.i頭的例子中,你將看到如何應用NumPy typemaps例子。

在你的情況,你應該改變

%apply (double *arr, int dim1, int dim2) {(double *data, int dimx, int dimy)} 

%apply (double* IN_ARRAY2, int DIM1, int DIM2) {(const double *testTruth, int testRows, int testColsdouble)}; 

%apply (double* IN_ARRAY2, int DIM1, int DIM2) {(const double *trainTruth, int trainRows, int trainCols)}; 

注意如何IN_ARRAY2用於

+0

嗨,謝謝你的迴應。不過,在進行建議更改後,我仍然收到同樣的錯誤。 我已經嘗試使用和不使用const限定符(因爲我想能夠傳遞一些numpy數組作爲const和其他非常量)。 –

+0

參數名稱'data','dimx'和'dimy'必須與頭文件中的名稱相匹配。如果是「runRegression」函數,則必須命名爲'trainRows'等。 –

+0

感謝您的協助。我現在更新了我的問題,並在實施您的建議後收到了當前的問題。謝謝。 –