akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
huber.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/assert.hpp"
12
13namespace convex {
14
16template <linalg::RnSpace Space>
17 requires(linalg::space_dim_v<Space> == 1)
19
21template <linalg::RnSpace Space>
22 requires(linalg::space_dim_v<Space> == 1)
24
26template <linalg::RnSpace Space>
27 requires(linalg::space_dim_v<Space> == 1)
29
31template <linalg::RnSpace Space>
32using HuberMeta =
34
36template <linalg::RnSpace Space>
40
44template <typename Meta, typename Child>
45struct Huber : Atom<Meta, Huber<Meta, Child>, Child> {
48 using ConvexBase::N;
51
54
60 constexpr explicit Huber(T delta_in, const Child& child_in)
63 AK_ASSERT(delta_in >= T(0) && "Huber expects delta >= 0");
64 }
65
72 constexpr explicit Huber(T delta_in, const Child& child_in,
73 const affine::AffineMap<LiftedVarMat<T>>& map_in)
75 AK_ASSERT(delta_in >= T(0) && "Huber expects delta >= 0");
76 }
77
83 constexpr MonotonicityType monotonicity() const {
84 static constexpr VarType sign =
86 if constexpr (Tag == CurvatureType::CONVEX) {
87 if constexpr (sign == VarType::NONNEG) {
89 } else if constexpr (sign == VarType::NONPOS) {
91 } else {
93 }
94 } else {
95 if constexpr (sign == VarType::NONNEG) {
97 } else if constexpr (sign == VarType::NONPOS) {
99 } else {
101 }
102 }
103 }
104
112 constexpr T operator()(const PointT& x) const { return eval(x); }
113
121 constexpr T eval(const PointT& x) const {
122 const auto alpha = lift_map.linear_part()(0, 0);
123 const auto beta = lift_map.translation()(0);
124 if (linalg::constexpr_abs(x(0)) <= delta) {
125 if constexpr (Tag == CurvatureType::CONVEX)
126 return alpha * T(0.5) * x(0) * x(0) + beta;
127 else return T(-0.5) * alpha * x(0) * x(0) + beta;
128 } else {
129 if constexpr (Tag == CurvatureType::CONVEX)
130 return alpha * delta * (linalg::constexpr_abs(x(0)) - T(0.5) * delta) +
131 beta;
132 else
133 return T(-1) * alpha * delta *
134 (linalg::constexpr_abs(x(0)) - T(0.5) * delta) +
135 beta;
136 }
137 }
138
144 template <T Scalar>
145 constexpr auto mul() const {
146 if constexpr (Scalar < T(0)) {
147 const auto alpha = T(-1) * Scalar;
148 affine::AffineMap<LiftedVarMat<T>> new_map(alpha * lift_map.linear_part(),
149 lift_map.translation());
150 using Space = dom_space_t<meta_dom_t<Meta>>;
151 if constexpr (Tag == CurvatureType::CONCAVE) {
153 delta, std::get<0>(this->children), new_map);
154 } else {
156 delta, std::get<0>(this->children), new_map);
157 }
158 } else {
159 affine::AffineMap<LiftedVarMat<T>> new_map(
160 Scalar * lift_map.linear_part(), lift_map.translation());
161 return Huber<Meta, Child>(delta, std::get<0>(this->children), new_map);
162 }
163 }
164
172 constexpr auto add(T beta) const {
173 LiftedVarBias<T> bias{beta + lift_map.translation()(0)};
174 affine::AffineMap<LiftedVarMat<T>> new_map(lift_map.linear_part(), bias);
175 return Huber<Meta, Child>(delta, std::get<0>(this->children), new_map);
176 }
177
210 template <AtomType Type, conic::BuilderLike Builder>
211 constexpr auto canonicalize_impl(const Builder& builder) const {
212 const auto child_builder =
213 std::get<0>(this->children)
214 .template canonicalize<AtomType::FN>(builder);
215 const auto child_coord = child_builder.coord_map;
216
217 using AffineMatT = affine::affine_mat_t<decltype(child_coord)>;
218 static constexpr std::size_t Dom = linalg::mat_cols_v<AffineMatT>;
219 static constexpr std::size_t Codom = linalg::mat_rows_v<AffineMatT>;
220 static_assert(Codom == 1,
221 "input affine map from cone block has invalid codom dim for "
222 "scalar fn domain (i.e., != 1");
223
224 linalg::Matrix<T, 9, Dom + 5> F{};
225 linalg::Vector<T, 9> g{};
226 const auto a = child_coord.linear_part();
227 const auto b = child_coord.translation();
228 F = linalg::set_block<0, 1, 0, Dom>(F, a);
229 F = linalg::set_block<1, 2, 0, Dom>(F, T(-1) * a);
230 F(0, Dom) = T(-1), F(0, Dom + 1) = T(-1);
231 F(1, Dom) = T(1), F(1, Dom + 1) = T(1);
232 F(2, Dom) = T(1), F(2, Dom + 2) = T(1);
233 F(3, Dom) = T(-1), F(3, Dom + 2) = T(1);
234 F(4, Dom + 2) = T(1);
235 F(5, Dom + 2) = T(-1) * delta;
236 F(5, Dom + 3) = T(-1);
237 g(0) = b(0);
238 g(1) = T(-1) * b(0);
239
240 linalg::Matrix<T, 3, Dom + 5> F_rsoc{};
241 F_rsoc(0, Dom + 1) = T(1);
242 F_rsoc(2, Dom + 3) = T(1);
243
244 if constexpr (Tag == CurvatureType::CONVEX) {
245 F(5, Dom + 4) = T(1);
246 } else {
247 F(5, Dom + 4) = T(-1);
248 }
249
250 linalg::Vector<T, 3> g_rsoc{T(0), T(0.5), T(0)};
251
252 const auto rsoc_coords =
253 affine::AffineMap<decltype(F_rsoc)>(F_rsoc, g_rsoc);
254 const auto soc_coords =
256 F = linalg::set_block<6, 9, 0, Dom + 5>(F, soc_coords.linear_part());
257 const auto g_hat = soc_coords.translation();
258 g(6) = g_hat(0);
259 g(7) = g_hat(1);
260 g(8) = g_hat(2);
261
262 const auto coord_map_up = affine::AffineMap<decltype(F)>(F, g);
265 const auto cones = std::make_tuple(rplus, rsoc);
266 const auto emission =
268
270 }
271
274 affine::AffineMap<LiftedVarMat<T>> lift_map;
275 const int idx{-1};
276};
277
278template <typename T, typename Child>
279Huber(const T&, const Child&)
282
283} // namespace convex
VarType
Domain/variable annotation attached to domains/codomains.
typename dom_traits< linalg::remove_cvref_t< Dom > >::Space dom_space_t
constexpr std::size_t dom_size_v
CurvatureType
Curvature annotation for atom codomain.
linalg::remove_cvref_t< T > atom_decay_t
normalize atom-facing types to a stable internal form.
MonotonicityType
Monotonicity annotation for function atoms.
linalg::Vector< T, 1 > LiftedVarBias
alias for lifted var map
linalg::RowVector< T, 1 > LiftedVarMat
alias for lifted var map
Atom-local canonical emission bundle.
forward decl for nonneg orthant cone
Definition rplus.hpp:47
RSOC -> SOC.
Definition soc.hpp:40
forward decl for soc
Definition soc.hpp:128
CRTP base for convex atoms.
Definition atom.hpp:22
ChildrenT children
Tuple of normalized child atoms.
Definition atom.hpp:240
dom_point_t< Domain > PointT
Point type accepted by the atom domain.
Definition atom.hpp:32
dom_type_t< Domain > T
Scalar field for the atom domain.
Definition atom.hpp:30
static constexpr std::size_t N
Domain dimension.
Definition atom.hpp:35
Atom metadata bundling domain, codomain, and curvature.
Domain wrapper with a static sign label.
forward declaration - huber
Definition huber.hpp:45
constexpr auto canonicalize_impl(const Builder &builder) const
canonicalize impl
Definition huber.hpp:211
const int idx
Definition huber.hpp:275
static constexpr CurvatureType Tag
curvature tag
Definition huber.hpp:53
constexpr T operator()(const PointT &x) const
eval via operator overload
Definition huber.hpp:112
T delta
member vars
Definition huber.hpp:273
affine::AffineMap< LiftedVarMat< T > > lift_map
Definition huber.hpp:274
constexpr Huber(T delta_in, const Child &child_in, const affine::AffineMap< LiftedVarMat< T > > &map_in)
CTOR.
Definition huber.hpp:72
constexpr Huber(T delta_in, const Child &child_in)
CTOR.
Definition huber.hpp:60
constexpr MonotonicityType monotonicity() const
mono
Definition huber.hpp:83
constexpr auto add(T beta) const
add
Definition huber.hpp:172
constexpr auto mul() const
mul
Definition huber.hpp:145
constexpr T eval(const PointT &x) const
eval impl
Definition huber.hpp:121