akreon-convex
Typed convex modeling, conic canonicalization, and primal-dual optimization in C++26.
Loading...
Searching...
No Matches
atom.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
9#include "akreon/linalg/assert.hpp"
10#include "convex_traits.hpp"
11
12namespace convex {
13
21template <typename Meta, typename Derived, typename... Cs>
22struct Atom {
28 using ChildrenT = std::tuple<atom_decay_t<Cs>...>;
33
35 static constexpr std::size_t N = dom_size_v<Domain>;
37 static constexpr std::size_t M = dom_size_v<Codomain>;
44
48 constexpr explicit Atom() { validate_domain(); }
49
55 constexpr explicit Atom(ChildrenT child_in) : children(std::move(child_in)) {
57 }
58
66 constexpr void validate_fn_domain(const auto& child) const {
67 using ChildCodom = meta_codom_t<atom_meta_t<decltype(child)>>;
70 "Mismatch in size between parent domain and child codomain");
71
74
75 AK_ASSERT((self().monotonicity() != MonotonicityType::UNKNOWN ||
77 "Function with unknown monotonicity requires affine child");
78
81 return;
82
84 if ((self().monotonicity() == MonotonicityType::NONDEC &&
86 (self().monotonicity() == MonotonicityType::NONINC &&
88 return;
89 }
90
92 if ((self().monotonicity() == MonotonicityType::NONDEC &&
94 (self().monotonicity() == MonotonicityType::NONINC &&
96 return;
97 }
98
99 const bool dcp_composition_valid =
101 ((self().monotonicity() == MonotonicityType::NONDEC &&
103 (self().monotonicity() == MonotonicityType::NONINC &&
106 ((self().monotonicity() == MonotonicityType::NONDEC &&
108 (self().monotonicity() == MonotonicityType::NONINC &&
111 "Function composition fails DCP compliance");
113 }
114
120 constexpr void validate_domain() const {
121 std::size_t num_convex = 0, num_concave = 0, num_affine = 0;
122 auto validate_child = [&](const auto& child) {
123 if constexpr (is_fn_type_v<decltype(self())>) {
125 }
126
127 if constexpr (is_set_type_v<decltype(self())>) {
128 static_assert(is_var_type_v<decltype(child)>,
129 "Set expects child to be a variable type");
130 }
131
132 const VarType& dom_sign =
134 if (dom_sign != VarType::FREE) {
135 const VarType& child_sign =
137 switch (dom_sign) {
138 case VarType::POS: {
140 "Parent positive domain expects positive child codomain");
141 break;
142 }
143 case VarType::NONNEG: {
144 AK_ASSERT(
146 "Parent non-negative domain expects "
147 "positive/non-negative child codomain");
148 break;
149 }
150 case VarType::NEG: {
152 "Parent negative domain expects negative child codomain");
153 break;
154 }
155 case VarType::NONPOS: {
156 AK_ASSERT(
158 "Parent non-positive domain expects "
159 "non-positive/negative child codomain");
160 break;
161 }
162 case VarType::PSD: {
164 "Parent PSD domain expects PSD child codomain");
165 break;
166 }
167 case VarType::FREE:
168 default:
169 break;
170 }
172 }
173
174 if constexpr (is_cap_type_v<decltype(self())>) {
175 AK_ASSERT((is_set_type_v<decltype(child)> ||
176 is_cap_type_v<decltype(child)>) &&
177 "Intersection expects each child to be a set or "
178 "intersection");
179 }
180
181 if constexpr (is_add_type_v<decltype(self())>) {
183 AK_ASSERT(!is_set_type_v<decltype(child)> &&
184 "Minkowski sum is not supported for set children");
185 }
186
188 meta_curv_v<atom_meta_t<decltype(child)>>;
192 };
193 std::apply([&](const auto&... child) { (validate_child(child), ...); },
194 children);
195
196 if constexpr (is_add_type_v<decltype(self())>) {
197 if ((num_convex == N || num_convex + num_affine == N) &&
198 num_concave == 0) {
199 // no-op - valid dcp
200 } else if ((num_concave == N || num_concave + num_affine == N) &&
201 num_convex == 0) {
202 // no-op - valid dcp
203 } else {
204 const bool dcp_sum_valid =
205 ((num_convex == N || num_convex + num_affine == N) &&
206 num_concave == 0) ||
207 ((num_concave == N || num_concave + num_affine == N) &&
208 num_convex == 0);
210 "Not dcp valid to sum convex with concave atoms");
212 }
213 }
214 }
215
226 template <AtomType Type, conic::BuilderLike Builder>
227 constexpr auto canonicalize(const Builder& builder) const {
228 return self().template canonicalize_impl<Type>(builder);
229 }
230
236 constexpr const Derived& self() const {
237 return static_cast<const Derived&>(*this);
238 }
239
241};
242
243} // namespace convex
VarType
Domain/variable annotation attached to domains/codomains.
constexpr std::size_t dom_size_v
CurvatureType
Curvature annotation for atom codomain.
constexpr CurvatureType meta_curv_v
constexpr bool is_set_type_v
typename dom_traits< linalg::remove_cvref_t< Dom > >::T dom_type_t
constexpr bool is_fn_type_v
Helper predicates on atom category.
constexpr bool is_add_type_v
typename dom_traits< linalg::remove_cvref_t< Dom > >::Point dom_point_t
constexpr bool is_cap_type_v
typename meta_traits< linalg::remove_cvref_t< Meta > >::Codomain meta_codom_t
typename atom_traits< atom_decay_t< Atom > >::ConvexMeta atom_meta_t
Extract metadata type from atom.
constexpr VarType dom_vartype_v
constexpr bool is_var_type_v
typename meta_traits< linalg::remove_cvref_t< Meta > >::Domain meta_dom_t
CRTP base for convex atoms.
Definition atom.hpp:22
meta_codom_t< Meta > Codomain
Atom output codomain.
Definition atom.hpp:26
constexpr void validate_domain() const
Validate child domains, signs, curvature, and composition rules.
Definition atom.hpp:120
static constexpr VarType CodomSign
Codomain sign declared by atom metadata.
Definition atom.hpp:43
constexpr Atom(ChildrenT child_in)
Construct an atom with normalized children.
Definition atom.hpp:55
static constexpr std::size_t M
Codomain dimension.
Definition atom.hpp:37
ChildrenT children
Tuple of normalized child atoms.
Definition atom.hpp:240
std::tuple< atom_decay_t< Cs >... > ChildrenT
Tuple of decayed child atom types.
Definition atom.hpp:28
constexpr const Derived & self() const
Return this object as the CRTP-derived atom type.
Definition atom.hpp:236
dom_point_t< Domain > PointT
Point type accepted by the atom domain.
Definition atom.hpp:32
static constexpr VarType DomSign
Domain sign declared by atom metadata.
Definition atom.hpp:41
constexpr Atom()
Construct a leaf atom with no children.
Definition atom.hpp:48
constexpr auto canonicalize(const Builder &builder) const
Dispatch canonicalization to the derived atom.
Definition atom.hpp:227
constexpr void validate_fn_domain(const auto &child) const
Validate DCP composition for a function child.
Definition atom.hpp:66
meta_dom_t< Meta > Domain
Atom input domain.
Definition atom.hpp:24
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
static constexpr CurvatureType Curvature
Curvature declared by atom metadata.
Definition atom.hpp:39