15using std::chrono::duration_cast;
16using std::chrono::microseconds;
26 bool always_overwrite_results,
34 auto start_time = std::chrono::steady_clock::now();
57 grad_̂ψₖ(need_grad_̂ψₖ ?
n : 0),
60 vec work_n(
n), work_m(
m);
65 using indexvec = std::vector<vec::Index>;
71 unsigned no_progress = 0;
72 unsigned last_γ_change = 0;
101 xₖ, ψₖ, grad_ψₖ,
y,
Σ, x̂ₖ, pₖ, ŷx̂ₖ, ψx̂ₖ, pₖᵀpₖ, grad_ψₖᵀpₖ, Lₖ, γₖ);
105 std::cout <<
"[PANOC] " << std::setw(6) << k
106 <<
": ψ = " << std::setw(13) << ψₖ
107 <<
", ‖∇ψ‖ = " << std::setw(13) << grad_ψₖ.norm()
108 <<
", ‖p‖ = " << std::setw(13) << std::sqrt(pₖᵀpₖ)
109 <<
", γ = " << std::setw(13) << γₖ
110 <<
", εₖ = " << std::setw(13) << εₖ <<
"\r\n";
121 ψₖ, grad_ψₖ, x̂ₖ, grad_ψₖ₊₁, work_n, work_m);
129 if (not std::isfinite(Lₖ)) {
139 calc_x̂(γₖ, xₖ, grad_ψₖ, x̂ₖ, pₖ);
142 real_t grad_ψₖᵀpₖ = grad_ψₖ.dot(pₖ);
143 real_t pₖᵀpₖ = pₖ.squaredNorm();
145 real_t φₖ = ψₖ + 1 / (2 * γₖ) * pₖᵀpₖ + grad_ψₖᵀpₖ;
153 bool force_qub_check =
false;
154 bool skip_qub_check =
false;
158 problem, xₖ,
y,
Σ, grad_ψₖ, grad_ψₖ, HqK, work_n, work_n2,
160 real_t η = grad_ψₖ.squaredNorm() / grad_ψₖ.dot(HqK);
168 calc_x̂(γₖ₊₁, xₖ, grad_ψₖ, x̂ₖ₊₁, pₖ₊₁);
170 real_t grad_ψₖ₊₁ᵀpₖ₊₁ = grad_ψₖ.dot(pₖ₊₁);
171 real_t pₖ₊₁ᵀpₖ₊₁ = pₖ₊₁.squaredNorm();
175 real_t margin = (1 + std::abs(ψₖ)) *
177 constexpr bool always_accept =
false;
178 if (always_accept || ψx̂ₖ₊₁ - ψₖ <= grad_ψₖ₊₁ᵀpₖ₊₁ +
179 0.5 * Lₖ₊₁ * pₖ₊₁ᵀpₖ₊₁ +
186 grad_ψₖᵀpₖ = grad_ψₖ₊₁ᵀpₖ₊₁;
190 φₖ = ψₖ + 1 / (2 * γₖ) * pₖᵀpₖ + grad_ψₖᵀpₖ;
192 skip_qub_check = not always_accept;
193 force_qub_check = always_accept;
205 if ((qub_check && !skip_qub_check) || force_qub_check) {
210 ψx̂ₖ, pₖᵀpₖ, grad_ψₖᵀpₖ, Lₖ, γₖ);
213 φₖ = ψₖ + 1 / (2 * γₖ) * pₖᵀpₖ + grad_ψₖᵀpₖ;
228 progress_cb({k, xₖ, pₖ, pₖᵀpₖ, x̂ₖ, φₖ, ψₖ, grad_ψₖ, ψx̂ₖ, grad_̂ψₖ,
231 auto time_elapsed = std::chrono::steady_clock::now() - start_time;
241 always_overwrite_results) {
248 s.
elapsed_time = duration_cast<microseconds>(time_elapsed);
258 for (vec::Index i = 0; i <
n; ++i) {
259 real_t gd = xₖ(i) - γₖ * grad_ψₖ(i);
260 if (gd <
problem.C.lowerbound(i)) {
262 }
else if (
problem.C.upperbound(i) < gd) {
276 problem, xₖ,
y,
Σ, grad_ψₖ, qₖ, HqK, work_n,
279 problem.hess_L_prod(xₖ,
y, qₖ, HqK);
283 for (vec::Index i = 0; i <
m; ++i) {
285 bool inactive =
problem.D.lowerbound(i) < ζ &&
288 problem.grad_gi(xₖ, i, work_n);
289 auto t =
Σ(i) * work_n.dot(qₖ);
293 HqK(j) += work_n(j) *
t;
300 qₖ(j) = -grad_ψₖ(j) - HqK(j);
328 real_t σₖγₖ⁻¹pₖᵀpₖ = (1 - γₖ * Lₖ) * pₖᵀpₖ / (2 * γₖ);
329 real_t φₖ₊₁, ψₖ₊₁, ψx̂ₖ₊₁, grad_ψₖ₊₁ᵀpₖ₊₁, pₖ₊₁ᵀpₖ₊₁;
333 nmΦₖ = k == 0 ? φₖ :
w * nmΦₖ + (1 -
w) * φₖ;
341 }
else if (not qₖ.allFinite()) {
344 }
else if (J.empty()) {
349 unsigned last_γ_changeₖ₊₁;
351 last_γ_changeₖ₊₁ = last_γ_change;
360 grad_ψₖ₊₁.swap(grad_̂ψₖ);
367 xₖ₊₁ = xₖ + (1 - τ) * pₖ + τ * qₖ;
373 calc_x̂(γₖ₊₁, xₖ₊₁, grad_ψₖ₊₁, x̂ₖ₊₁, pₖ₊₁);
378 grad_ψₖ₊₁ᵀpₖ₊₁ = grad_ψₖ₊₁.dot(pₖ₊₁);
379 pₖ₊₁ᵀpₖ₊₁ = pₖ₊₁.squaredNorm();
380 real_t pₖ₊₁ᵀpₖ₊₁_ₖ = pₖ₊₁ᵀpₖ₊₁;
385 xₖ₊₁, ψₖ₊₁, grad_ψₖ₊₁,
387 ψx̂ₖ₊₁, pₖ₊₁ᵀpₖ₊₁, grad_ψₖ₊₁ᵀpₖ₊₁, Lₖ₊₁, γₖ₊₁);
388 if (old_γₖ₊₁ != γₖ₊₁)
389 last_γ_changeₖ₊₁ = k;
393 φₖ₊₁ = ψₖ₊₁ + 1 / (2 * γₖ₊₁) * pₖ₊₁ᵀpₖ₊₁ + grad_ψₖ₊₁ᵀpₖ₊₁;
395 ls_cond = φₖ₊₁ - (nmΦₖ - σₖγₖ⁻¹pₖᵀpₖ);
397 ls_cond -= (0.5 / γₖ₊₁ - 0.5 / γₖ) * pₖ₊₁ᵀpₖ₊₁_ₖ;
416 no_progress = xₖ == xₖ₊₁ ? no_progress + 1 : 0;
419 const bool force =
true;
424 last_γ_change = last_γ_changeₖ₊₁;
436 grad_ψₖ.swap(grad_ψₖ₊₁);
437 grad_ψₖᵀpₖ = grad_ψₖ₊₁ᵀpₖ₊₁;
440 throw std::logic_error(
"[PANOC] loop error");
bool apply(Vec &&q, real_t γ)
Apply the inverse Hessian approximation to the given vector q.
bool update(crvec xₖ, crvec xₖ₊₁, crvec pₖ, crvec pₖ₊₁, Sign sign, bool forced=false)
Update the inverse Hessian approximation using the new vectors xₖ₊₁ and pₖ₊₁.
void resize(size_t n)
Re-allocate storage for a problem with a different size.
std::function< void(const ProgressInfo &)> progress_cb
AtomicStopSignal stop_signal
Stats operator()(const Problem &problem, crvec Σ, real_t ε, bool always_overwrite_results, rvec x, rvec y, rvec err_z)
real_t calc_error_stop_crit(const Box &C, PANOCStopCrit crit, crvec pₖ, real_t γ, crvec xₖ, crvec x̂ₖ, crvec ŷₖ, crvec grad_ψₖ, crvec grad_̂ψₖ)
Compute the ε from the stopping criterion, see PANOCStopCrit.
SolverStatus check_all_stop_conditions(const ParamsT ¶ms, DurationT time_elapsed, unsigned iteration, const AtomicStopSignal &stop_signal, real_t ε, real_t εₖ, unsigned no_progress)
Check all stop conditions (required tolerance reached, out of time, maximum number of iterations exce...
real_t calc_ψ_ŷ(const Problem &p, crvec x, crvec y, crvec Σ, rvec ŷ)
Calculate both ψ(x) and the vector ŷ that can later be used to compute ∇ψ.
real_t descent_lemma(const Problem &problem, real_t rounding_tolerance, real_t L_max, crvec xₖ, real_t ψₖ, crvec grad_ψₖ, crvec y, crvec Σ, rvec x̂ₖ, rvec pₖ, rvec ŷx̂ₖ, real_t &ψx̂ₖ, real_t &norm_sq_pₖ, real_t &grad_ψₖᵀpₖ, real_t &Lₖ, real_t &γₖ)
Increase the estimate of the Lipschitz constant of the objective gradient and decrease the step size ...
bool stop_crit_requires_grad_̂ψₖ(PANOCStopCrit crit)
real_t calc_ψ_grad_ψ(const Problem &p, crvec x, crvec y, crvec Σ, rvec grad_ψ, rvec work_n, rvec work_m)
Calculate both ψ(x) and its gradient ∇ψ(x).
void calc_err_z(const Problem &p, crvec x̂, crvec y, crvec Σ, rvec err_z)
Calculate the error between ẑ and g(x).
real_t initial_lipschitz_estimate(const Problem &problem, crvec xₖ, crvec y, crvec Σ, real_t ε, real_t δ, real_t L_min, real_t L_max, real_t &ψ, rvec grad_ψ, rvec work_n1, rvec work_n2, rvec work_n3, rvec work_m)
Estimate the Lipschitz constant of the gradient using finite differences.
void calc_augmented_lagrangian_hessian_prod_fd(const Problem &problem, crvec xₖ, crvec y, crvec Σ, crvec grad_ψ, crvec v, rvec Hv, rvec work_n1, rvec work_n2, rvec work_m)
Compute the Hessian matrix of the augmented Lagrangian function multiplied by the given vector,...
void calc_grad_ψ_from_ŷ(const Problem &p, crvec x, crvec ŷ, rvec grad_ψ, rvec work_n)
Calculate ∇ψ(x) using ŷ.
void calc_x̂(const Problem &prob, real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p)
void print_progress(unsigned k, real_t ψₖ, crvec grad_ψₖ, real_t pₖᵀpₖ, real_t γₖ, real_t εₖ)
LipschitzEstimateParams Lipschitz
Parameters related to the Lipschitz constant estimate and step size.
real_t Lγ_factor
Factor that relates step size γ and Lipschitz constant.
bool alternative_linesearch_cond
Eigen::Ref< const vec > crvec
Default type for immutable references to vectors.
real_t δ
Minimum step size for initial finite difference Lipschitz estimate.
constexpr real_t NaN
Not a number.
bool update_lipschitz_in_linesearch
unsigned max_no_progress
Maximum number of iterations without any progress before giving up.
real_t L_max
Maximum Lipschitz constant estimate.
bool full_augmented_hessian
@ Interrupted
Solver was interrupted by the user.
@ Converged
Converged and reached given tolerance.
@ NotFinite
Intermediate results were infinite or not-a-number.
bool hessian_vec_finite_differences
realvec vec
Default type for vectors.
real_t ε
Relative step size for initial finite difference Lipschitz estimate.
real_t L₀
Initial estimate of the Lipschitz constant of ∇ψ(x)
real_t quadratic_upperbound_tolerance_factor
std::chrono::microseconds elapsed_time
double real_t
Default floating point type.
unsigned linesearch_failures
unsigned print_interval
When to print progress.
real_t τ_min
Minimum weight factor between Newton step and projected gradient step.
real_t L_min
Minimum Lipschitz constant estimate.
LBFGSStepSize lbfgs_stepsize
@ BasedOnGradientStepSize
unsigned max_iter
Maximum number of inner PANOC iterations.
PANOCStopCrit stop_crit
What stopping criterion to use.
Eigen::Ref< vec > rvec
Default type for mutable references to vectors.
unsigned hessian_step_size_heuristic
real_t nonmonotone_linesearch
Factor used in update for exponentially weighted nonmonotone line search.
Problem description for minimization problems.