akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
norm.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
10
11namespace convex {
12
14template <linalg::RnSpace Space>
16
18template <linalg::RnSpace Space>
19 requires(linalg::space_dim_v<Space> == 1)
21
23template <linalg::RnSpace Space>
24 requires(linalg::space_dim_v<Space> == 1)
26
28template <linalg::RnSpace Dom, linalg::RnSpace Codom>
29using NormMeta =
31
33template <linalg::RnSpace Dom, linalg::RnSpace Codom>
36
40template <typename Meta, typename Child, linalg::NormFunction NormFunc>
41 requires(dom_size_v<meta_dom_t<Meta>> == linalg::norm_dim_v<NormFunc>)
42struct Norm : Atom<Meta, Norm<Meta, Child, NormFunc>, Child> {
45 using ConvexBase::N;
48
50 static constexpr CurvatureType Tag = meta_curv_v<Meta>;
51
57 constexpr explicit Norm(const Child& child_in)
59 }
60
67 constexpr explicit Norm(const Child& child_in,
68 const affine::AffineMap<LiftedVarMat<T>>& map_in)
69 : ConvexBase(child_in), lift_map(map_in) {}
70
76 constexpr MonotonicityType monotonicity() const {
77 static constexpr VarType sign =
79 if constexpr (Tag == CurvatureType::CONVEX) {
80 if constexpr (sign == VarType::NONNEG) {
82 } else if constexpr (sign == VarType::NONPOS) {
84 } else {
86 }
87 } else {
88 if constexpr (sign == VarType::NONNEG) {
90 } else if constexpr (sign == VarType::NONPOS) {
92 } else {
94 }
95 }
96 }
97
105 constexpr T operator()(const PointT& x) const { return eval(x); }
106
114 constexpr T eval(const PointT& x) const {
115 const auto alpha = lift_map.linear_part()(0, 0);
116 const auto beta = lift_map.translation()(0);
117 if constexpr (Tag == CurvatureType::CONVEX)
118 return alpha * NormFunc()(x) + beta;
119 else return T(-1) * alpha * NormFunc()(x) + beta;
120 }
121
127 template <T Scalar>
128 constexpr auto mul() const {
129 if constexpr (Scalar < T(0)) {
130 const auto alpha = T(-1) * Scalar;
131 affine::AffineMap<LiftedVarMat<T>> new_map(alpha * lift_map.linear_part(),
132 lift_map.translation());
133 using Dom = dom_space_t<meta_dom_t<Meta>>;
134 using Codom = dom_space_t<meta_codom_t<Meta>>;
135
136 using Dom = dom_space_t<meta_dom_t<Meta>>;
137 using Codom = dom_space_t<meta_codom_t<Meta>>;
138 if constexpr (Tag == CurvatureType::CONCAVE) {
140 std::get<0>(this->children), new_map);
141 } else {
143 std::get<0>(this->children), new_map);
144 }
145 } else {
146 affine::AffineMap<LiftedVarMat<T>> new_map(
147 Scalar * lift_map.linear_part(), lift_map.translation());
148 return Norm<Meta, Child, NormFunc>(std::get<0>(this->children), new_map);
149 }
150 }
151
159 constexpr auto add(T beta) const {
160 LiftedVarBias<T> bias{beta + lift_map.translation()(0)};
161 affine::AffineMap<LiftedVarMat<T>> new_map(lift_map.linear_part(), bias);
162 return Norm<Meta, Child, NormFunc>(std::get<0>(this->children), new_map);
163 }
164
230 template <AtomType Type, conic::BuilderLike Builder>
231 constexpr auto canonicalize_impl(const Builder& builder) const {
232 using Vec = linalg::Vector<T, N>;
233 const auto child_builder =
234 std::get<0>(this->children)
235 .template canonicalize<AtomType::FN>(builder);
236 const auto child_coord = child_builder.coord_map;
237
238 using AffineMatT = affine::affine_mat_t<decltype(child_coord)>;
239 static constexpr std::size_t Dom = linalg::mat_cols_v<AffineMatT>;
240 static constexpr std::size_t Codom = linalg::mat_rows_v<AffineMatT>;
241 static_assert(Codom == N,
242 "Input affine map from cone block has invalid dom which is a "
243 "mismatch between domain in the convex function");
244 static_assert(Dom == N,
245 "Expecting child affine map to have square linear part");
246
247 if constexpr (std::same_as<NormFunc, linalg::L2<Vec>>) {
248 linalg::Matrix<T, N + 1, Dom + 1> F;
249 F = linalg::set_block<0, N, 0, Dom>(F, child_coord.linear_part());
250
251 linalg::Vector<T, N + 1> g;
252 for (std::size_t i = 0; i < N; ++i) g(i) = child_coord.translation()(i);
253
254 if constexpr (Tag == CurvatureType::CONCAVE) {
255 F(N, N) = T(-1);
256 } else {
257 F(N, N) = T(1);
258 }
259
260 const auto coord_map_up = affine::AffineMap<decltype(F)>(F, g);
261
263 const auto cones = std::make_tuple(soc);
264 const auto emission =
266
267 return child_builder.template realize<Type>(idx, lift_map, emission);
268 } else if constexpr (std::same_as<NormFunc, linalg::Linf<Vec>>) {
269 linalg::Matrix<T, 2 * N, Dom + 1> F;
270 F = linalg::set_block<0, N, 0, N>(F, child_coord.linear_part());
271 F = linalg::set_block<N, 2 * N, 0, N>(F,
272 T(-1) * child_coord.linear_part());
273
274 linalg::Vector<T, 2 * N> g;
275 for (std::size_t i = 0; i < N; ++i) g(i) = child_coord.translation()(i);
276 for (std::size_t i = 0; i < N; ++i)
277 g(i + N) = T(-1) * child_coord.translation()(i);
278
279 if constexpr (Tag == CurvatureType::CONVEX) {
280 for (std::size_t i = 0; i < 2 * N; ++i) F(i, N) = T(1);
281 } else {
282 for (std::size_t i = 0; i < 2 * N; ++i) F(i, N) = T(-1);
283 }
284
285 const auto coord_map_up = affine::AffineMap<decltype(F)>(F, g);
286
288 const auto cones = std::make_tuple(rplus, rplus);
289 const auto emission =
291
292 return child_builder.template realize<Type>(idx, lift_map, emission);
293 } else {
294 linalg::Matrix<T, 3 * N + 1, 2 * Dom + 1> F;
295 const auto I = linalg::make_identity<T, N>();
296 F = linalg::set_block<0, N, 0, N>(F, child_coord.linear_part());
297 F = linalg::set_block<N, 2 * N, 0, N>(F,
298 T(-1) * child_coord.linear_part());
299 F = linalg::set_block<0, N, N, 2 * N>(F, I);
300 F = linalg::set_block<N, 2 * N, N, 2 * N>(F, I);
301 for (std::size_t i = 0; i < N; ++i) F(2 * N, N + i) = T(-1);
302 F = linalg::set_block<2 * N + 1, 3 * N + 1, N, 2 * N>(F, I);
303
304 linalg::Vector<T, 3 * N + 1> g;
305 for (std::size_t i = 0; i < N; ++i) g(i) = child_coord.translation()(i);
306 for (std::size_t i = 0; i < N; ++i)
307 g(i + N) = T(-1) * child_coord.translation()(i);
308
309 if constexpr (Tag == CurvatureType::CONVEX) {
310 F(2 * N, 2 * N) = T(1);
311 } else {
312 F(2 * N, 2 * N) = T(-1);
313 }
314
315 const auto coord_map_up = affine::AffineMap<decltype(F)>(F, g);
316
319 const auto cones = std::make_tuple(rplus1, rplus1, rplus2, rplus1);
320 const auto emission =
322
323 return child_builder.template realize<Type>(idx, lift_map, emission);
324 }
325 }
326
328 affine::AffineMap<LiftedVarMat<T>> lift_map;
329 const int idx{-1};
330};
331
332} // 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.
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
forward decl for soc
Definition soc.hpp:128
CRTP base for convex atoms.
Definition atom.hpp:22
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
Atom metadata bundling domain, codomain, and curvature.
Domain wrapper with a static sign label.
forward declaration - norm fn
Definition norm.hpp:42
affine::AffineMap< LiftedVarMat< T > > lift_map
member vars
Definition norm.hpp:328
constexpr auto mul() const
mul
Definition norm.hpp:128
constexpr Norm(const Child &child_in, const affine::AffineMap< LiftedVarMat< T > > &map_in)
CTOR.
Definition norm.hpp:67
constexpr T eval(const PointT &x) const
eval impl
Definition norm.hpp:114
constexpr auto canonicalize_impl(const Builder &builder) const
canonicalize_impl
Definition norm.hpp:231
constexpr T operator()(const PointT &x) const
eval via operator overload
Definition norm.hpp:105
constexpr Norm(const Child &child_in)
CTOR.
Definition norm.hpp:57
constexpr MonotonicityType monotonicity() const
mono
Definition norm.hpp:76
constexpr auto add(T beta) const
add
Definition norm.hpp:159