18template <
class InnerSolverT>
19typename ALMSolver<InnerSolverT>::Stats
21 std::optional<rvec> Σ) {
22 using std::chrono::duration_cast;
23 using std::chrono::nanoseconds;
24 auto start_time = std::chrono::steady_clock::now();
29 if (params.max_iter == 0)
35 vec Σ_curr(0), error(0);
38 .max_time = params.max_time,
39 .tolerance = params.tolerance,
43 auto ps = inner_solver(p, opts, x, y, Σ_curr, error);
45 auto time_elapsed = std::chrono::steady_clock::now() - start_time;
52 s.
elapsed_time = duration_cast<nanoseconds>(time_elapsed);
57 constexpr auto NaN = alpaqa::NaN<config_t>;
58 vec Σ_curr = vec::Constant(m,
NaN);
59 vec Σ_old = vec::Constant(m,
NaN);
60 vec error_1 = vec::Constant(m,
NaN);
61 vec error_2 = vec::Constant(m,
NaN);
65 std::array<char, 64> printbuf;
66 auto print_real = [&](
real_t x) {
72 if (Σ && Σ->allFinite() && Σ->norm() > 0) {
76 else if (params.initial_penalty > 0) {
77 Σ_curr.fill(params.initial_penalty);
81 Helpers::initialize_penalty(p, params, x, Σ_curr);
84 real_t ε = params.initial_tolerance;
86 real_t Δ = params.penalty_update_factor;
87 real_t ρ = params.tolerance_update_factor;
89 unsigned num_successful_iters = 0;
91 for (
unsigned i = 0; i < params.max_iter; ++i) {
94 p.eval_proj_multipliers(y, params.max_multiplier);
96 bool out_of_penalty_factor_updates =
97 (num_successful_iters == 0
101 params.max_total_num_retries);
102 bool out_of_iter = i + 1 == params.max_iter;
106 bool overwrite_results = out_of_iter || out_of_penalty_factor_updates;
111 auto time_elapsed = std::chrono::steady_clock::now() - start_time;
112 auto time_remaining = time_elapsed < params.max_time
113 ? params.max_time - time_elapsed
114 :
decltype(time_elapsed){0};
117 .max_time = time_remaining,
125 auto ps = inner_solver(p, opts, x, y, Σ_curr, error_2);
132 time_elapsed = std::chrono::steady_clock::now() - start_time;
133 bool out_of_time = time_elapsed > params.max_time;
135 not inner_converged && not overwrite_results && not out_of_time;
138 if (params.print_interval != 0 && i % params.print_interval == 0) {
140 const char *color = inner_converged ?
"\x1b[0;32m" :
"\x1b[0;31m";
141 const char *color_end =
"\x1b[0m";
142 *os <<
"[\x1b[0;34mALM\x1b[0m] " << std::setw(5) << i
143 <<
": ‖Σ‖ = " << print_real(Σ_curr.norm())
144 <<
", ‖y‖ = " << print_real(y.norm())
145 <<
", δ = " << print_real(δ) <<
", ε = " << print_real(ps.ε)
146 <<
", Δ = " << print_real(Δ) <<
", status = " << color
147 << std::setw(13) << ps.status << color_end
148 <<
", iter = " << std::setw(13) << ps.iterations
158 s.
elapsed_time = duration_cast<nanoseconds>(time_elapsed);
179 if (num_successful_iters > 0) {
182 Δ = std::fmax(params.min_penalty_update_factor,
183 Δ * params.penalty_update_factor_lower);
184 Helpers::update_penalty_weights(params, Δ,
false, error_1,
185 error_2, norm_e_1, norm_e_2,
186 Σ_old, Σ_curr,
true);
188 ρ = std::fmin(params.ρ_max, ρ * params.ρ_increase);
189 ε = std::fmax(ρ * ε_old, params.tolerance);
194 Σ_curr *= params.initial_penalty_lower;
195 ε *= params.initial_tolerance_increase;
205 error_2.swap(error_1);
209 bool alm_converged = ps.ε <= params.tolerance && inner_converged &&
210 norm_e_1 <= params.dual_tolerance;
211 bool exit = alm_converged || out_of_iter || out_of_time;
217 s.
elapsed_time = duration_cast<nanoseconds>(time_elapsed);
230 Helpers::update_penalty_weights(
231 params, Δ, num_successful_iters == 0, error_1, error_2,
232 norm_e_1, norm_e_2, Σ_old, Σ_curr,
true);
234 ε_old = std::exchange(ε, std::fmax(ρ * ε, params.tolerance));
235 ++num_successful_iters;
238 throw std::logic_error(
"[ALM] loop error");
unsigned penalty_reduced
The number of times that the penalty update factor ALMParams::penalty_update_factor was reduced,...
real_t δ
Final dual tolerance or constraint violation that was reached:
real_t norm_penalty
2-norm of the final penalty factors .
typename InnerSolver::Problem Problem
std::chrono::nanoseconds elapsed_time
Total elapsed time.
unsigned initial_penalty_reduced
The number of times that the initial penalty factor was reduced by ALMParams::initial_penalty_lower a...
InnerStatsAccumulator< typename InnerSolver::Stats > inner
The statistics of the inner solver invocations, accumulated over all ALM iterations.
unsigned inner_convergence_failures
The total number of times that the inner solver failed to converge.
real_t ε
Final primal tolerance that was reached, depends on the stopping criterion used by the inner solver,...
unsigned outer_iterations
Total number of outer ALM iterations (i.e.
Stats operator()(const Problem &problem, rvec x, rvec y, std::optional< rvec > Σ=std::nullopt)
SolverStatus status
Whether the solver converged or not.
auto norm_inf(const Eigen::MatrixBase< Derived > &v)
Get the maximum or infinity-norm of the given vector.
@ Interrupted
Solver was interrupted by the user.
@ MaxTime
Maximum allowed execution time exceeded.
@ MaxIter
Maximum number of iterations exceeded.
@ Converged
Converged and reached given tolerance.
typename Conf::real_t real_t
bool always_overwrite_results
Return the final iterate and multipliers, even if the solver did not converge.
std::string_view float_to_str_vw(auto &buf, double value, int precision=std::numeric_limits< double >::max_digits10)