19template <
class ObjFunT,
class ObjGradFunT>
24 const ObjGradFunT &grad_ψ,
42 auto h = (xₖ *
ε).cwiseAbs().cwiseMax(δ);
43 auto xh = alloc.
alloc() = xₖ + h;
45 auto grad_ψxh = alloc.
alloc();
53 real_t L = (grad_ψxh - grad_ψₖ).norm() / norm_h;
54 alloc.
free(xh, grad_ψxh);
55 return std::clamp(
L, L_min, L_max);
81template <
class ObjFunT>
119 real_t margin = (1 + std::abs(ψₖ)) * rounding_tolerance;
120 while (ψx̂ₖ - ψₖ > grad_ψₖᵀpₖ + 0.5 * Lₖ * norm_sq_pₖ + margin) {
121 if (not(Lₖ * 2 <= L_max))
128 calc_x̂(γₖ, xₖ,
C, grad_ψₖ, x̂ₖ, pₖ);
130 grad_ψₖᵀpₖ = grad_ψₖ.dot(pₖ);
131 norm_sq_pₖ = pₖ.squaredNorm();
141 std::cout <<
"[PANOC] " << std::setw(6) << k
142 <<
": ψ = " << std::setw(13) << ψₖ
143 <<
", ‖∇ψ‖ = " << std::setw(13) << grad_ψₖ.norm()
144 <<
", ‖p‖ = " << std::setw(13) << std::sqrt(pₖᵀpₖ)
145 <<
", γ = " << std::setw(13) << γₖ
146 <<
", εₖ = " << std::setw(13) << εₖ <<
"\r\n";
151using std::chrono::duration_cast;
152using std::chrono::microseconds;
156template <
class ObjFunT,
class ObjGradFunT,
class DirectionT>
160 DirectionT &direction_provider) {
161 auto start_time = std::chrono::steady_clock::now();
165 unsigned no_progress = 0;
173 auto grad_ψₖ = alloc.
alloc();
174 auto xₖ = alloc.
alloc() =
x;
176 if (
params.Lipschitz.L₀ <= 0) {
179 params.L_max, ψₖ, grad_ψₖ, alloc);
188 if (not std::isfinite(Lₖ)) {
197 auto x̂ₖ = alloc.
alloc(), pₖ = alloc.
alloc(), grad_̂ψₖ = alloc.
alloc();
198 auto xₖ₊₁ = alloc.
alloc(), qₖ = alloc.
alloc(), grad_ψₖ₊₁ = alloc.
alloc();
199 auto x̂ₖ₊₁ = alloc.
alloc(), pₖ₊₁ = alloc.
alloc();
205 real_t grad_ψₖᵀpₖ = grad_ψₖ.dot(pₖ);
206 real_t pₖᵀpₖ = pₖ.squaredNorm();
208 real_t φₖ = ψₖ + 1 / (2 * γₖ) * pₖᵀpₖ + grad_ψₖᵀpₖ;
212 for (
unsigned k = 0; k <=
params.max_iter; ++k) {
215 if (k == 0 ||
params.update_lipschitz_in_linesearch ==
false) {
218 ψ,
C,
params.quadratic_upperbound_tolerance_factor,
219 params.L_max, xₖ, ψₖ, grad_ψₖ,
221 ψx̂ₖ, pₖᵀpₖ, grad_ψₖᵀpₖ, Lₖ, γₖ);
222 if (k > 0 && γₖ != old_γₖ)
223 direction_provider.changed_γ(γₖ, old_γₖ);
225 direction_provider.initialize(xₖ, x̂ₖ, pₖ, grad_ψₖ);
227 φₖ = ψₖ + 1 / (2 * γₖ) * pₖᵀpₖ + grad_ψₖᵀpₖ;
230 grad_ψ(x̂ₖ, grad_̂ψₖ);
233 C,
params.stop_crit, pₖ, γₖ, xₖ, x̂ₖ,
vec(), grad_ψₖ, grad_̂ψₖ);
236 if (
params.print_interval != 0 && k %
params.print_interval == 0)
239 auto time_elapsed = std::chrono::steady_clock::now() - start_time;
241 params, time_elapsed, k, stop_signal,
ε, εₖ, no_progress);
246 s.
elapsed_time = duration_cast<microseconds>(time_elapsed);
248 alloc.
free(grad_ψₖ, xₖ, x̂ₖ, pₖ, grad_̂ψₖ, xₖ₊₁, qₖ, grad_ψₖ₊₁, x̂ₖ₊₁,
258 direction_provider.apply(xₖ, x̂ₖ, pₖ, step_size,
263 real_t σₖγₖ⁻¹pₖᵀpₖ = (1 - γₖ * Lₖ) * pₖᵀpₖ / (2 * γₖ);
264 real_t φₖ₊₁, ψₖ₊₁, ψx̂ₖ₊₁, grad_ψₖ₊₁ᵀpₖ₊₁, pₖ₊₁ᵀpₖ₊₁;
269 (1 + std::abs(φₖ)) *
params.quadratic_upperbound_tolerance_factor;
274 }
else if (not qₖ.allFinite()) {
277 direction_provider.reset();
286 if (τ / 2 <
params.τ_min) {
289 grad_ψₖ₊₁.swap(grad_̂ψₖ);
294 xₖ₊₁ = xₖ + (1 - τ) * pₖ + τ * qₖ;
297 grad_ψ(xₖ₊₁, grad_ψₖ₊₁);
306 grad_ψₖ₊₁ᵀpₖ₊₁ = grad_ψₖ₊₁.dot(pₖ₊₁);
307 pₖ₊₁ᵀpₖ₊₁ = pₖ₊₁.squaredNorm();
308 real_t pₖ₊₁ᵀpₖ₊₁_ₖ = pₖ₊₁ᵀpₖ₊₁;
310 if (
params.update_lipschitz_in_linesearch ==
true) {
313 ψ,
C,
params.quadratic_upperbound_tolerance_factor,
314 params.L_max, xₖ₊₁, ψₖ₊₁, grad_ψₖ₊₁,
316 ψx̂ₖ₊₁, pₖ₊₁ᵀpₖ₊₁, grad_ψₖ₊₁ᵀpₖ₊₁, Lₖ₊₁, γₖ₊₁);
320 φₖ₊₁ = ψₖ₊₁ + 1 / (2 * γₖ₊₁) * pₖ₊₁ᵀpₖ₊₁ + grad_ψₖ₊₁ᵀpₖ₊₁;
322 ls_cond = φₖ₊₁ - (φₖ - σₖγₖ⁻¹pₖᵀpₖ);
323 if (
params.alternative_linesearch_cond)
324 ls_cond -= (0.5 / γₖ₊₁ - 0.5 / γₖ) * pₖ₊₁ᵀpₖ₊₁_ₖ;
327 }
while (ls_cond > margin && τ >=
params.τ_min);
330 if (τ <
params.τ_min && k != 0) {
342 direction_provider.changed_γ(γₖ₊₁, γₖ);
344 s.
lbfgs_rejected += not direction_provider.update(xₖ, xₖ₊₁, pₖ, pₖ₊₁,
348 if (no_progress > 0 || k %
params.max_no_progress == 0)
349 no_progress = xₖ == xₖ₊₁ ? no_progress + 1 : 0;
362 grad_ψₖ.swap(grad_ψₖ₊₁);
363 grad_ψₖᵀpₖ = grad_ψₖ₊₁ᵀpₖ₊₁;
366 throw std::logic_error(
"[PANOC] loop error");
369template <
class DirectionProv
iderT = LBFGS,
class ObjFunT,
class ObjGradFunT>
375 throw std::logic_error(
"Allocator too small, should be at least " +
377 const auto n =
x.size();
379 throw std::logic_error(
"Allocator size mismatch");
384template <
class DirectionProv
iderT = LBFGS,
class ObjFunT,
class ObjGradFunT>
Eigen::Index vector_size() const
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 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 ...
auto projected_gradient_step(const Box &C, real_t γ, crvec x, crvec grad_ψ)
Projected gradient step.
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_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 εₖ)
Eigen::Ref< const vec > crvec
Default type for immutable references to vectors.
constexpr real_t NaN
Not a number.
PANOCStats panoc(ObjFunT &ψ, ObjGradFunT &grad_ψ, const Box &C, rvec x, real_t ε, const PANOCParams ¶ms, PANOCDirection< DirectionProviderT > direction, vec_allocator &alloc)
@ NotFinite
Intermediate results were infinite or not-a-number.
PANOCStats panoc_impl(ObjFunT &ψ, ObjGradFunT &grad_ψ, const Box &C, rvec x, real_t ε, const PANOCParams ¶ms, vec_allocator &alloc, DirectionT &direction_provider)
realvec vec
Default type for vectors.
constexpr size_t panoc_min_alloc_size
std::chrono::microseconds elapsed_time
double real_t
Default floating point type.
unsigned linesearch_failures
@ BasedOnGradientStepSize
Eigen::Ref< vec > rvec
Default type for mutable references to vectors.
Tuning parameters for the PANOC algorithm.