#pragma once #include #include #include "autoopt/derivative.hpp" namespace autoopt { template struct optimization_problem { virtual std::array initial_guess() = 0; virtual T objective(const std::array& params) = 0; virtual std::array gradient(const std::array& params) = 0; virtual matrix_t hessian(const std::array& params) = 0; }; template struct auto_diff_optimization_problem : public optimization_problem { Func _objective_func; std::array _initial_guess; auto_diff_optimization_problem( Func objective_func, std::array initial_guess = std::array{}) : _objective_func(objective_func), _initial_guess(initial_guess) {} std::array initial_guess() override { return _initial_guess; } T objective(const std::array& params) override { return _objective_func(params); } std::array gradient(const std::array& params) override { return autoopt::gradient(_objective_func, params); } matrix_t hessian(const std::array& params) override { return autoopt::hessian(_objective_func, params); } }; template struct log_barrier_optimization_problem : public optimization_problem { optimization_problem& _base_problem; std::array _delta; T _barrier_strength; log_barrier_optimization_problem( optimization_problem& base_problem, std::array delta, T barrier_strength = T{1e-3}) : _base_problem(base_problem), _delta(delta), _barrier_strength(barrier_strength) {} std::array initial_guess() override { return _base_problem.initial_guess(); } T objective(const std::array& params) override { T base_obj = _base_problem.objective(params); T barrier = barrier_term(params); return base_obj + barrier; } std::array gradient(const std::array& params) override { auto base_grad = _base_problem.gradient(params); std::array barrier_grad = autoopt::gradient( [this](const std::array& p) { return barrier_term(p); }, params); std::array total_grad; for (size_t i = 0; i < N; ++i) { total_grad[i] = base_grad[i] + barrier_grad[i]; } return total_grad; } matrix_t hessian(const std::array& params) override { auto base_hess = _base_problem.hessian(params); matrix_t barrier_hess = autoopt::hessian( [this](const std::array& p) { return barrier_term(p); }, params); matrix_t total_hess; for (size_t i = 0; i < N; ++i) { for (size_t j = 0; j < N; ++j) { total_hess[i][j] = base_hess[i][j] + barrier_hess[i][j]; } } return total_hess; } private: template U barrier_term(const std::array& params) { U barrier = U{0}; for (size_t i = 0; i < N; ++i) { U lb = _base_problem.initial_guess()[i] - _delta[i]; U ub = _base_problem.initial_guess()[i] + _delta[i]; barrier = barrier + std::log(params[i] - lb) + std::log(ub - params[i]); } return -U{_barrier_strength} * barrier; } }; } // namespace autoopt