使用 SWIG 在 Python 中包装 C++ class
Wrapping C++ class in Python with SWIG
我有以下 C++ class,我希望用 SWIG 包装在 Python 中。
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 ¶ms);
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 类型映射以允许我执行此操作。我写了下面的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 数组的类型映射中犯了一个错误。
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 *'
总而言之,我想知道我尝试包装 class 及其成员函数以便我可以将 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 ¶ms);
以便参数的顺序与类型映射的顺序相匹配。但是,我仍然收到以下错误:
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
如果查看 numpy.i
header 中的示例,您将看到有关如何应用 NumPy
类型映射的示例。
对于你的情况,你应该改变
%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
的用法
我认为当你将你的 numpy ndarray 提供给你的 C++ 函数时,你不应该添加你的 ndarray 维度信息,在你的情况下是:2, 30, 30...
.
相反,只需提供如下参数:regressor.runRegression(X, Y, X_s, Y_s, {'a' : 0.0, 'b' : 0.0})
.
我有以下 C++ class,我希望用 SWIG 包装在 Python 中。
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 ¶ms);
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 类型映射以允许我执行此操作。我写了下面的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 数组的类型映射中犯了一个错误。
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 *'
总而言之,我想知道我尝试包装 class 及其成员函数以便我可以将 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 ¶ms);
以便参数的顺序与类型映射的顺序相匹配。但是,我仍然收到以下错误:
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
如果查看 numpy.i
header 中的示例,您将看到有关如何应用 NumPy
类型映射的示例。
对于你的情况,你应该改变
%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
的用法
我认为当你将你的 numpy ndarray 提供给你的 C++ 函数时,你不应该添加你的 ndarray 维度信息,在你的情况下是:2, 30, 30...
.
相反,只需提供如下参数:regressor.runRegression(X, Y, X_s, Y_s, {'a' : 0.0, 'b' : 0.0})
.