56 lines
1.4 KiB
C++
56 lines
1.4 KiB
C++
#pragma once
|
|
|
|
#include <iostream>
|
|
|
|
#include "autoopt/optimization_problem.hpp"
|
|
|
|
namespace autoopt {
|
|
|
|
template <typename T>
|
|
struct btls_parameters {
|
|
T step_decrease = T{0.5};
|
|
T step_increase = T{1.2};
|
|
T sufficient_decrease = T{1e-2};
|
|
T tolerance = T{1e-10};
|
|
size_t max_iters = 2000;
|
|
};
|
|
|
|
template <typename T>
|
|
void btls(optimization_problem<T>& problem,
|
|
const btls_parameters<T>& params = btls_parameters<T>()) {
|
|
Eigen::VectorX<T>& x = problem.x();
|
|
T step_size = T{1.0};
|
|
|
|
for (size_t iter = 0; iter < params.max_iters; ++iter) {
|
|
T obj_value = problem.objective(x);
|
|
|
|
Eigen::VectorX<T> grad = problem.gradient(x);
|
|
|
|
Eigen::MatrixX<T> hess = problem.hessian(x);
|
|
Eigen::VectorX<T> step_dir = -hess.ldlt().solve(grad).normalized();
|
|
|
|
// Eigen::VectorX<T> step_dir = -grad.normalized();
|
|
|
|
auto decrease_condition = [&] {
|
|
T new_obj = problem.objective(x + step_size * step_dir);
|
|
return std::isnan(new_obj) ||
|
|
(new_obj > obj_value - std::abs(params.sufficient_decrease *
|
|
step_size * grad.dot(step_dir)));
|
|
};
|
|
|
|
while (decrease_condition()) {
|
|
step_size *= params.step_decrease;
|
|
}
|
|
x += step_size * step_dir;
|
|
|
|
step_size = step_size * params.step_increase;
|
|
|
|
if (step_size < params.tolerance) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
problem.x() = x;
|
|
}
|
|
|
|
} // namespace autoopt
|