#pragma once #include #include "autoopt/derivative.hpp" namespace autoopt { template struct optimization_problem { virtual Eigen::VectorX& initial_guess() = 0; virtual Eigen::VectorX& x() = 0; virtual T objective(const Eigen::VectorX& params) = 0; virtual Eigen::VectorX gradient(const Eigen::VectorX& params) = 0; virtual Eigen::MatrixX hessian(const Eigen::VectorX& params) = 0; }; template struct auto_diff_optimization_problem : public optimization_problem { Func _objective_func; Eigen::VectorX _initial_guess; Eigen::VectorX _x; auto_diff_optimization_problem( Func objective_func, Eigen::VectorX initial_guess = Eigen::VectorX{}) : _objective_func(objective_func), _initial_guess(initial_guess), _x(initial_guess) {} Eigen::VectorX& initial_guess() override { return _initial_guess; } Eigen::VectorX& x() override { return _x; } T objective(const Eigen::VectorX& params) override { return _objective_func(params); } Eigen::VectorX gradient(const Eigen::VectorX& params) override { return autoopt::gradient(_objective_func, params); } Eigen::MatrixX hessian(const Eigen::VectorX& params) override { return autoopt::hessian(_objective_func, params); } }; template struct log_barrier_optimization_problem : public optimization_problem { optimization_problem& _base_problem; Eigen::VectorX _delta; T _barrier_strength; log_barrier_optimization_problem( optimization_problem& base_problem, Eigen::VectorX delta, T barrier_strength = T{1e-3}) : _base_problem(base_problem), _delta(delta), _barrier_strength(barrier_strength) {} Eigen::VectorX& initial_guess() override { return _base_problem.initial_guess(); } Eigen::VectorX& x() override { return _base_problem.x(); } T objective(const Eigen::VectorX& params) override { T base_obj = _base_problem.objective(params); T barrier = barrier_term(params); return base_obj + barrier; } Eigen::VectorX gradient(const Eigen::VectorX& params) override { auto base_grad = _base_problem.gradient(params); Eigen::VectorX barrier_grad = autoopt::gradient( [this](const Eigen::VectorX& p) { return barrier_term(p); }, params); Eigen::VectorX total_grad(params.size()); total_grad = base_grad + barrier_grad; return total_grad; } Eigen::MatrixX hessian(const Eigen::VectorX& params) override { auto base_hess = _base_problem.hessian(params); Eigen::MatrixX barrier_hess = autoopt::hessian( [this](const Eigen::VectorX& p) { return barrier_term(p); }, params); Eigen::MatrixX total_hess(params.size(), params.size()); total_hess = base_hess + barrier_hess; return total_hess; } private: template U barrier_term(const Eigen::VectorX& params) { U barrier = U{0}; for (int i = 0; i < params.size(); ++i) { U lb = U{_base_problem.initial_guess()(i) - _delta(i)}; U ub = U{_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