akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
log_sum_exp.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 <algorithm>
9
12
13namespace convex {
14
16template <linalg::RnSpace Space>
18
20template <linalg::RnSpace Space>
21 requires(linalg::space_dim_v<Space> == 1)
23
25template <linalg::RnSpace Space>
26 requires(linalg::space_dim_v<Space> == 1)
28
30template <linalg::RnSpace Dom, linalg::RnSpace Codom>
33
35template <linalg::RnSpace Dom, linalg::RnSpace Codom>
39
49template <typename Meta, typename Child>
50struct LogSumExp : Atom<Meta, LogSumExp<Meta, Child>, Child> {
53 using ConvexBase::N;
56
59
65 constexpr explicit LogSumExp(const Child& child_in)
67 }
68
75 constexpr explicit LogSumExp(const Child& child_in,
76 const affine::AffineMap<LiftedVarMat<T>>& map_in)
78
84 constexpr MonotonicityType monotonicity() const {
85 if constexpr (Tag == CurvatureType::CONVEX) return MonotonicityType::NONDEC;
86 else return MonotonicityType::NONINC;
87 }
88
96 constexpr T operator()(const PointT& x) const { return eval(x); }
97
105 constexpr T eval(const PointT& x) const {
106 T sum(0);
107 std::for_each(x.begin(), x.end(),
108 [&](const auto& pt) { sum += linalg::constexpr_exp(pt); });
109
110 const auto res = linalg::constexpr_ln_safe(sum);
111
112 if constexpr (Tag == CurvatureType::CONVEX) return res;
113 else { return T(-1) * res; }
114 }
115
121 template <T Scalar>
122 constexpr auto mul() const {
123 if constexpr (Scalar < T(0)) {
124 const auto alpha = T(-1) * Scalar;
125 affine::AffineMap<LiftedVarMat<T>> new_map(alpha * lift_map.linear_part(),
126 lift_map.translation());
127
128 using Dom = dom_space_t<meta_dom_t<Meta>>;
129 using Codom = dom_space_t<meta_codom_t<Meta>>;
130 if constexpr (Tag == CurvatureType::CONCAVE) {
132 std::get<0>(this->children), new_map);
133 } else {
135 std::get<0>(this->children), new_map);
136 }
137 } else {
138 affine::AffineMap<LiftedVarMat<T>> new_map(
139 Scalar * lift_map.linear_part(), lift_map.translation());
140 return LogSumExp<Meta, Child>(std::get<0>(this->children), new_map);
141 }
142 }
143
151 constexpr auto add(T beta) const {
152 LiftedVarBias<T> bias{beta + lift_map.translation()(0)};
153 affine::AffineMap<LiftedVarMat<T>> new_map(lift_map.linear_part(), bias);
154 return LogSumExp<Meta, Child>(std::get<0>(this->children), new_map);
155 }
156
196 template <AtomType Type, conic::BuilderLike Builder>
197 constexpr auto canonicalize_impl(const Builder& builder) const {
198 const auto child_builder =
199 std::get<0>(this->children)
200 .template canonicalize<AtomType::FN>(builder);
201 const auto child_coord = child_builder.coord_map;
202
203 using AffineMatT = affine::affine_mat_t<decltype(child_coord)>;
204 static constexpr std::size_t Dom = linalg::mat_cols_v<AffineMatT>;
205 static constexpr std::size_t Codom = linalg::mat_rows_v<AffineMatT>;
206 static_assert(Codom == N,
207 "Input affine map from cone block has invalid dom which is a "
208 "mismatch between domain in the convex function");
209 static_assert(Dom == N,
210 "Expecting child affine map to have square linear part");
211 linalg::Matrix<T, 3 * N + 1, 2 * Dom + 1> F;
212 linalg::Vector<T, 3 * N + 1> g;
213 F = linalg::set_block<0, N, 0, Dom>(F, child_coord.linear_part());
214 const auto I = linalg::make_identity<T, Dom>();
215
216 if constexpr (Tag == CurvatureType::CONVEX) {
217 for (std::size_t i = 0; i < N; ++i) F(i, N) = T(-1);
218 } else {
219 for (std::size_t i = 0; i < N; ++i) F(i, N) = T(1);
220 }
221 F = linalg::set_block<2 * N, 3 * N, N + 1, 2 * N + 1>(F, I);
222 for (std::size_t i = 0; i < N; ++i) F(3 * N, N + 1 + i) = T(-1);
223 for (std::size_t i = 0; i < N; ++i) g(i) = child_coord.translation()(i);
224 for (std::size_t i = N; i < 2 * N; ++i) g(i) = T(1);
225 g(3 * N) = T(1);
226
227 const auto coord_map_up = affine::AffineMap<decltype(F)>(F, g);
230 const auto cones = std::make_tuple(exp_cone, rplus);
231 const auto emission =
233
235 }
236
238 affine::AffineMap<LiftedVarMat<T>> lift_map;
239 const int idx{-2};
240};
241
242template <typename Child>
246 linalg::Matrix<dom_type_t<meta_codom_t<atom_meta_t<Child>>>, 1, 1>>,
248
249} // namespace convex
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
forward decl for exp
Definition exp_cone.hpp:25
Atom-local canonical emission bundle.
forward decl for nonneg orthant cone
Definition rplus.hpp:47
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 - log sum exp fn
constexpr auto add(T beta) const
add
constexpr auto mul() const
mul
constexpr LogSumExp(const Child &child_in)
CTOR.
static constexpr CurvatureType Tag
curvature tag
affine::AffineMap< LiftedVarMat< T > > lift_map
member vars
constexpr T eval(const PointT &x) const
eval impl
constexpr MonotonicityType monotonicity() const
mono
constexpr LogSumExp(const Child &child_in, const affine::AffineMap< LiftedVarMat< T > > &map_in)
CTOR.
constexpr T operator()(const PointT &x) const
eval via operator overload
constexpr auto canonicalize_impl(const Builder &builder) const
canonicalize impl