51 Mat M,
const EqMat& A,
53 using T = linalg::matrix_scalar_t<Mat>;
54 constexpr std::size_t N = linalg::mat_cols_v<Mat>;
55 constexpr std::size_t EqRows = linalg::mat_rows_v<EqMat>;
56 constexpr std::size_t EqCols = linalg::mat_cols_v<EqMat>;
60 for (
const auto& x :
d) s = std::max(s, linalg::constexpr_abs(x));
62 s = std::max(s, T(1));
63 const auto delta = reg.global_eps * s;
64 const auto eq_delta = reg.eq_eps * s;
66 for (std::size_t
j = 0;
j < N; ++
j) {
69 if constexpr (EqRows != 0 && EqCols != 0) {
72 for (std::size_t
i = 0;
i < EqRows; ++
i) {
73 if (linalg::constexpr_abs(A(
i,
j)) > T(0)) {
97 using ConeMap =
decltype(std::declval<const Problem&>().constraint_map());
98 using ConeMat = affine::affine_mat_t<ConeMap>;
99 using EqMap =
decltype(std::declval<const Problem&>().equality_map());
100 using EqMat = affine::affine_mat_t<EqMap>;
102 decltype(std::declval<const Problem&>().canonical_trace());
103 using T = linalg::space_type_t<DecVar>;
106 static constexpr std::size_t
NumCones = std::tuple_size_v<
107 decltype(std::declval<const Problem&>().constraint_cones())>;
108 static constexpr std::size_t
M = linalg::mat_rows_v<ConeMat>;
109 static constexpr std::size_t
N = linalg::mat_cols_v<ConeMat>;
111 static constexpr std::size_t
EqRows = linalg::mat_rows_v<EqMat>;
112 using NuVar = linalg::Vector<T, EqRows>;
116 using Var = linalg::Vector<T, N>;
120#ifdef AKREON_REPORT_OUTPUT
127 "Problem is not set therefore cannot be solved");
130 static constexpr T rho{linalg::ln2_v<T>};
133 static constexpr T beta{1 - linalg::ln2_v<T>};
163 res.iterate = iterate;
179 res.iterate = iterate;
186#ifdef AKREON_REPORT_OUTPUT
203 const auto c =
prob.linear_objective();
204 const auto g =
prob.constraint_map().translation();
205 const auto F =
prob.constraint_map().linear_part();
206 const auto A =
prob.equality_map().linear_part();
207 const auto b =
prob.equality_map().translation();
208 const auto K =
prob.constraint_cones();
209 res.canonical_trace =
prob.canonical_trace();
211 AK_ASSERT(
prob.validate() &&
"submitted problem is not valid!");
212 if (!
prob.validate())
return;
214 auto& z =
res.iterate.z;
215 auto& x =
res.iterate.x;
216 auto& y =
res.iterate.y;
217 auto& nu =
res.iterate.nu;
222 auto&
i =
res.num_iter;
231#ifdef AKREON_REPORT_OUTPUT
255 auto residuals = compute_residuals(
F, A,
g, c, b, z, nu, x, y);
266#ifdef AKREON_REPORT_OUTPUT
280 Var{},
pred_step.px,
pred_step.py,
K,
M_ldl,
eq,
F, rp, rd, req, x, y
281#ifdef AKREON_REPORT_OUTPUT
306#ifdef AKREON_REPORT_OUTPUT
319 residuals = compute_residuals(
F, A,
g, c, b, z, nu, x, y);
332#ifdef AKREON_REPORT_OUTPUT
337 res.solver_trace = trace;
341 res.convex_obj = linalg::inner_product(c, z);
342 res.dual_obj = -linalg::inner_product(
g, y);
367 template <std::
size_t idx = 0, std::
size_t Start = 0>
372 return std::tuple(std::move(
M_blk), linalg::NumericalEvent::NONE);
374 const auto Ki = std::get<idx>(
K);
377 constexpr std::size_t
KiRows = linalg::vector_dim_v<Slack>;
384 xk(
j) = x(
i), yk(
j) = y(
i);
386 const auto [P, event] =
Ki.H(xk, yk);
387 if (linalg::is_fatal_event(event))
388 return std::tuple(std::move(
M_blk), event);
390 const auto F_blk = linalg::get_block<Start, End, 0, N>(
F);
391 const auto Mi = linalg::transpose(
F_blk) * P.apply(
F_blk);
411 template <std::
size_t idx = 0, std::
size_t Start = 0>
414 if constexpr (idx >=
NumCones)
return T(0);
416 const auto Ki = std::get<idx>(
K);
419 constexpr std::size_t
KiRows = linalg::vector_dim_v<Slack>;
426 xk(
j) = x(
i), yk(
j) = y(
i);
428 if (
Ki.in_cone(xk) &&
Ki.in_dual_cone(yk))
432 const auto x0 =
Ki.x0(), y0 =
Ki.y0();
434 x(
i) = x0(
j), y(
i) = y0(
j);
455 template <std::
size_t idx = 0, std::
size_t Start = 0>
456 constexpr auto alpha_max(
T&& alpha_x,
T&& alpha_y,
const auto&
K,
460 const auto ax = std::max(
T(0), std::min(
T(1), alpha_x));
461 const auto ay = std::max(
T(0), std::min(
T(1), alpha_y));
462 return std::tuple(
ax,
ay);
464 const auto Ki = std::get<idx>(
K);
466 constexpr std::size_t
KiRows = linalg::vector_dim_v<Slack>;
475 alpha_x = std::min(
Ki.alpha_max(xk,
pxk), alpha_x);
476 alpha_y = std::min(
Ki.alpha_max_dual(yk,
pyk), alpha_y);
494 template <std::
size_t idx = 0, std::
size_t Start = 0>
495 constexpr bool check_functional_proximity(
const auto&
K,
const ConeVar& x,
500 const auto Ki = std::get<idx>(
K);
502 constexpr std::size_t
KiRows = linalg::vector_dim_v<Slack>;
508 xk(
j) = x(
i), yk(
j) = y(
i);
511 const auto [gamma_F, event] =
Ki.gamma_F(xk, yk);
512 bool rv =
Ki.in_cone(xk) &&
Ki.in_dual_cone(yk) &&
513 !linalg::is_fatal_event(event) && gamma_F <
beta_limit;
539 constexpr bool backtrack_iterates(std::tuple<T, T>&
alpha_xy,
const auto&
K,
548 ax = std::max(
T(0),
ax);
549 ay = std::max(
T(0),
ay);
551 const auto curr = compute_residuals(
F, A,
g, c, b, z, nu, x, y);
553 constexpr auto zeta{1.05};
555 for (std::size_t
i = 0;
i <
config.backtrack_steps; ++
i) {
556 const auto z_tmp = z +
ax * pz;
558 const auto x_tmp = x +
ax * px;
559 const auto y_tmp = y +
ay * py;
595 constexpr auto dual_residual(
const ConeMat&
F,
const EqMat& A,
const Var& c,
597 if constexpr (
EqRows == 0)
return linalg::transpose(
F) * y - c;
598 else return linalg::transpose(
F) * y - linalg::transpose(A) * nu - c;
615 return F * z +
g - x;
629 constexpr auto equality_residual(
const EqMat& A,
const NuVar& b,
630 const Var& z)
const {
632 else return b - A * z;
656 residuals.req = equality_residual(A, b, z);
671 constexpr auto make_equality_coupling(
const auto&
M_ldl,
672 const EqMat& A)
const {
675 if constexpr (
EqRows == 0) {
677 return std::tuple(std::optional<Coupling>{
Coupling{}},
678 linalg::NumericalEvent::NONE);
679 }
else if constexpr (
EqRows == 1) {
680 const auto [
M_inv_AT, event] =
M_ldl.apply(linalg::transpose(A));
682 if (linalg::is_fatal_event(event))
683 return std::tuple(std::optional<Coupling>{}, event);
688 return std::tuple(std::optional<Coupling>{},
689 linalg::NumericalEvent::FACTORIZATION_FAILED);
691 return std::tuple(std::optional<Coupling>{
Coupling(A,
S(0, 0))},
692 linalg::NumericalEvent::NONE);
694 const auto [
M_inv_AT, event] =
M_ldl.apply(linalg::transpose(A));
697 if (linalg::is_fatal_event(event))
698 return std::tuple(std::optional<Coupling>{}, event);
702 if (!
S_ldl.is_valid())
703 return std::tuple(std::optional<Coupling>{},
704 linalg::NumericalEvent::FACTORIZATION_FAILED);
706 return std::tuple(std::optional<Coupling>{
Coupling(A,
S_ldl)},
707 linalg::NumericalEvent::NONE);
734 constexpr auto get_tag()
const {