akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
psd_cone.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 "cone.hpp"
9#include "akreon/linalg/space/symmetric_matrix_space.hpp"
10#include "akreon/linalg/operator/matrix_inverse.hpp"
11#include "akreon/linalg/operator/matrix_sqrt.hpp"
12
13namespace conic {
14
20template <linalg::VectorContainer Vec, std::size_t N>
21struct PSDCirc {
23 using T = linalg::vector_element_t<Vec>;
24
35 constexpr auto operator()(const Vec& x, const Vec& y) const {
36 const auto X = linalg::make_smat<N>(x);
37 const auto Y = linalg::make_smat<N>(y);
38 return linalg::get_svec(T(0.5) * (X * Y + Y * X));
39 }
40};
41
46template <linalg::VectorContainer Slack, std::size_t N>
48 : public Cone<Slack, PositiveSemidefiniteCone<Slack, N>,
49 ConeType::SYMMETRIC> {
51 using ConeBase =
53
55 using ConeBase::eps;
56 using ConeBase::M;
57 using typename ConeBase::HessianMat;
58 using typename ConeBase::T;
59
60 static_assert(M == N * (N + 1) / 2,
61 "Encoded dim for PSD Cone does not align with slack dim");
62
64 using ambient_space = linalg::SymmetricMatrixSpace<T, N>;
66 using element_type = linalg::space_element_t<ambient_space>;
67
74 static constexpr bool contains(const element_type& element) {
75 return element.is_psd();
76 }
77
83 constexpr Slack x0_impl() const { return e_impl(); }
84
90 constexpr Slack y0_impl() const { return e_impl(); }
91
99 constexpr bool in_cone_impl(const Slack& x) const {
100 const auto X = linalg::make_smat<N, Slack>(x);
101 const linalg::Cholesky chol(X);
102 return chol.is_pd();
103 }
104
112 constexpr bool in_dual_cone_impl(const Slack& y) const {
113 return in_cone_impl(y);
114 }
115
138 constexpr T alpha_max_impl(const Slack& x,
139 const linalg::Vector<T, M>& p) const {
140 constexpr T eta{0.99};
141 if (in_cone_impl(x + p)) return eta;
142
143 constexpr std::size_t steps{64};
144 T lo{0}, hi{1};
145 for (std::size_t i = 0; i < steps; ++i) {
146 const T mid = T(0.5) * (lo + hi);
147 if (in_cone_impl(x + mid * p)) lo = mid;
148 else hi = mid;
149 }
150 return eta * lo;
151 }
152
162 constexpr T alpha_max_dual_impl(const Slack& y,
163 const linalg::Vector<T, M>& p) const {
164 return alpha_max_impl(y, p);
165 }
166
181 constexpr auto H_impl(const Slack& x, const Slack& y) const {
182 const auto [w, event] = w_impl(x, y);
183 if (linalg::is_fatal_event(event))
184 return std::tuple(
185 linalg::QuadraticRep<HessianMat, PSDCirc<Slack, N>>(e_impl()), event);
186 const auto [w_inv, inv_event] = inv_impl(w);
187 if (linalg::is_fatal_event(inv_event))
188 return std::tuple(
189 linalg::QuadraticRep<HessianMat, PSDCirc<Slack, N>>(e_impl()),
190 inv_event);
191 const auto out_event = (event != linalg::NumericalEvent::NONE ||
192 inv_event != linalg::NumericalEvent::NONE)
193 ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
194 : linalg::NumericalEvent::NONE;
195 return std::tuple(
196 linalg::QuadraticRep<HessianMat, PSDCirc<Slack, N>>(w_inv), out_event);
197 }
198
208 constexpr auto grad_impl(const Slack& x) const {
209 const auto [x_inv, event] = inv_impl(x);
210 return std::tuple(T(-1) * x_inv, event);
211 }
212
218 constexpr T nu_impl() const { return static_cast<T>(N); }
219
227 constexpr auto e_impl() const {
228 Slack x{};
229 std::size_t k{0};
230 for (std::size_t i = 0; i < N; ++i)
231 for (std::size_t j = 0; j <= i; ++j, ++k)
232 if (i == j) x(k) = T(1);
233 return x;
234 }
235
237 constexpr auto sqrt_impl(const Slack& x) const {
238 const auto matrix = linalg::make_smat<N>(x);
239 const auto [root, inv_root, event] =
240 linalg::MatrixSqrt<decltype(matrix)>()(matrix);
241 return std::tuple(linalg::get_svec(root), event);
242 }
243
254 constexpr auto w_impl(const Slack& x, const Slack& y) const {
255 Slack w{};
256 const auto X = linalg::make_smat<N, Slack>(x);
257 const auto [X_sqrt, X_inv_sqrt, event1] =
258 linalg::MatrixSqrt<decltype(X)>()(X);
259 if (linalg::is_fatal_event(event1)) return std::tuple(w, event1);
260 (void)X_inv_sqrt;
261
262 const auto Y = linalg::make_smat<N, Slack>(y);
263 const auto U = linalg::symmetric_part(X_sqrt * (Y * X_sqrt));
264 const auto [U_sqrt, U_inv_sqrt, event2] =
265 linalg::MatrixSqrt<decltype(U)>()(U);
266 if (linalg::is_fatal_event(event2)) return std::tuple(w, event2);
267 (void)U_sqrt;
268
269 w = linalg::get_svec(
270 linalg::symmetric_part(X_sqrt * (U_inv_sqrt * X_sqrt)));
271 const auto out_event = (event1 != linalg::NumericalEvent::NONE ||
272 event2 != linalg::NumericalEvent::NONE)
273 ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
274 : linalg::NumericalEvent::NONE;
275 return std::tuple(w, out_event);
276 }
277
288 constexpr auto circ_impl(const Slack& x, const Slack& y) const {
289 return PSDCirc<Slack, N>()(x, y);
290 }
291
302 constexpr T trace_impl(const Slack& x, const Slack& y) const {
303 const auto X = linalg::make_smat<N, Slack>(x);
304 const auto Y = linalg::make_smat<N, Slack>(y);
305 return linalg::trace(X * Y);
306 }
307
318 constexpr auto gamma_F_impl(const Slack& x, const Slack& y) const {
319 const auto X = linalg::make_smat<N, Slack>(x);
320 const auto Y = linalg::make_smat<N, Slack>(y);
321
322 const auto [X_sqrt, X_inv_sqrt, event] =
323 linalg::MatrixSqrt<decltype(X)>()(X);
324 if (event != linalg::NumericalEvent::NONE) return std::tuple(T(0), event);
325 (void)X_inv_sqrt;
326
327 const auto ldl_X = linalg::LDL(X);
328 const auto ldl_Y = linalg::LDL(Y);
329
330 const auto factor_res = ldl_X.is_valid() && ldl_Y.is_valid();
331 AK_ASSERT(factor_res && "Either LDL(X) or LDL(Y) is invalid");
332 if (!factor_res)
333 return std::tuple(T(0), linalg::NumericalEvent::FACTORIZATION_FAILED);
334
335 const auto a = T(-1) * linalg::constexpr_ln_safe(ldl_X.det());
336 const auto b = T(-1) * linalg::constexpr_ln_safe(ldl_Y.det());
337 const auto tr_term = linalg::trace(X_sqrt * (Y * X_sqrt));
338 const auto c = nu_impl() * linalg::constexpr_ln_safe(tr_term / nu_impl());
339
340 return std::tuple(a + b + c, linalg::NumericalEvent::NONE);
341 }
342
350 constexpr auto inv_impl(const Slack& x) const {
351 const auto X = linalg::make_smat<N, Slack>(x);
352 const auto [X_inv, event] =
353 linalg::SymmetricMatrixInverse<decltype(X)>()(X);
354 return std::tuple(linalg::get_svec(linalg::symmetric_part(X_inv)), event);
355 }
356};
357
358} // namespace conic
cone base class
Definition cone.hpp:19
static constexpr std::size_t M
helpers to get M slack size
Definition cone.hpp:24
linalg::vector_element_t< Slack > T
alias for mat type
Definition cone.hpp:21
constexpr auto w(const Slack &x, const Slack &y) const
w (self-scaling point)
Definition cone.hpp:166
Circ - Jordan map/product for the PSD cone.
Definition psd_cone.hpp:21
constexpr auto operator()(const Vec &x, const Vec &y) const
circ (jordan map/product)
Definition psd_cone.hpp:35
linalg::vector_element_t< Vec > T
types and size extraction
Definition psd_cone.hpp:23
forward decl for psd
Definition psd_cone.hpp:49
constexpr auto w_impl(const Slack &x, const Slack &y) const
w (self-scaled point)
Definition psd_cone.hpp:254
constexpr auto H_impl(const Slack &x, const Slack &y) const
hessian
Definition psd_cone.hpp:181
constexpr Slack x0_impl() const
default x in K
Definition psd_cone.hpp:83
constexpr auto circ_impl(const Slack &x, const Slack &y) const
circ
Definition psd_cone.hpp:288
constexpr T alpha_max_impl(const Slack &x, const linalg::Vector< T, M > &p) const
alpha_max (fraction to boundary)
Definition psd_cone.hpp:138
constexpr auto gamma_F_impl(const Slack &x, const Slack &y) const
gamma_F
Definition psd_cone.hpp:318
constexpr T trace_impl(const Slack &x, const Slack &y) const
trace
Definition psd_cone.hpp:302
constexpr bool in_cone_impl(const Slack &x) const
x in K check
Definition psd_cone.hpp:99
constexpr Slack y0_impl() const
default y in K^*
Definition psd_cone.hpp:90
constexpr T alpha_max_dual_impl(const Slack &y, const linalg::Vector< T, M > &p) const
alpha_max dual (fraction to dK^*)
Definition psd_cone.hpp:162
static constexpr bool contains(const element_type &element)
Closed-cone membership, including semidefinite boundary elements.
Definition psd_cone.hpp:74
constexpr T nu_impl() const
barrier param
Definition psd_cone.hpp:218
constexpr auto inv_impl(const Slack &x) const
inv
Definition psd_cone.hpp:350
linalg::space_element_t< ambient_space > element_type
Canonical matrix representation of an ambient-space element.
Definition psd_cone.hpp:66
constexpr auto sqrt_impl(const Slack &x) const
Jordan square root in symmetric-vector coordinates.
Definition psd_cone.hpp:237
constexpr bool in_dual_cone_impl(const Slack &y) const
y in K^* check
Definition psd_cone.hpp:112
constexpr auto e_impl() const
e (jordan identity)
Definition psd_cone.hpp:227
linalg::SymmetricMatrixSpace< T, N > ambient_space
Ambient vector space of real symmetric matrices.
Definition psd_cone.hpp:64
constexpr auto grad_impl(const Slack &x) const
grad (jacobian)
Definition psd_cone.hpp:208