12#include <fmt/chrono.h>
14#include <fmt/format.h>
19#include "detail/math.hpp"
22#include "optim/tr_strategy.hpp"
29 std::shared_ptr<TrustRegionStrategy>
strat{std::make_shared<CeresStrategy>()};
42 enum class Status { Ftol, Ptol, MaxIters } status;
44 std::chrono::nanoseconds time;
67 std::optional<SolveResult::Status> status = {};
68 const auto t0 = std::chrono::high_resolution_clock::now();
74 for (; iter < opts.max_iter && !status.has_value(); ++iter) {
76 const auto [r, J] = diff::dr<1, D>(f, x);
78 using JType = std::decay_t<
decltype(J)>;
79 static constexpr auto N = JType::ColsAtCompileTime;
81 if (opts.verbose && iter == 0) {
83 fmt::print(
"{0:x^69s}\n{1:x^69s}\n{0:x^69s}\n",
"",
" NLS SOLVER ");
84 fmt::print(
"Optimizing {} residuals in {} degrees of freedom\n", J.rows(), J.cols());
86 std::cout <<
"#define SMOOTH_HAS_FMT and link with fmt to see minimizer progress.\n";
91 static constexpr auto clamper = [](
double el) {
return std::clamp(el, 1e-6, 1e32); };
92 const Eigen::Vector<double, N> d = colwise_norm(J).unaryExpr(clamper);
95 const double Delta = opts.strat->get_delta();
97 const auto xp = wrt_rplus(x, dx);
100 const double r_n = r.stableNorm();
101 const double actu_red = 1. - fpow<2>(std::apply(f, xp).stableNorm() / r_n);
102 const double pred_red = 1. - fpow<2>((r + J * dx).stableNorm() / r_n);
103 const double rho = actu_red / pred_red;
106 const bool take_step = opts.strat->step_and_update(rho);
111 using namespace std::chrono;
112 if (iter % 25 == 0) {
113 print(
"{:<6s}",
"ITER");
114 print(
"{:^10s}",
"TIME");
115 print(emphasis::bold,
"{:^12s}",
"∥r∥");
116 print(
"{:^9s}",
"Δ");
118 print(
"{:^9s}",
"∥D dx∥");
119 print(
"{:^9s}",
"∥D∥");
120 print(
"{:^6s}",
"STEP");
123 const auto step_col = take_step ? color::dark_green : color::dark_red;
124 const auto rho_col = rho > 0 ? color::dark_green : color::dark_red;
126 print(
"{:<6}", iter);
127 print(
"{:>9} ", duration_cast<milliseconds>(high_resolution_clock::now() - t0));
128 print(emphasis::bold,
"{:^12.4e}", r_n);
129 print(
"{:^9.1e}", Delta);
130 print(fg(rho_col),
"{:^9.1e}", rho);
131 print(
"{:^9.1e}", d.cwiseProduct(dx).stableNorm());
132 print(
"{:^9.1e}", d.norm());
133 print(fg(step_col),
"{:^5s}", take_step ?
" ✔️ " :
" ❌ ");
139 if (r_n == 0 || pred_red <= 0 || take_step) {
146 if (std::abs(actu_red) < opts.ftol && pred_red < opts.ftol && rho <= 2.) {
147 status = SolveResult::Status::Ftol;
148 }
else if (d.cwiseProduct(dx).stableNorm() < opts.ptol *
static_cast<double>(dx.size())) {
149 status = SolveResult::Status::Ptol;
157 using namespace std::chrono;
159 print(
"{0:x^69s}\n",
"");
160 print(
"{:>10s}: {}\n",
"Total time", duration_cast<milliseconds>(high_resolution_clock::now() - t0));
161 print(
"{:>10s}: {}\n",
"Iterations", iter);
162 print(
"{:>10s}: {:.2f}\n",
"Objective", std::apply(f, x).norm());
163 print(
"{0:x^69s}\n",
"");
168 .status = status.value_or(SolveResult::Status::MaxIters),
170 .time = std::chrono::high_resolution_clock::now() - t0,
188template<diff::Type D>
191 static constexpr auto do_nothing = [](
const auto &...) {};
192 return minimize<D>(std::forward<
decltype(f)>(f), std::forward<
decltype(x)>(x), do_nothing, opts);
211 static constexpr auto do_nothing = [](
const auto &...) {};
212 return minimize<diff::Type::Default>(std::forward<
decltype(f)>(f), std::forward<
decltype(x)>(x), do_nothing, opts);
Differentiation on Manifolds.
std::shared_ptr< TrustRegionStrategy > strat
strategy
double ptol
relative parameter tolerance for convergence
double ftol
relative function tolerance for convergence
bool verbose
print solver status to stdout
std::size_t max_iter
maximum number of iterations
Trust region algorithms for determining step size.
auto solve_trust_region(const auto &J, const Eigen::MatrixBase< D2 > &d, const Eigen::MatrixBase< D3 > &r, const double Delta) -> std::pair< Eigen::Vector< typename std::decay_t< decltype(J)>::Scalar, std::decay_t< decltype(J)>::ColsAtCompileTime >, double >
Approximately solve trust-region step determination problem.