akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
rplus.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/operator/quadratic_rep.hpp"
10
11namespace conic {
12
18template <linalg::VectorContainer Vec>
19struct RplusCirc {
21 using T = linalg::vector_element_t<Vec>;
22 static constexpr std::size_t N = linalg::vector_dim_v<Vec>;
23
34 constexpr auto operator()(const Vec& x, const Vec& y) const {
35 Vec res{};
36 for (std::size_t i = 0; i < N; ++i) res(i) = x(i) * y(i);
37 return res;
38 }
39};
40
45template <linalg::VectorContainer Slack>
47 : public Cone<Slack, NonnegOrthantCone<Slack>, ConeType::SYMMETRIC> {
50
52 using ConeBase::eps;
53 using ConeBase::M;
54 using typename ConeBase::HessianMat;
55 using typename ConeBase::T;
56
62 constexpr Slack x0_impl() const {
63 Slack s{};
64 for (std::size_t i = 0; i < M; ++i) s(i) = T(1);
65 return s;
66 }
67
73 constexpr Slack y0_impl() const { return x0_impl(); }
74
82 constexpr bool in_cone_impl(const Slack& x) const {
83 for (std::size_t i = 0; i < M; ++i)
84 if (!(x(i) > T(0))) return false;
85 return true;
86 }
87
95 constexpr bool in_dual_cone_impl(const Slack& y) const {
96 return in_cone_impl(y);
97 }
98
114 constexpr T alpha_max_impl(const Slack& x,
115 const linalg::Vector<T, M>& p) const {
116 constexpr T eta{0.99};
117 T a{1};
118 for (std::size_t i = 0; i < M; ++i) {
119 if (p(i) < T(0)) {
120 const T cand = -x(i) / p(i);
121 a = (cand < a) ? cand : a;
122 }
123 }
124 return std::min(T(1), eta * a);
125 }
126
135 constexpr T alpha_max_dual_impl(const Slack& y,
136 const linalg::Vector<T, M>& p) const {
137 return alpha_max_impl(y, p);
138 }
139
156 constexpr auto H_impl(const Slack& x, const Slack& y) const {
157 const auto [w, event] = w_impl(x, y);
158 if (linalg::is_fatal_event(event))
159 return std::tuple(
160 linalg::QuadraticRep<HessianMat, RplusCirc<Slack>>(e_impl()), event);
161 Slack w_inv{};
162 bool safeguarded = false;
163 for (std::size_t i = 0; i < M; ++i) {
164 const T wi_safe = std::max(w(i), eps);
165 safeguarded = safeguarded || (wi_safe != w(i));
166 w_inv(i) = T(1) / wi_safe;
167 }
168 const auto out_event =
169 linalg::is_fatal_event(event) ? event
170 : (event != linalg::NumericalEvent::NONE || safeguarded)
171 ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
172 : linalg::NumericalEvent::NONE;
173 return std::tuple(linalg::QuadraticRep<HessianMat, RplusCirc<Slack>>(w_inv),
174 out_event);
175 }
176
186 constexpr auto grad_impl(const Slack& x) const {
187 Slack dx{};
188 bool safeguarded = false;
189 for (std::size_t i = 0; i < M; ++i) {
190 const T xi_safe = std::max(x(i), eps);
191 safeguarded = safeguarded || (xi_safe != x(i));
192 dx(i) = T(-1) / xi_safe;
193 }
194 return std::tuple(dx, safeguarded
195 ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
196 : linalg::NumericalEvent::NONE);
197 }
198
204 constexpr T nu_impl() const { return static_cast<T>(M); }
205
213 constexpr auto e_impl() const {
214 linalg::vector_traits<Slack> vec{};
215 return vec.fill(T(1));
216 }
217
226 constexpr auto w_impl(const Slack& x, const Slack& y) const {
227 Slack w{};
228 bool safeguarded{false};
229 for (std::size_t i = 0; i < M; ++i) {
230 const T x_safe = std::max(x(i), eps);
231 const T y_safe = std::max(y(i), eps);
232 safeguarded = safeguarded || (x_safe != x(i)) || (y_safe != y(i));
233 w(i) = linalg::constexpr_sqrt_safe(x_safe / y_safe);
234 }
235 return std::tuple(w, safeguarded
236 ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
237 : linalg::NumericalEvent::NONE);
238 }
239
250 constexpr auto circ_impl(const Slack& x, const Slack& y) const {
251 return RplusCirc<Slack>()(x, y);
252 }
253
264 template <typename Scaling>
265 constexpr auto scaled_affine_correction_impl(const Slack& x, const Scaling&,
266 const Slack& px,
267 const Slack& py) const {
268 Slack correction{};
269 bool safeguarded = false;
270 for (std::size_t i = 0; i < M; ++i) {
271 const T xi_safe = std::max(x(i), eps);
272 safeguarded = safeguarded || (xi_safe != x(i));
273 correction(i) = px(i) * py(i) * (T(1) / xi_safe);
274 }
275 return std::tuple(correction,
276 safeguarded ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
277 : linalg::NumericalEvent::NONE);
278 }
279
290 constexpr auto trace_impl(const Slack& x, const Slack& y) const {
291 const auto x_circ_y = circ_impl(x, y);
292 T res{};
293 for (std::size_t i = 0; i < M; ++i) res += x_circ_y(i);
294 return res;
295 }
296
304 constexpr auto inv_impl(const Slack& x) const {
305 Slack res{};
306 bool safeguarded = false;
307 for (std::size_t i = 0; i < M; ++i) {
308 const T xi_safe = std::max(x(i), eps);
309 safeguarded = safeguarded || (xi_safe != x(i));
310 res(i) = T(1) / xi_safe;
311 }
312 return std::tuple(res, safeguarded
313 ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
314 : linalg::NumericalEvent::NONE);
315 }
316
325 constexpr auto gamma_F_impl(const Slack& x, const Slack& y) const {
326 T res{};
327 bool safeguarded = false;
328 for (std::size_t i = 0; i < M; ++i) {
329 const auto xy_safe = std::max(x(i) * y(i), eps);
330 safeguarded = safeguarded || (xy_safe != x(i) * y(i));
331 res += linalg::constexpr_ln_safe(xy_safe, eps);
332 }
333 const auto xTy_safe =
334 std::max(linalg::inner_product(x, y), eps) / nu_impl();
335 safeguarded =
336 safeguarded || (xTy_safe * nu_impl() != linalg::inner_product(x, y));
337 res = nu_impl() * linalg::constexpr_ln_safe(xTy_safe, eps) - res;
338 return std::tuple(res, safeguarded
339 ? linalg::NumericalEvent::NUMERICAL_SAFEGUARD
340 : linalg::NumericalEvent::NONE);
341 }
342};
343
344} // 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
forward decl for nonneg orthant cone
Definition rplus.hpp:47
constexpr bool in_dual_cone_impl(const Slack &y) const
in interior of K^*
Definition rplus.hpp:95
constexpr T alpha_max_impl(const Slack &x, const linalg::Vector< T, M > &p) const
fraction to boundary dK
Definition rplus.hpp:114
constexpr auto trace_impl(const Slack &x, const Slack &y) const
trace
Definition rplus.hpp:290
constexpr auto inv_impl(const Slack &x) const
jordan inverse
Definition rplus.hpp:304
constexpr auto e_impl() const
e (jordan identity)
Definition rplus.hpp:213
constexpr T nu_impl() const
barrier parameter
Definition rplus.hpp:204
constexpr auto grad_impl(const Slack &x) const
grad
Definition rplus.hpp:186
constexpr auto circ_impl(const Slack &x, const Slack &y) const
circ
Definition rplus.hpp:250
constexpr auto gamma_F_impl(const Slack &x, const Slack &y) const
gamma_F
Definition rplus.hpp:325
constexpr T alpha_max_dual_impl(const Slack &y, const linalg::Vector< T, M > &p) const
fracto to dK^*
Definition rplus.hpp:135
constexpr auto w_impl(const Slack &x, const Slack &y) const
w (self-scaled point)
Definition rplus.hpp:226
constexpr auto H_impl(const Slack &x, const Slack &y) const
hessian
Definition rplus.hpp:156
constexpr auto scaled_affine_correction_impl(const Slack &x, const Scaling &, const Slack &px, const Slack &py) const
Componentwise form of the NT-scaled affine correction for R^n_+.
Definition rplus.hpp:265
constexpr bool in_cone_impl(const Slack &x) const
in interior of K
Definition rplus.hpp:82
constexpr Slack y0_impl() const
default dual point
Definition rplus.hpp:73
constexpr Slack x0_impl() const
default interior point
Definition rplus.hpp:62
Circ - Jordan Map/Product for R^n_+.
Definition rplus.hpp:19
constexpr auto operator()(const Vec &x, const Vec &y) const
circ (jordan map/product)
Definition rplus.hpp:34
linalg::vector_element_t< Vec > T
types and size extraction
Definition rplus.hpp:21
static constexpr std::size_t N
Definition rplus.hpp:22