86 using std::chrono::nanoseconds;
87 auto os = opts.os ? opts.os : this->
os;
88 auto start_time = std::chrono::steady_clock::now();
91 const auto n = problem.get_num_variables();
92 const auto m = problem.get_num_constraints();
113 real_t fbe()
const {
return ψx + hx̂ + pᵀp / (2 * γ) + grad_ψᵀp; }
117 Iterate *curr = &iterate;
121 curr->grad_ψx̂.resize(n);
123 vec work_n1(n), work_n2(n), work_m(m);
128 auto qub_violated = [
this](
const Iterate &i) {
130 (1 + std::abs(i.ψx)) *
params.quadratic_upperbound_tolerance_factor;
131 return i.ψx̂ > i.ψx + i.grad_ψᵀp +
real_t(0.5) * i.L * i.pᵀp + margin;
136 auto eval_ψ_grad_ψ = [&problem, &y, &Σ, &work_n1, &work_m](Iterate &i) {
137 i.ψx = problem.eval_augmented_lagrangian_and_gradient(
138 i.x, y, Σ, i.grad_ψ, work_n1, work_m);
140 auto eval_augmented_lagrangian_gradient = [&problem, &y, &Σ, &work_n1,
141 &work_m](Iterate &i) {
142 problem.eval_augmented_lagrangian_gradient(i.x, y, Σ, i.grad_ψ, work_n1,
145 auto eval_prox_grad_step = [&problem](Iterate &i) {
147 problem.eval_proximal_gradient_step(i.γ, i.x, i.grad_ψ, i.x̂, i.p);
148 i.pᵀp = i.p.squaredNorm();
149 i.grad_ψᵀp = i.p.dot(i.grad_ψ);
151 auto eval_ψx̂ = [&problem, &y, &Σ](Iterate &i) {
152 i.ψx̂ = problem.eval_augmented_lagrangian(i.x̂, y, Σ, i.ŷx̂);
154 auto eval_grad_ψx̂ = [&problem, &work_n1](Iterate &i) {
156 problem.eval_lagrangian_gradient(i.x̂, i.ŷx̂, i.grad_ψx̂, work_n1);
161 std::array<char, 64> print_buf;
162 auto print_real = [
this, &print_buf](
real_t x) {
163 return float_to_str_vw(print_buf, x,
params.print_precision);
165 auto print_progress_1 = [&print_real,
os](
unsigned k,
real_t ψₖ,
169 *
os <<
"┌─[FISTA]\n";
171 *
os <<
"├─ " << std::setw(6) << k <<
'\n';
172 *
os <<
"| ψ = " << print_real(ψₖ)
173 <<
", ‖∇ψ‖ = " << print_real(grad_ψₖ.norm())
174 <<
", ‖p‖ = " << print_real(std::sqrt(pₖᵀpₖ))
175 <<
", γ = " << print_real(γₖ)
176 <<
", ε = " << print_real(εₖ) <<
'\n';
179 *
os <<
"└─ " << status <<
" ──"
183 auto do_progress_cb = [
this, &s, &problem, &Σ, &y,
202 .grad_ψ_hat = it.grad_ψx̂,
209 .outer_iter = opts.outer_iter,
224 if (fixed_lipschitz) {
227 eval_augmented_lagrangian_gradient(*curr);
230 else if (
params.Lipschitz.L_0 <= 0) {
232 problem, curr->x, y, Σ,
params.Lipschitz.ε,
params.Lipschitz.δ,
234 curr->ψx, curr->grad_ψ,
235 curr->x̂, work_n1, work_n2, work_m);
239 curr->L =
params.Lipschitz.L_0;
241 eval_ψ_grad_ψ(*curr);
243 if (not std::isfinite(curr->L)) {
247 curr->γ =
params.Lipschitz.Lγ_factor / curr->L;
255 unsigned no_progress = 0;
264 prev_x̂.swap(curr->x̂);
265 eval_prox_grad_step(*curr);
268 if (!fixed_lipschitz || need_grad_ψx̂)
271 eval_grad_ψx̂(*curr);
275 while (curr->L <
params.L_max && qub_violated(*curr)) {
278 eval_prox_grad_step(*curr);
286 if (no_progress > 0 || k %
params.max_no_progress == 0)
287 no_progress = curr->x̂ == prev_x̂ ? no_progress + 1 : 0;
290 problem,
params.stop_crit, curr->p, curr->γ, curr->x, curr->x̂,
291 curr->ŷx̂, curr->grad_ψ, curr->grad_ψx̂, work_n1, work_n2);
293 auto time_elapsed = std::chrono::steady_clock::now() - start_time;
300 do_progress_cb(k, *curr, t, εₖ, stop_status);
301 if (
params.print_interval) {
302 print_progress_1(k, curr->ψx, curr->grad_ψ, curr->pᵀp, curr->γ,
304 print_progress_n(stop_status);
307 if (fixed_lipschitz && !need_grad_ψx̂)
311 opts.always_overwrite_results) {
313 if (err_z.size() > 0)
314 err_z = (ŷ - y).cwiseQuotient(Σ);
320 s.
elapsed_time = duration_cast<nanoseconds>(time_elapsed);
331 params.print_interval != 0 && k %
params.print_interval == 0;
333 print_progress_1(k, curr->ψx, curr->grad_ψ, curr->pᵀp, curr->γ, εₖ);
342 real_t t_new = (1 + std::sqrt(1 + 4 * t)) / 2;
343 real_t t_prev = std::exchange(t, t_new);
345 if (
params.disable_acceleration)
348 curr->x = curr->x̂ + ((t_prev - 1) / t) * (curr->x̂ - prev_x̂);
351 eval_augmented_lagrangian_gradient(*curr);
353 eval_ψ_grad_ψ(*curr);
358 throw std::logic_error(
"[FISTA] loop error");