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);
218 switch (params.stop_crit) {
223 return std::sqrt(
pₖᵀpₖ);
232 return std::sqrt(
pTp);
235 return norm_inf(
pₖ) / γ;
238 return std::sqrt(
pₖᵀpₖ) / γ;
245 throw std::invalid_argument(
"Unsupported stopping criterion");
249 auto check_all_stop_conditions =
259 auto max_time = params.max_time;
261 max_time = std::min(max_time, *
opts.max_time);
262 auto tolerance =
opts.tolerance > 0 ?
opts.tolerance :
real_t(1e-8);
267 bool conv =
εₖ <= tolerance;
268 bool max_no_progress =
no_progress > params.max_no_progress;
278 auto assign_interleave_xu = [&vars](
crvec u,
rvec xu) {
281 auto assign_extract_u = [&vars](
crvec xu,
rvec u) {
287 if (nc > 0 || nc_N > 0) {
288 for (
index_t t = 0; t < N; ++t) {
289 auto ct = vars.ck(it.xû, t);
290 auto yt = y.segment(nc * t, nc);
291 auto μt =
μ.segment(nc * t, nc);
292 auto ζ =
ct +
μt.asDiagonal().inverse() *
yt;
293 auto et =
err_z.segment(nc * t, nc);
294 et = projecting_difference(ζ, D);
295 et -=
μt.asDiagonal().inverse() *
yt;
296 yt +=
μt.asDiagonal() *
et;
298 auto ct = vars.ck(it.xû, N);
299 auto yt = y.segment(nc * N, nc_N);
300 auto μt =
μ.segment(nc * N, nc_N);
301 auto ζ =
ct +
μt.asDiagonal().inverse() *
yt;
302 auto et =
err_z.segment(nc * N, nc_N);
303 et = projecting_difference(ζ, D_N);
304 et -=
μt.asDiagonal().inverse() *
yt;
305 yt +=
μt.asDiagonal() *
et;
307 assign_extract_u(it.xû, u);
314 std::tie(i.pᵀp, i.grad_ψᵀp) =
322 i.ψu =
eval.forward(i.xu, D, D_N,
μ, y);
328 i.ψû =
eval.forward(i.xû, D, D_N,
μ, y);
340 (1 + std::abs(i.ψu)) * params.quadratic_upperbound_tolerance_factor;
341 return i.ψû > i.ψu + i.grad_ψᵀp +
real_t(0.5) * i.L * i.pᵀp +
margin;
346 real_t β = params.linesearch_strictness_factor;
349 real_t margin = (1 + std::abs(φγ)) * params.linesearch_tolerance_factor;
353 auto initial_lipschitz_estimate =
373 auto h = it->grad_ψ.unaryExpr([&](
real_t g) {
374 return g > 0 ? std::max(g * ε, δ) : std::min(g * ε, -δ);
378 for (
index_t t = 0; t < N; ++t)
380 vars.uk(it->xu, t) - h.segment(t * nu, nu);
393 it->L = std::clamp(it->L, L_min, L_max);
408 *os <<
"┌─[PANOCOCP]\n";
410 *os <<
"├─ " << std::setw(6) << k <<
'\n';
420 const char *
color =
τₖ == 1 ?
"\033[0;32m"
421 :
τₖ > 0 ?
"\033[0;33m"
424 <<
", #J = " << std::setw(7 + params.print_precision) << nJ
427 <<
", " << (
did_gn ?
"GN" :
"L-BFGS")
429 << (
reject ?
"\033[0;31mrejected\033[0m"
430 :
"\033[0;32maccepted\033[0m")
434 *os <<
"└─ " << status <<
" ──"
451 .norm_sq_p =
curr.pᵀp,
455 .grad_ψ =
curr.grad_ψ,
460 .lqr_min_rcond =
lqr.min_rcond,
465 .outer_iter =
opts.outer_iter,
473 assign_interleave_xu(u,
curr->xu);
474 problem.get_x_init(
curr->xu.topRows(nx));
475 curr->xû.topRows(nx) =
curr->xu.topRows(nx);
476 next->xu.topRows(nx) =
curr->xu.topRows(nx);
477 next->xû.topRows(nx) =
curr->xu.topRows(nx);
483 problem.get_D_N(D_N);
485 bool do_gn_step = params.gn_interval > 0
and !params.disable_acceleration;
494 if (params.Lipschitz.L_0 <= 0) {
495 initial_lipschitz_estimate(
curr, params.Lipschitz.ε, params.Lipschitz.δ,
496 params.L_min, params.L_max,
next->xu,
501 curr->L = params.Lipschitz.L_0;
506 if (
not std::isfinite(
curr->L)) {
510 curr->γ = params.Lipschitz.Lγ_factor /
curr->L;
544 params.print_interval != 0 && k % params.print_interval == 0;
565 opts.always_overwrite_results) {
584 if (params.disable_acceleration) {
607 nJ =
J.sizes().sum();
611 for (
index_t t = 0; t < N; ++t)
612 problem.eval_jac_f(t, vars.xk(
curr->xu, t),
613 vars.uk(
curr->xu, t), vars.ABk(
jacs, t));
618 Rk_prod(
curr->xu), Sk_prod(
curr->xu), qk, rk,
619 uk_eq,
Jk,
Kk, params.lqr_factor_cholesky);
627 throw std::logic_error(
"enable_lbfgs");
639 q(t * nu + i) =
curr->p(t * nu + i);
651 for (
index_t t = 0; t < N; ++t)
652 for (
index_t i = 0; i < nu; ++i)
654 J_idx(nJ++) = t * nu + i;
672 if (
not q.allFinite()) {
681 ((k + 1) % params.gn_interval) == 0 &&
682 !params.disable_acceleration;
704 for (
index_t t = 0; t < N; ++t)
705 vars.uk(
next->xu, t) =
706 vars.uk(
curr->xu, t) + q.segment(t * nu, nu);
709 for (
index_t t = 0; t < N; ++t)
710 vars.uk(
next->xu, t) =
711 vars.uk(
curr->xu, t) +
712 (1 - τ) *
curr->p.segment(t * nu, nu) +
713 τ * q.segment(t * nu, nu);
721 while (!stop_signal.stop_requested()) {
732 bool fail =
next->L >= params.L_max || !std::isfinite(
next->ψu);
762 if (τ < params.min_linesearch_coefficient)
779 if (
no_progress > 0 || k % params.max_no_progress == 0)
785 const bool force =
true;
786 assign_extract_u(
next->xu,
next->u);
808 throw std::logic_error(
"[PANOC] loop error");