63 using std::chrono::nanoseconds;
64 auto os =
opts.os ?
opts.os : this->os;
65 auto start_time = std::chrono::steady_clock::now();
68 const auto N = problem.get_N();
69 const auto nu = problem.get_nu();
70 const auto nx = problem.get_nx();
71 const auto nc = problem.get_nc();
72 const auto nc_N = problem.get_nc_N();
73 const auto n = nu * N;
89 vec qr = vars.create_qr();
100 assert(
μ.size() == nc * N + nc_N);
101 assert(y.size() == nc * N + nc_N);
105 auto Qk = [&](
rvec storage) {
106 return [&, storage](
index_t k) {
107 return [&, k](
rmat out) {
109 return eval.Qk(storage, y,
μ, D, D_N, k, out);
113 auto Rk = [&](
rvec storage) {
114 return [&, storage](
index_t k) {
117 return eval.Rk(storage, k,
mask, out);
121 auto Sk = [&](
rvec storage) {
122 return [&, storage](
index_t k) {
125 return eval.Sk(storage, k,
mask, out);
129 auto Rk_prod = [&](
rvec storage) {
130 return [&, storage](
index_t k) {
138 auto Sk_prod = [&](
rvec storage) {
139 return [&, storage](
index_t k) {
147 auto mut_q_N = [&]() ->
rvec {
return vars.qk(qr, N); };
148 auto qk = [&](
index_t k) ->
crvec {
return vars.qk(qr, k); };
149 auto rk = [&](
index_t k) ->
crvec {
return vars.rk(qr, k); };
201 for (
index_t t = 0; t < N; ++t) {
202 auto &&
grad_ψ_t = grad_ψ.segment(t * nu, nu);
203 auto &&
p_t = p.segment(t * nu, nu);
204 eval_proj_grad_step_box(γ, vars.uk(xu, t),
grad_ψ_t,
205 vars.uk(x̂u, t),
p_t);
217 switch (params.stop_crit) {
222 return std::sqrt(
pₖᵀpₖ);
231 return std::sqrt(
pTp);
237 return std::sqrt(
pₖᵀpₖ) / γ;
244 throw std::invalid_argument(
"Unsupported stopping criterion");
248 auto check_all_stop_conditions =
258 auto max_time = params.max_time;
260 max_time = std::min(max_time, *
opts.max_time);
261 auto tolerance =
opts.tolerance > 0 ?
opts.tolerance :
real_t(1e-8);
266 bool conv =
εₖ <= tolerance;
267 bool max_no_progress =
no_progress > params.max_no_progress;
277 auto assign_interleave_xu = [&vars](
crvec u,
rvec xu) {
280 auto assign_extract_u = [&vars](
crvec xu,
rvec u) {
286 if (nc > 0 || nc_N > 0) {
287 for (
index_t t = 0; t < N; ++t) {
288 auto ct = vars.ck(it.xû, t);
289 auto yt = y.segment(nc * t, nc);
290 auto μt =
μ.segment(nc * t, nc);
291 auto ζ =
ct +
μt.asDiagonal().inverse() *
yt;
292 auto et =
err_z.segment(nc * t, nc);
293 et = projecting_difference(
ζ, D);
294 et -=
μt.asDiagonal().inverse() *
yt;
295 yt +=
μt.asDiagonal() *
et;
297 auto ct = vars.ck(it.xû, N);
298 auto yt = y.segment(nc * N, nc_N);
299 auto μt =
μ.segment(nc * N, nc_N);
300 auto ζ =
ct +
μt.asDiagonal().inverse() *
yt;
301 auto et =
err_z.segment(nc * N, nc_N);
302 et = projecting_difference(
ζ, D_N);
303 et -=
μt.asDiagonal().inverse() *
yt;
304 yt +=
μt.asDiagonal() *
et;
306 assign_extract_u(it.xû, u);
313 std::tie(i.pᵀp, i.grad_ψᵀp) =
321 i.ψu =
eval.forward(i.xu, D, D_N,
μ, y);
327 i.ψû =
eval.forward(i.xû, D, D_N,
μ, y);
339 (1 + std::abs(i.ψu)) * params.quadratic_upperbound_tolerance_factor;
340 return i.ψû > i.ψu + i.grad_ψᵀp +
real_t(0.5) * i.L * i.pᵀp +
margin;
345 real_t β = params.linesearch_strictness_factor;
348 real_t margin = (1 + std::abs(φγ)) * params.linesearch_tolerance_factor;
352 auto initial_lipschitz_estimate =
372 auto h = it->grad_ψ.unaryExpr([&](
real_t g) {
373 return g > 0 ? std::max(g * ε, δ) : std::min(g * ε, -δ);
377 for (
index_t t = 0; t < N; ++t)
379 vars.uk(it->xu, t) - h.segment(t * nu, nu);
392 it->L = std::clamp(it->L, L_min, L_max);
407 *os <<
"┌─[PANOCOCP]\n";
409 *os <<
"├─ " << std::setw(6) << k <<
'\n';
419 const char *
color =
τₖ == 1 ?
"\033[0;32m"
420 :
τₖ > 0 ?
"\033[0;33m"
423 <<
", #J = " << std::setw(7 + params.print_precision) << nJ
426 <<
", " << (
did_gn ?
"GN" :
"L-BFGS")
428 << (
reject ?
"\033[0;31mrejected\033[0m"
429 :
"\033[0;32maccepted\033[0m")
433 *os <<
"└─ " << status <<
" ──"
450 .norm_sq_p =
curr.pᵀp,
454 .grad_ψ =
curr.grad_ψ,
459 .lqr_min_rcond =
lqr.min_rcond,
464 .outer_iter =
opts.outer_iter,
472 assign_interleave_xu(u,
curr->xu);
473 problem.get_x_init(
curr->xu.topRows(nx));
474 curr->xû.topRows(nx) =
curr->xu.topRows(nx);
475 next->xu.topRows(nx) =
curr->xu.topRows(nx);
476 next->xû.topRows(nx) =
curr->xu.topRows(nx);
482 problem.get_D_N(D_N);
484 bool do_gn_step = params.gn_interval > 0
and !params.disable_acceleration;
493 if (params.Lipschitz.L_0 <= 0) {
494 initial_lipschitz_estimate(
curr, params.Lipschitz.ε, params.Lipschitz.δ,
495 params.L_min, params.L_max,
next->xu,
500 curr->L = params.Lipschitz.L_0;
505 if (
not std::isfinite(
curr->L)) {
509 curr->γ = params.Lipschitz.Lγ_factor /
curr->L;
543 params.print_interval != 0 && k % params.print_interval == 0;
564 opts.always_overwrite_results) {
583 if (params.disable_acceleration) {
606 nJ =
J.sizes().sum();
610 for (
index_t t = 0; t < N; ++t)
611 problem.eval_jac_f(t, vars.xk(
curr->xu, t),
612 vars.uk(
curr->xu, t), vars.ABk(
jacs, t));
617 Rk_prod(
curr->xu), Sk_prod(
curr->xu), qk, rk,
618 uk_eq,
Jk,
Kk, params.lqr_factor_cholesky);
626 throw std::logic_error(
"enable_lbfgs");
638 q(t * nu + i) =
curr->p(t * nu + i);
650 for (
index_t t = 0; t < N; ++t)
651 for (
index_t i = 0; i < nu; ++i)
653 J_idx(nJ++) = t * nu + i;
671 if (
not q.allFinite()) {
680 ((k + 1) % params.gn_interval) == 0 &&
681 !params.disable_acceleration;
703 for (
index_t t = 0; t < N; ++t)
704 vars.uk(
next->xu, t) =
705 vars.uk(
curr->xu, t) + q.segment(t * nu, nu);
708 for (
index_t t = 0; t < N; ++t)
709 vars.uk(
next->xu, t) =
710 vars.uk(
curr->xu, t) +
711 (1 - τ) *
curr->p.segment(t * nu, nu) +
712 τ * q.segment(t * nu, nu);
720 while (!stop_signal.stop_requested()) {
731 bool fail =
next->L >= params.L_max || !std::isfinite(
next->ψu);
761 if (τ < params.min_linesearch_coefficient)
778 if (
no_progress > 0 || k % params.max_no_progress == 0)
784 const bool force =
true;
785 assign_extract_u(
next->xu,
next->u);
807 throw std::logic_error(
"[PANOC] loop error");