Иерархия абстрактных классов моего кода C++, который в настоящее время нужно обернуть выглядит примерно так (multivariate.h):
Код: Выделить всё
typedef std::function multivariate;
struct multivariate_problem {
// objective
multivariate _f;
int _n;
// bound constraints
double *_lower;
double *_upper;
multivariate_problem(const multivariate f, const int n, double *lower,
double *upper):
_f(f), _n(n), _lower(lower), _upper(upper)) {
}
};
struct multivariate_solution {
... // some code here for return a solution (seems to work ok)
};
class MultivariateOptimizer {
public:
virtual ~MultivariateOptimizer() {
}
// initialize the optimizer
virtual void init(const multivariate_problem &f, const double *guess) = 0;
// perform one step of iteration
virtual void iterate() = 0;
// retrieve current solution
virtual multivariate_solution solution() = 0;
// this essentially calls init(), performs a number of iterate() calls, returns solution()
virtual multivariate_solution optimize(const multivariate_problem &f,
const double *guess) = 0;
};
Код: Выделить всё
// wrap the function expressions
typedef std::function py_multivariate;
// wrap the multivariable optimizer
void build_multivariate(py::module_ &m) {
// wrap the solution object
py::class_ solution(m, "MultivariateSolution");
...
// wrap the solver
py::class_ solver(m, "MultivariateSearch");
// corresponds to MultivariateSearch::optimize()
solver.def("optimize",
[](MultivariateOptimizer &self, py_multivariate py_f,
py::array_t &py_lower,
py::array_t &py_upper,
py::array_t &py_guess) {
const int n = py_lower.size();
double *lower = static_cast(py_lower.request().ptr);
double *upper = static_cast(py_upper.request().ptr);
const multivariate &f = [&py_f, &n](const double *x) -> double {
const auto &py_x = py::array_t(n, x);
return py_f(py_x);
};
const multivariate_problem &prob { f, n, lower, upper };
double *guess = static_cast(py_guess.request().ptr);
return self.optimize(prob, guess);
}, "f"_a, "lower"_a, "upper"_a, "guess"_a,
py::call_guard());
// corresponds to MultivariateSearch::init()
solver.def("initialize",
[](MultivariateOptimizer &self, py_multivariate py_f,
py::array_t &py_lower,
py::array_t &py_upper,
py::array_t &py_guess) {
const int n = py_lower.size();
double *lower = static_cast(py_lower.request().ptr);
double *upper = static_cast(py_upper.request().ptr);
const multivariate &f = [&py_f, &n](const double *x) -> double {
const auto &py_x = py::array_t(n, x);
return py_f(py_x);
};
const multivariate_problem &prob { f, n, lower, upper };
double *guess = static_cast(py_guess.request().ptr);
return self.init(prob, guess);
}, "f"_a, "lower"_a, "upper"_a, "guess"_a,
py::call_guard());
// corresponds to MultivariateSearch::iterate()
solver.def("iterate", &MultivariateOptimizer::iterate);
// corresponds to MultivariateSearch::solution()
solver.def("solution", &MultivariateOptimizer::solution);
// put algorithm-specific bindings here
build_acd(m);
build_amalgam(m);
build_basin_hopping(m);
...
Который затем будет вызываться pybind со следующей точкой входа (mylibrary.cpp):
Код: Выделить всё
namespace py = pybind11;
void build_multivariate(py::module_&);
PYBIND11_MODULE(mypackagename, m) {
build_multivariate(m);
...
}
Код: Выделить всё
import numpy as np
from mylibrary import MySolverName
# function to optimize
def fx(x):
total = 0.0
for x1, x2 in zip(x[:-1], x[1:]):
total += 100 * (x2 - x1 ** 2) ** 2 + (1 - x1) ** 2
return total
n = 10 # dimension of problem
alg = MySolverName(some_args_to_pass...)
sol = alg.optimize(fx,
lower=-10 * np.ones(n),
upper=10 * np.ones(n),
guess=np.random.uniform(low=-10., high=10., size=n))
print(sol)
Чтобы проиллюстрировать вариант использования, следующий код не запускается:
Код: Выделить всё
import numpy as np
from mylibrary import MySolverName
# function to optimize
def fx(x):
... return result here for np.ndarray x
n = 10 # dimension of problem
alg = MySolverName(some_args_to_pass...)
alg.initialize(f=fx,
lower=-10 * np.ones(n),
upper=10 * np.ones(n),
guess=np.random.uniform(low=-10., high=10., size=n))
alg.iterate()
print(alg.solution())
Когда я использую std::cout внутри C++ iterate()< /code>, она всегда зависает в точке прямо перед любыми вызовами функции fx и ничего не печатает после вызова, поэтому я сузил проблему до функции Python, которая не сохраняется правильно с помощью iterate() в качестве точки входа. Тем не менее, оптимизация() вызывает iterate() внутри кода C++, и предыдущий пример работает успешно, поэтому ошибка довольно странная.
Я Я пытался просмотреть документацию по pybind, но не смог найти пример, который бы достиг именно того, что я пытаюсь сделать выше. Я пробовал другие решения, такие как Keep_alive, но безрезультатно.
Можете ли вы помочь мне изменить оболочки pybind, чтобы сохранялась внутренне сохраненная функция Python? внутри объекта C++ и корректно выполняться даже после повторного восстановления управления интерпретатором Python между вызовами iterate()? Спасибо за помощь!
Подробнее здесь: https://stackoverflow.com/questions/791 ... d-wrappers
Мобильная версия