363 proxsuite::linalg::veg::unsafe, kkt_unscaled, data.
dim);
376 H_unscaled.
to_eigen().template triangularView<Eigen::Upper>();
378 { proxsuite::linalg::sparse::from_eigen, H_triu },
379 { proxsuite::linalg::sparse::from_eigen, data.
g },
380 { proxsuite::linalg::sparse::from_eigen, AT_unscaled.
to_eigen() },
381 { proxsuite::linalg::sparse::from_eigen, data.
b },
382 { proxsuite::linalg::sparse::from_eigen, CT_unscaled.
to_eigen() },
383 { proxsuite::linalg::sparse::from_eigen, data.
l },
384 { proxsuite::linalg::sparse::from_eigen, data.
u }
396 precond.scale_primal_in_place(
397 { proxsuite::proxqp::from_eigen, results.
x });
398 precond.scale_dual_in_place_eq(
399 { proxsuite::proxqp::from_eigen, results.
y });
400 precond.scale_dual_in_place_in(
401 { proxsuite::proxqp::from_eigen, results.
z });
411 precond.scale_primal_in_place(
412 { proxsuite::proxqp::from_eigen,
414 precond.scale_dual_in_place_eq(
415 { proxsuite::proxqp::from_eigen, results.
y });
416 precond.scale_dual_in_place_in(
417 { proxsuite::proxqp::from_eigen, results.
z });
423 precond.scale_primal_in_place(
424 { proxsuite::proxqp::from_eigen, results.
x });
425 precond.scale_dual_in_place_eq(
426 { proxsuite::proxqp::from_eigen, results.
y });
427 precond.scale_dual_in_place_in(
428 { proxsuite::proxqp::from_eigen, results.
z });
438 P::scale_qp_in_place_req(
439 proxsuite::linalg::veg::Tag<T>{}, data.
dim, data.
n_eq, data.
n_in));
449 precond.scale_primal_in_place(
450 { proxsuite::proxqp::from_eigen,
453 precond.scale_dual_in_place_eq(
454 { proxsuite::proxqp::from_eigen, results.
y });
455 precond.scale_dual_in_place_in(
456 { proxsuite::proxqp::from_eigen, results.
z });
463 precond.scale_primal_in_place(
464 { proxsuite::proxqp::from_eigen, results.
x });
465 precond.scale_dual_in_place_eq(
466 { proxsuite::proxqp::from_eigen, results.
y });
467 precond.scale_dual_in_place_in(
468 { proxsuite::proxqp::from_eigen, results.
z });
472 precond.scale_primal_in_place(
473 { proxsuite::proxqp::from_eigen,
476 precond.scale_dual_in_place_eq(
477 { proxsuite::proxqp::from_eigen, results.
y });
478 precond.scale_dual_in_place_in(
479 { proxsuite::proxqp::from_eigen, results.
z });
490 auto zx = util::zero_extend;
497 isize n_tot = n + n_eq + n_in;
505 auto kkt_top_n_rows =
524 { proxsuite::linalg::sparse::from_eigen, g_scaled_e },
526 { proxsuite::linalg::sparse::from_eigen, b_scaled_e },
528 { proxsuite::linalg::sparse::from_eigen, l_scaled_e },
529 { proxsuite::linalg::sparse::from_eigen, u_scaled_e },
532 T
const dual_feasibility_rhs_2 = infty_norm(data.
g);
535 auto ldl_col_ptrs = work.
internal.
ldl.col_ptrs.ptr_mut();
536 proxsuite::linalg::veg::Tag<I> itag;
537 proxsuite::linalg::veg::Tag<T> xtag;
541 isize ldlt_ntot = do_ldlt ? n_tot : 0;
543 auto _perm = stack.make_new_for_overwrite(itag, ldlt_ntot);
545 I* perm_inv = work.
internal.
ldl.perm_inv.ptr_mut();
546 I* perm = _perm.ptr_mut();
550 for (
isize i = 0; i < n_tot; ++i) {
551 perm[
isize(zx(perm_inv[i]))] = I(i);
558 isize C_active_nnz = 0;
566 for (
isize j = 0; j < n_in; ++j) {
567 kkt_nnz_counts[n + n_eq + j] = 0;
581 for (
isize j = 0; j < n_in; ++j) {
582 if (results.
z(j) != 0) {
583 kkt_nnz_counts[n + n_eq + j] = I(kkt.
col_end(
usize(n + n_eq + j)) -
586 C_active_nnz += kkt_nnz_counts[n + n_eq + j];
588 kkt_nnz_counts[n + n_eq + j] = 0;
601 for (
isize j = 0; j < n_in; ++j) {
602 kkt_nnz_counts[n + n_eq + j] = 0;
615 for (
isize j = 0; j < n_in; ++j) {
616 if (results.
z(j) != 0) {
617 kkt_nnz_counts[n + n_eq + j] = I(kkt.
col_end(
usize(n + n_eq + j)) -
620 C_active_nnz += kkt_nnz_counts[n + n_eq + j];
623 kkt_nnz_counts[n + n_eq + j] = 0;
636 for (
isize j = 0; j < n_in; ++j) {
637 if (results.
z(j) != 0) {
638 kkt_nnz_counts[n + n_eq + j] = I(kkt.
col_end(
usize(n + n_eq + j)) -
641 C_active_nnz += kkt_nnz_counts[n + n_eq + j];
643 kkt_nnz_counts[n + n_eq + j] = 0;
652 proxsuite::linalg::sparse::from_raw_parts,
663 I* ldl_nnz_counts = work.
internal.
ldl.nnz_counts.ptr_mut();
664 I* ldl_row_indices = work.
internal.
ldl.row_indices.ptr_mut();
665 T* ldl_values = work.
internal.
ldl.values.ptr_mut();
670 proxsuite::linalg::sparse::from_raw_parts,
675 do_ldlt ? ldl_nnz_counts :
nullptr,
680 T bcl_eta_ext_init = pow(T(0.1), settings.
alpha_bcl);
681 T bcl_eta_ext = bcl_eta_ext_init;
683 T eps_in_min = std::min(settings.
eps_abs, T(1e-9));
685 auto x_e = x.to_eigen();
686 auto y_e = y.to_eigen();
687 auto z_e = z.to_eigen();
689 work, results, settings, kkt_active, active_constraints, data, stack, xtag);
695 rhs.head(n) = -g_scaled_e;
696 rhs.segment(n, n_eq) = b_scaled_e;
697 rhs.segment(n + n_eq, n_in).setZero();
700 { proxqp::from_eigen, no_guess },
716 y_e = rhs.segment(n, n_eq);
717 z_e = rhs.segment(n + n_eq, n_in);
737 T rhs_duality_gap(0);
738 T scaled_eps(settings.
eps_abs);
742 results.
info.iter_ext += 1;
746 T new_bcl_mu_eq = results.
info.mu_eq;
747 T new_bcl_mu_in = results.
info.mu_in;
748 T new_bcl_mu_eq_inv = results.
info.mu_eq_inv;
749 T new_bcl_mu_in_inv = results.
info.mu_in_inv;
752 T primal_feasibility_eq_rhs_0;
753 T primal_feasibility_in_rhs_0;
755 T dual_feasibility_rhs_0(0);
756 T dual_feasibility_rhs_1(0);
757 T dual_feasibility_rhs_3(0);
766 auto is_primal_feasible = [&](T primal_feasibility_lhs) ->
bool {
767 T rhs_pri = scaled_eps;
770 settings.
eps_rel * std::max({ primal_feasibility_eq_rhs_0,
771 primal_feasibility_in_rhs_0 });
773 return primal_feasibility_lhs <= rhs_pri;
775 auto is_dual_feasible = [&](T dual_feasibility_lhs) ->
bool {
778 rhs_dua += settings.
eps_rel * std::max({
779 dual_feasibility_rhs_0,
780 dual_feasibility_rhs_1,
781 dual_feasibility_rhs_2,
782 dual_feasibility_rhs_3,
786 return dual_feasibility_lhs <= rhs_dua;
792 (primal_feasibility_lhs, dual_feasibility_lhs),
796 primal_residual_eq_scaled,
797 primal_residual_in_scaled_lo,
798 primal_residual_in_scaled_up,
799 dual_residual_scaled,
800 primal_feasibility_eq_rhs_0,
801 primal_feasibility_in_rhs_0,
802 dual_feasibility_rhs_0,
803 dual_feasibility_rhs_1,
804 dual_feasibility_rhs_3,
831 precond.unscale_dual_residual_in_place({ proxqp::from_eigen, tmp });
833 precond.unscale_primal_in_place({ proxqp::from_eigen, x_e });
834 precond.unscale_dual_in_place_eq({ proxqp::from_eigen, y_e });
835 precond.unscale_dual_in_place_in({ proxqp::from_eigen, z_e });
838 results.
info.objValue = (tmp).dot(x_e);
839 std::cout <<
"\033[1;32m[outer iteration " << iter + 1 <<
"]\033[0m"
841 std::cout << std::scientific << std::setw(2) << std::setprecision(2)
842 <<
"| primal residual=" << primal_feasibility_lhs
843 <<
" | dual residual=" << dual_feasibility_lhs
844 <<
" | duality gap=" << results.
info.duality_gap
845 <<
" | mu_in=" << results.
info.mu_in
846 <<
" | rho=" << results.
info.rho << std::endl;
847 results.
info.pri_res = primal_feasibility_lhs;
848 results.
info.dua_res = dual_feasibility_lhs;
853 if (is_primal_feasible(primal_feasibility_lhs) &&
854 is_dual_feasible(dual_feasibility_lhs)) {
856 if (std::fabs(results.
info.duality_gap) <=
859 results.
info.pri_res = primal_feasibility_lhs;
860 results.
info.dua_res = dual_feasibility_lhs;
862 results.
info.status =
870 results.
info.pri_res = primal_feasibility_lhs;
871 results.
info.dua_res = dual_feasibility_lhs;
873 results.
info.status =
892 primal_residual_in_scaled_up += results.
info.mu_in * z_prev_e;
901 primal_residual_in_scaled_lo = primal_residual_in_scaled_up;
904 primal_residual_in_scaled_lo -= l_scaled_e;
907 primal_residual_in_scaled_up -= u_scaled_e;
910 auto primal_dual_newton_semi_smooth = [&]() ->
void {
926 primal_residual_in_scaled_lo.array() <= 0;
928 primal_residual_in_scaled_up.array() >= 0;
933 bool removed =
false;
936 for (
isize i = 0; i < n_in; ++i) {
937 bool was_active = active_constraints[i];
938 bool is_active = new_active_constraints[i];
940 isize idx = n + n_eq + i;
945 if (is_active && !was_active) {
953 proxsuite::linalg::sparse::from_raw_parts,
959 T mu_in_neg = -results.
info.mu_in;
970 ldl, etree, perm_inv, idx, new_col, mu_in_neg, stack);
972 active_constraints[i] = new_active_constraints[i];
974 }
else if (!is_active && was_active) {
980 ldl, etree, perm_inv, idx, stack);
982 active_constraints[i] = new_active_constraints[i];
987 if (removed || added) {
1000 rhs.head(n) = -dual_residual_scaled;
1001 rhs.segment(n, n_eq) = -primal_residual_eq_scaled;
1002 for (
isize i = 0; i < n_in; ++i) {
1005 results.
info.mu_in * z_e(i) - primal_residual_in_scaled_up(i);
1008 results.
info.mu_in * z_e(i) - primal_residual_in_scaled_lo(i);
1010 rhs(n + n_eq + i) = -z_e(i);
1011 rhs.head(n) += z_e(i) * CT_scaled.
to_eigen().col(i);
1047 { proxqp::from_eigen, rhs },
1048 { proxqp::from_eigen,
1064 active_constraints);
1067 auto dx = dw.head(n);
1068 auto dy = dw.segment(n, n_eq);
1069 auto dz = dw.segment(n + n_eq, n_in);
1091 auto primal_dual_gradient_norm =
1099 auto zero = Eigen::Matrix<T, Eigen::Dynamic, 1>::Zero(n_in);
1101 tmp_lo = primal_residual_in_scaled_lo + alpha_cur * Cdx;
1102 tmp_up = primal_residual_in_scaled_up + alpha_cur * Cdx;
1104 (tmp_lo.array() < 0 || tmp_up.array() > 0).select(Cdx, zero);
1105 active_part_z = (tmp_lo.array() < 0)
1106 .select(primal_residual_in_scaled_lo, zero) +
1107 (tmp_up.array() > 0)
1108 .select(primal_residual_in_scaled_up, zero);
1112 results.
info.rho * dx.squaredNorm() +
1113 results.
info.mu_eq_inv * Adx.squaredNorm() +
1114 +results.
info.mu_in_inv * Cdx_active.squaredNorm() +
1115 results.
info.nu * results.
info.mu_eq *
1116 (results.
info.mu_eq_inv * Adx - dy).squaredNorm() +
1117 results.
info.nu * results.
info.mu_in *
1118 (results.
info.mu_in_inv * Cdx_active - dz).squaredNorm();
1122 (results.
info.rho * (x_e - x_prev_e) + g_scaled_e).dot(dx) +
1123 Adx.dot(results.
info.mu_eq_inv * primal_residual_eq_scaled +
1125 results.
info.mu_in_inv * Cdx_active.dot(active_part_z) +
1126 results.
info.nu * primal_residual_eq_scaled.dot(
1127 results.
info.mu_eq_inv * Adx - dy) +
1129 (active_part_z - results.
info.mu_in * z_e)
1130 .dot(results.
info.mu_in_inv * Cdx_active - dz);
1191 isize alphas_count = 0;
1192 const T machine_eps = std::numeric_limits<T>::epsilon();
1194 for (
isize i = 0; i < n_in; ++i) {
1195 T alpha_candidates[2] = {
1196 -primal_residual_in_scaled_lo(i) / (Cdx(i) + machine_eps),
1197 -primal_residual_in_scaled_up(i) / (Cdx(i) + machine_eps),
1200 for (
auto alpha_candidate : alpha_candidates) {
1201 if (alpha_candidate > machine_eps) {
1202 alphas[alphas_count] = alpha_candidate;
1207 std::sort(alphas.data(), alphas.data() + alphas_count);
1209 std::unique(alphas.data(), alphas.data() + alphas_count) -
1211 if (alphas_count > 0) {
1212 auto infty = std::numeric_limits<T>::infinity();
1214 T last_neg_grad = 0;
1215 T alpha_last_neg = 0;
1216 T first_pos_grad = 0;
1217 T alpha_first_pos = infty;
1219 for (
isize i = 0; i < alphas_count; ++i) {
1220 T alpha_cur = alphas[i];
1221 T gr = primal_dual_gradient_norm(alpha_cur).grad;
1232 alpha_last_neg = alpha_cur;
1235 first_pos_grad = gr;
1236 alpha_first_pos = alpha_cur;
1241 if (alpha_last_neg == 0) {
1243 primal_dual_gradient_norm(alpha_last_neg).grad;
1255 if (alpha_first_pos == infty) {
1256 auto res = primal_dual_gradient_norm(2 * alpha_last_neg + 1);
1257 alpha = -res.b / res.a;
1271 alpha = alpha_last_neg -
1272 last_neg_grad * (alpha_first_pos - alpha_last_neg) /
1273 (first_pos_grad - last_neg_grad);
1277 auto res = primal_dual_gradient_norm(T(0));
1278 alpha = -res.b / res.a;
1291 if (alpha * infty_norm(dw) < T(1e-11) && iter_inner > 0) {
1292 results.
info.iter += iter_inner + 1;
1299 dual_residual_scaled +=
1300 alpha * (Hdx + ATdy + CTdz + results.
info.rho * dx);
1301 primal_residual_eq_scaled += alpha * (Adx - results.
info.mu_eq * dy);
1302 primal_residual_in_scaled_lo += alpha * Cdx;
1303 primal_residual_in_scaled_up += alpha * Cdx;
1305 T err_in = std::max({
1308 results.
info.mu_in * z_e)),
1309 (infty_norm(primal_residual_eq_scaled)),
1310 (infty_norm(dual_residual_scaled)),
1344 std::cout <<
"\033[1;34m[inner iteration " << iter_inner + 1
1345 <<
"]\033[0m" << std::endl;
1346 std::cout << std::scientific << std::setw(2) << std::setprecision(2)
1347 <<
"| inner residual=" << err_in <<
" | alpha=" << alpha
1372 if (is_primal_infeasible) {
1375 results.
info.iter += iter_inner + 1;
1379 }
else if (is_dual_infeasible) {
1382 results.
info.iter += iter_inner + 1;
1388 if (err_in <= bcl_eta_in) {
1389 results.
info.iter += iter_inner + 1;
1396 primal_dual_newton_semi_smooth();
1401 results.
x = dw_prev.head(data.
dim);
1402 results.
y = dw_prev.segment(data.
dim, data.
n_eq);
1403 results.
z = dw_prev.tail(data.
n_in);
1408 if (scaled_eps == settings.
eps_abs &&
1414 rhs_n_eq.setConstant(T(1));
1415 rhs_n_in.setConstant(T(1));
1418 scaled_eps = infty_norm(rhs_dim) * settings.
eps_abs;
1425 (primal_feasibility_lhs_new, dual_feasibility_lhs_new),
1429 primal_residual_eq_scaled,
1430 primal_residual_in_scaled_lo,
1431 primal_residual_in_scaled_up,
1432 dual_residual_scaled,
1433 primal_feasibility_eq_rhs_0,
1434 primal_feasibility_in_rhs_0,
1435 dual_feasibility_rhs_0,
1436 dual_feasibility_rhs_1,
1437 dual_feasibility_rhs_3,
1447 if (is_primal_feasible(primal_feasibility_lhs_new) &&
1448 is_dual_feasible(dual_feasibility_lhs_new)) {
1450 if (std::fabs(results.
info.duality_gap) <=
1453 results.
info.pri_res = primal_feasibility_lhs_new;
1454 results.
info.dua_res = dual_feasibility_lhs_new;
1456 results.
info.status ==
1458 results.
info.status =
1466 results.
info.pri_res = primal_feasibility_lhs_new;
1467 results.
info.dua_res = dual_feasibility_lhs_new;
1470 results.
info.status =
1480 auto bcl_update = [&]() ->
void {
1481 if (primal_feasibility_lhs_new <= bcl_eta_ext ||
1483 bcl_eta_ext *= pow(results.
info.mu_in, settings.
beta_bcl);
1484 bcl_eta_in = std::max(bcl_eta_in * results.
info.mu_in, eps_in_min);
1489 new_bcl_mu_in = std::max(
1491 new_bcl_mu_eq = std::max(
1501 bcl_eta_ext_init * pow(new_bcl_mu_in, settings.
alpha_bcl);
1502 bcl_eta_in = std::max(new_bcl_mu_in, eps_in_min);
1510 (_, dual_feasibility_lhs_new_2),
1514 primal_residual_eq_scaled,
1515 primal_residual_in_scaled_lo,
1516 primal_residual_in_scaled_up,
1517 dual_residual_scaled,
1518 primal_feasibility_eq_rhs_0,
1519 primal_feasibility_in_rhs_0,
1520 dual_feasibility_rhs_0,
1521 dual_feasibility_rhs_1,
1522 dual_feasibility_rhs_3,
1531 proxsuite::linalg::veg::unused(_);
1533 if (primal_feasibility_lhs_new >= primal_feasibility_lhs &&
1534 dual_feasibility_lhs_new_2 >= dual_feasibility_lhs &&
1535 results.
info.mu_in <= T(1.E-5)) {
1542 if (results.
info.mu_in != new_bcl_mu_in ||
1543 results.
info.mu_eq != new_bcl_mu_eq) {
1545 ++results.
info.mu_updates;
1560 for (
isize j = 0; j < n_eq + n_in; ++j) {
1561 I row_index = I(j + n);
1563 alpha = results.
info.mu_eq - new_bcl_mu_eq;
1569 alpha = results.
info.mu_in - new_bcl_mu_in;
1582 proxsuite::linalg::veg::from_raw_parts,
1588 ldl = rank1_update(ldl, etree, perm_inv, w, alpha, stack);
1602 results.
info.mu_eq = new_bcl_mu_eq;
1603 results.
info.mu_in = new_bcl_mu_in;
1604 results.
info.mu_eq_inv = new_bcl_mu_eq_inv;
1605 results.
info.mu_in_inv = new_bcl_mu_in_inv;
1610 precond.unscale_dual_residual_in_place({ proxqp::from_eigen, tmp });
1612 precond.unscale_primal_in_place({ proxqp::from_eigen, x_e });
1613 precond.unscale_dual_in_place_eq({ proxqp::from_eigen, y_e });
1614 precond.unscale_dual_in_place_in({ proxqp::from_eigen, z_e });
1617 results.
info.objValue = (tmp).dot(x_e);
1620 results.
info.solve_time = work.
timer.elapsed().user;
1621 results.
info.run_time = results.
info.solve_time + results.
info.setup_time;
1624 std::cout <<
"-------------------SOLVER STATISTICS-------------------"
1626 std::cout <<
"outer iter: " << results.
info.iter_ext << std::endl;
1627 std::cout <<
"total iter: " << results.
info.iter << std::endl;
1628 std::cout <<
"mu updates: " << results.
info.mu_updates << std::endl;
1629 std::cout <<
"rho updates: " << results.
info.rho_updates << std::endl;
1630 std::cout <<
"objective: " << results.
info.objValue << std::endl;
1631 switch (results.
info.status) {
1633 std::cout <<
"status: "
1634 <<
"Solved" << std::endl;
1638 std::cout <<
"status: "
1639 <<
"Maximum number of iterations reached" << std::endl;
1643 std::cout <<
"status: "
1644 <<
"Primal infeasible" << std::endl;
1648 std::cout <<
"status: "
1649 <<
"Dual infeasible" << std::endl;
1653 std::cout <<
"status: "
1654 <<
"Solved closest primal feasible" << std::endl;
1658 std::cout <<
"status: "
1659 <<
"Solver not run" << std::endl;
1664 std::cout <<
"run time [μs]: " << results.
info.solve_time << std::endl;
1665 std::cout <<
"--------------------------------------------------------"
1669 assert(!std::isnan(results.
info.pri_res));
1670 assert(!std::isnan(results.
info.dua_res));
1671 assert(!std::isnan(results.
info.duality_gap));