15using std::chrono::duration_cast;
16using std::chrono::microseconds;
18template <
class DirectionProv
iderT>
20 return "PANOCSolver<" + direction_provider.get_name() +
">";
23template <
class DirectionProv
iderT>
33 bool always_overwrite_results,
41 auto start_time = std::chrono::steady_clock::now();
64 grad_̂ψₖ(need_grad_̂ψₖ ?
n : 0),
67 vec work_n(
n), work_m(
m);
70 unsigned no_progress = 0;
99 xₖ, ψₖ, grad_ψₖ,
y,
Σ, x̂ₖ, pₖ, ŷx̂ₖ, ψx̂ₖ, pₖᵀpₖ, grad_ψₖᵀpₖ, Lₖ, γₖ);
103 std::cout <<
"[PANOC] " << std::setw(6) << k
104 <<
": ψ = " << std::setw(13) << ψₖ
105 <<
", ‖∇ψ‖ = " << std::setw(13) << grad_ψₖ.norm()
106 <<
", ‖p‖ = " << std::setw(13) << std::sqrt(pₖᵀpₖ)
107 <<
", γ = " << std::setw(13) << γₖ
108 <<
", εₖ = " << std::setw(13) << εₖ <<
"\r\n";
115 if (
params.Lipschitz.L₀ <= 0) {
119 ψₖ, grad_ψₖ, x̂ₖ, grad_ψₖ₊₁, work_n, work_m);
127 if (not std::isfinite(Lₖ)) {
137 calc_x̂(γₖ, xₖ, grad_ψₖ, x̂ₖ, pₖ);
140 real_t grad_ψₖᵀpₖ = grad_ψₖ.dot(pₖ);
141 real_t pₖᵀpₖ = pₖ.squaredNorm();
143 real_t φₖ = ψₖ + 1 / (2 * γₖ) * pₖᵀpₖ + grad_ψₖᵀpₖ;
147 for (
unsigned k = 0; k <=
params.max_iter; ++k) {
150 if (k == 0 ||
params.update_lipschitz_in_linesearch ==
false) {
155 ψx̂ₖ, pₖᵀpₖ, grad_ψₖᵀpₖ, Lₖ, γₖ);
156 if (k > 0 && γₖ != old_γₖ)
157 direction_provider.changed_γ(γₖ, old_γₖ);
159 direction_provider.initialize(xₖ, x̂ₖ, pₖ, grad_ψₖ);
161 φₖ = ψₖ + 1 / (2 * γₖ) * pₖᵀpₖ + grad_ψₖᵀpₖ;
169 problem.C,
params.stop_crit, pₖ, γₖ, xₖ, x̂ₖ, ŷx̂ₖ, grad_ψₖ, grad_̂ψₖ);
172 if (
params.print_interval != 0 && k %
params.print_interval == 0)
175 progress_cb({k, xₖ, pₖ, pₖᵀpₖ, x̂ₖ, φₖ, ψₖ, grad_ψₖ, ψx̂ₖ, grad_̂ψₖ,
178 auto time_elapsed = std::chrono::steady_clock::now() - start_time;
180 params, time_elapsed, k, stop_signal,
ε, εₖ, no_progress);
188 always_overwrite_results) {
195 s.
elapsed_time = duration_cast<microseconds>(time_elapsed);
206 direction_provider.apply(xₖ, x̂ₖ, pₖ, step_size,
211 real_t σₖγₖ⁻¹pₖᵀpₖ = (1 - γₖ * Lₖ) * pₖᵀpₖ / (2 * γₖ);
212 real_t φₖ₊₁, ψₖ₊₁, ψx̂ₖ₊₁, grad_ψₖ₊₁ᵀpₖ₊₁, pₖ₊₁ᵀpₖ₊₁;
217 (1 + std::abs(φₖ)) *
params.quadratic_upperbound_tolerance_factor;
222 }
else if (not qₖ.allFinite()) {
225 direction_provider.reset();
234 if (τ / 2 <
params.τ_min) {
238 grad_ψₖ₊₁.swap(grad_̂ψₖ);
245 xₖ₊₁ = xₖ + (1 - τ) * pₖ + τ * qₖ;
251 calc_x̂(γₖ₊₁, xₖ₊₁, grad_ψₖ₊₁, x̂ₖ₊₁, pₖ₊₁);
256 grad_ψₖ₊₁ᵀpₖ₊₁ = grad_ψₖ₊₁.dot(pₖ₊₁);
257 pₖ₊₁ᵀpₖ₊₁ = pₖ₊₁.squaredNorm();
258 real_t pₖ₊₁ᵀpₖ₊₁_ₖ = pₖ₊₁ᵀpₖ₊₁;
260 if (
params.update_lipschitz_in_linesearch ==
true) {
265 grad_ψₖ₊₁ᵀpₖ₊₁, Lₖ₊₁, γₖ₊₁);
269 φₖ₊₁ = ψₖ₊₁ + 1 / (2 * γₖ₊₁) * pₖ₊₁ᵀpₖ₊₁ + grad_ψₖ₊₁ᵀpₖ₊₁;
271 ls_cond = φₖ₊₁ - (φₖ - σₖγₖ⁻¹pₖᵀpₖ);
272 if (
params.alternative_linesearch_cond)
273 ls_cond -= (0.5 / γₖ₊₁ - 0.5 / γₖ) * pₖ₊₁ᵀpₖ₊₁_ₖ;
276 }
while (ls_cond > margin && τ >=
params.τ_min);
279 if (τ <
params.τ_min && k != 0) {
291 direction_provider.changed_γ(γₖ₊₁, γₖ);
294 xₖ, xₖ₊₁, pₖ, pₖ₊₁, grad_ψₖ₊₁,
problem.C, γₖ₊₁);
297 if (no_progress > 0 || k %
params.max_no_progress == 0)
298 no_progress = xₖ == xₖ₊₁ ? no_progress + 1 : 0;
312 grad_ψₖ.swap(grad_ψₖ₊₁);
313 grad_ψₖᵀpₖ = grad_ψₖ₊₁ᵀpₖ₊₁;
316 throw std::logic_error(
"[PANOC] loop error");
std::string get_name() const
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_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 εₖ)
Eigen::Ref< const vec > crvec
Default type for immutable references to vectors.
constexpr real_t NaN
Not a number.
@ Interrupted
Solver was interrupted by the user.
@ Converged
Converged and reached given tolerance.
@ NotFinite
Intermediate results were infinite or not-a-number.
realvec vec
Default type for vectors.
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.
Problem description for minimization problems.