akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
equality_coupling.hpp
Go to the documentation of this file.
1/*
2 * Copyright © 2025-2026 Akreon LLC
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#pragma once
7
8#include "akreon/linalg/linalg_util.hpp"
9
10namespace convex {
11
15template <linalg::VectorContainer Var, linalg::VectorContainer NuVar>
27 constexpr auto solve_step(const auto& M_inv, const Var& pz_rhs, const Var& rd,
28 const NuVar& /* req */) const {
29 const auto [pz, event] = M_inv.solve(pz_rhs + rd);
30 return std::tuple(pz, NuVar{}, event);
31 }
32};
33
47template <linalg::MatrixContainer EqMat, typename SchurFactor,
48 linalg::VectorContainer Var, linalg::VectorContainer NuVar>
56 constexpr explicit SchurEqualityCoupling(const EqMat& A_in,
57 const SchurFactor& S_inv_in)
58 : A(A_in), S_inv(S_inv_in) {}
59
74 constexpr auto solve_step(const auto& M_inv, const Var& pz_rhs, const Var& rd,
75 const NuVar& req) const {
76 const auto [M_inv_pz, event_one] = M_inv.solve(pz_rhs + rd);
77 if (linalg::is_fatal_event(event_one))
78 return std::tuple(Var{}, NuVar{}, event_one);
79
80 const auto schur_rhs = A * M_inv_pz - req;
81 const auto [pnu, event_two] = S_inv.solve(schur_rhs);
82 if (linalg::is_fatal_event(event_two))
83 return std::tuple(Var{}, NuVar{}, event_two);
84
85 const auto [pz, event_three] =
86 M_inv.solve(pz_rhs + rd - linalg::transpose(A) * pnu);
87 if (linalg::is_fatal_event(event_three))
88 return std::tuple(Var{}, NuVar{}, event_three);
89
90 return std::tuple(pz, pnu, linalg::NumericalEvent::NONE);
91 }
92
94 EqMat A{};
96};
97
101template <linalg::MatrixContainer EqMat, linalg::Field Scalar,
102 linalg::VectorContainer Var, linalg::VectorContainer NuVar>
110 constexpr explicit ScalarEqualityCoupling(const EqMat& A_in,
111 const Scalar& s_in)
112 : A(A_in), s(s_in) {}
113
128 constexpr auto solve_step(const auto& M_inv, const Var& pz_rhs, const Var& rd,
129 const NuVar& req) const {
130 const auto [M_inv_pz, event_one] = M_inv.solve(pz_rhs + rd);
131 if (linalg::is_fatal_event(event_one))
132 return std::tuple(Var{}, NuVar{}, event_one);
133
134 const auto schur_rhs = A * M_inv_pz - req;
135 NuVar pnu{};
136 pnu(0) = schur_rhs(0) / s;
137
138 const auto [pz, event_two] =
139 M_inv.solve(pz_rhs + rd - linalg::transpose(A) * pnu);
140 if (linalg::is_fatal_event(event_two))
141 return std::tuple(Var{}, NuVar{}, event_two);
142
143 return std::tuple(pz, pnu, linalg::NumericalEvent::NONE);
144 }
145
147 EqMat A{};
148 Scalar s{};
149};
150
151} // namespace convex
constexpr std::size_t dom_size_v
No equality-coupling case for empty A.
constexpr auto solve_step(const auto &M_inv, const Var &pz_rhs, const Var &rd, const NuVar &) const
solve for pz step
Scalar Schur complement wrapper for 1x1 equality case.
constexpr ScalarEqualityCoupling(const EqMat &A_in, const Scalar &s_in)
CTOR.
constexpr auto solve_step(const auto &M_inv, const Var &pz_rhs, const Var &rd, const NuVar &req) const
solve for pz step
Equality-coupling wrapper for Schur-complement based solve.
constexpr SchurEqualityCoupling(const EqMat &A_in, const SchurFactor &S_inv_in)
CTOR.
SchurFactor S_inv
Schur factor S = (A M^{-1} A^T)^{-1}.
constexpr auto solve_step(const auto &M_inv, const Var &pz_rhs, const Var &rd, const NuVar &req) const
solve for pz step