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"
20template <linalg::VectorContainer Vec, std::
size_t N>
23 using T = linalg::vector_element_t<Vec>;
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));
46template <linalg::VectorContainer Slack, std::
size_t N>
48 :
public Cone<Slack, PositiveSemidefiniteCone<Slack, N>,
49 ConeType::SYMMETRIC> {
60 static_assert(
M == N * (N + 1) / 2,
61 "Encoded dim for PSD Cone does not align with slack dim");
75 return element.is_psd();
100 const auto X = linalg::make_smat<N, Slack>(x);
101 const linalg::Cholesky chol(X);
139 const linalg::Vector<T, M>& p)
const {
140 constexpr T eta{0.99};
143 constexpr std::size_t steps{64};
145 for (std::size_t i = 0; i < steps; ++i) {
146 const T mid =
T(0.5) * (lo + hi);
163 const linalg::Vector<T, M>& p)
const {
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))
186 const auto [w_inv, inv_event] =
inv_impl(
w);
187 if (linalg::is_fatal_event(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;
209 const auto [x_inv, event] =
inv_impl(x);
210 return std::tuple(
T(-1) * x_inv, event);
218 constexpr T nu_impl()
const {
return static_cast<T>(N); }
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);
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);
254 constexpr auto w_impl(
const Slack& x,
const Slack& y)
const {
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);
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);
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);
288 constexpr auto circ_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);
319 const auto X = linalg::make_smat<N, Slack>(x);
320 const auto Y = linalg::make_smat<N, Slack>(y);
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);
327 const auto ldl_X = linalg::LDL(X);
328 const auto ldl_Y = linalg::LDL(Y);
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");
333 return std::tuple(
T(0), linalg::NumericalEvent::FACTORIZATION_FAILED);
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());
340 return std::tuple(a + b + c, linalg::NumericalEvent::NONE);
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);
static constexpr std::size_t M
helpers to get M slack size
linalg::Matrix< T, M, M > HessianMat
hessian type
linalg::vector_element_t< Slack > T
alias for mat type
constexpr auto w(const Slack &x, const Slack &y) const
w (self-scaling point)
static constexpr T eps
eps constant
Circ - Jordan map/product for the PSD cone.
constexpr auto operator()(const Vec &x, const Vec &y) const
circ (jordan map/product)
linalg::vector_element_t< Vec > T
types and size extraction
constexpr auto w_impl(const Slack &x, const Slack &y) const
w (self-scaled point)
constexpr auto H_impl(const Slack &x, const Slack &y) const
hessian
constexpr Slack x0_impl() const
default x in K
constexpr auto circ_impl(const Slack &x, const Slack &y) const
circ
constexpr T alpha_max_impl(const Slack &x, const linalg::Vector< T, M > &p) const
alpha_max (fraction to boundary)
constexpr auto gamma_F_impl(const Slack &x, const Slack &y) const
gamma_F
constexpr T trace_impl(const Slack &x, const Slack &y) const
trace
constexpr bool in_cone_impl(const Slack &x) const
x in K check
constexpr Slack y0_impl() const
default y in K^*
constexpr T alpha_max_dual_impl(const Slack &y, const linalg::Vector< T, M > &p) const
alpha_max dual (fraction to dK^*)
static constexpr bool contains(const element_type &element)
Closed-cone membership, including semidefinite boundary elements.
constexpr T nu_impl() const
barrier param
constexpr auto inv_impl(const Slack &x) const
inv
linalg::space_element_t< ambient_space > element_type
Canonical matrix representation of an ambient-space element.
constexpr auto sqrt_impl(const Slack &x) const
Jordan square root in symmetric-vector coordinates.
constexpr bool in_dual_cone_impl(const Slack &y) const
y in K^* check
constexpr auto e_impl() const
e (jordan identity)
linalg::SymmetricMatrixSpace< T, N > ambient_space
Ambient vector space of real symmetric matrices.
constexpr auto grad_impl(const Slack &x) const
grad (jacobian)