我想有可能使用C ++中的numpy,scipy等python模块。以下代码尝试调用scipy.optimize.curve_fit以适合抛物线函数。调用curve_fit时会出现问题。在这里,抛出异常。
#include <iostream>
#include <pybind11/embed.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h> // mandatory for myPyObject.cast<std::vector<T>>()
#include <pybind11/functional.h> // mandatory for py::cast( std::function )
namespace py = pybind11;
int main()
{
try {
py::scoped_interpreter guard{};
py::module np = py::module::import("numpy");
py::object random = np.attr("random");
py::module scipy = py::module::import("scipy.optimize");
// create some data for fitting
std::vector<double> xValues(11, 0);
std::vector<double> yValues(11, 0);
for (int i = -5; i < 6; ++i) {
xValues[i + 5] = i;
yValues[i + 5] = i*i;
}
// cast it to numpy arrays
py::array_t<double> pyXValues = py::cast(xValues);
py::array_t<double> pyYValues = py::cast(yValues);
// add some noise to the yValues using numpy -> Works!
py::array_t<double> pyYValuesNoise = np.attr("add")(pyYValues, random.attr("randn")(11));
// create a function f_a(x) = a*x^2
std::function<std::vector<double>(std::vector<double>, double)> squared = [](std::vector<double> x, double a) {
std::vector<double> retvals(x);
std::transform(x.begin(), x.end(), retvals.begin(), [a](double val) { return a*val*val; });
return retvals;
};
// cast it to a python function
py::function pySquared = py::cast(squared);
// get scipy.optimize.curve_fit
py::function curve_fit = scipy.attr("curve_fit");
// call curve_fit -> throws exception
/* py::object = */ curve_fit(pySquared, pyXValues, pyYValues);
}
catch (std::exception error) {
std::cout << error.what() << std::endl;
}
system("pause");
return 0;
}
该例外提供了以下信息:
ValueError:找不到内置的<PyCapsule对象的内置方法0x00000204FFE9C630>
在: D:\ Programs \ python36_6_x64 \ Lib \ inspect.py(2090):_ signign_from_builtin D:\ Programs \ python36_6_x64 \ Lib \ inspect.py(2266):_ signign_from_callable D:\ Programs \ python36_6_x64 \ Lib \ inspect.py(2802): from_callable D:\ Programs \ python36_6_x64 \ Lib \ inspect.py(3052):签名D:\ Programs \ python36_6_x64 \ lib \ site-packages \ scipy_lib_util.py(290):getargspec_no_self D:\ Programs \ python36_6_x64 \ lib \ site-packages \ scipy \ optimize \ minpack.py(685):curve_fit
如何正确地从C ++调用curve_fit?
基于Jens Munk的comment,我创建了一个Python模块“MyPythonModule”,其中包含文件“MyFunctionality.py”,具有该功能
def python_square_function(x, a):
return a*x**2
我将此模块的路径添加到环境变量PYTHONPATH。 C ++代码更改为:
#include <iostream>
#include <pybind11/embed.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h> // for myPyObject.cast<std::vector<T>>()
namespace py = pybind11;
int main()
{
py::scoped_interpreter guard{};
py::module np = py::module::import("numpy");
py::object random = np.attr("random");
py::module scipy = py::module::import("scipy.optimize");
// Load created module containing f_a(x) = a*x^2
py::module myModule = py::module::import("MyPythonModule.MyFunctionality");
// Create some data for fitting
std::vector<double> xValues(11, 0);
std::vector<double> yValues(11, 0);
for (int i = -5; i < 6; ++i) {
xValues[i + 5] = i;
yValues[i + 5] = i*i;
}
// Cast data to numpy arrays
py::array_t<double> pyXValues = py::cast(xValues);
py::array_t<double> pyYValues = py::cast(yValues);
// Add some noise to the yValues using numpy
py::array_t<double> pyYValuesNoise = np.attr("add")(pyYValues, random.attr("randn")(11));
// Get the function f_a(x) = a*x^2 we want to fit
py::function pySquareFunction = myModule.attr("python_square_function");
// Load scipy.optimize.curve_fit
py::function curve_fit = scipy.attr("curve_fit");
// Call curve_fit
py::object retVals = curve_fit(pySquareFunction, pyXValues, pyYValuesNoise);
// The return value contains the optimal values and the covariance matrix.
// Get the optimal values
py::object optVals = retVals.attr("__getitem__")(0);
// Cast return value back to std::vector and show the result
std::vector<double> retValsStd = optVals.cast<std::vector<double>>();
std::cout << "Fitted parameter a = " << retValsStd[0] << std::endl;
return 0;
}
此代码导致预期的行为:拟合参数a = 0.978144
。
不幸的是,这仍然是一种解决方法,它使用了一些外部Python代码。能够在C ++源代码中定义所有内容会很棒。