tinyopt 700
Tinyopt, a lightweight, header only optimization library
Loading...
Searching...
No Matches
parameter_traits.h
1// Copyright 2026 Julien Michot.
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include <cassert>
7#include <type_traits>
8#include <utility>
9
10#include <tinyopt/traits/matrix_traits.h>
11
12namespace tinyopt::traits {
13
14template <typename T, typename = void>
16 using Scalar = typename T::Scalar;
17 static constexpr Index Dims = Dynamic;
18
19 static Index dims(const T &v) { return v.dims(); }
20
21 template <typename T2>
22 static auto cast(const T &v) {
23 if constexpr (has_static_cast_v<T>)
24 return T::template cast<T2>(v);
25 else if constexpr (has_cast_v<T>)
26 return v.template cast<T2>();
27 else
28 return T2(v);
29 }
30
31 static void PlusEq(T &v, const auto &delta) { v += delta; }
32};
33
34template <typename T>
35struct params_trait<T, std::void_t<decltype(T::Dims)>> {
36 using Scalar = typename T::Scalar;
37 static constexpr Index Dims = T::Dims;
38
39 static Index dims(const T &v) { return Dims == Dynamic ? v.dims() : Dims; }
40
41 template <typename T2>
42 static auto cast(const T &v) {
43 if constexpr (has_static_cast_v<T>)
44 return T::template cast<T2>(v);
45 else if constexpr (has_cast_v<T>)
46 return v.template cast<T2>();
47 else
48 return T2(v);
49 }
50
51 static void PlusEq(T &v, const auto &delta) { v += delta; }
52};
53
54template <typename T>
55struct params_trait<T, std::enable_if_t<std::is_scalar_v<T>>> {
56 using Scalar = T;
57 static constexpr Index Dims = 1;
58
59 static constexpr Index dims(const T &) { return 1; }
60
61 template <typename T2>
62 static T2 cast(const T &v) {
63 return static_cast<T2>(v);
64 }
65
66 static void PlusEq(T &v, const auto &delta) { v += delta[0]; }
67 static void PlusEq(T &v, const Scalar &delta) { v += delta; }
68};
69
70template <typename T>
71struct params_trait<T, std::enable_if_t<is_matrix_or_array_v<T>>> {
72 using Scalar = typename T::Scalar;
73 static constexpr int ColsAtCompileTime = T::ColsAtCompileTime;
74 static constexpr Index Dims =
75 (T::RowsAtCompileTime == Dynamic || T::ColsAtCompileTime == Dynamic)
76 ? Dynamic
77 : T::RowsAtCompileTime * T::ColsAtCompileTime;
78
79 static Index dims(const T &m) { return m.size(); }
80
81 template <typename T2>
82 static auto cast(const T &v) {
83 return v.template cast<T2>().eval();
84 }
85
86 static void PlusEq(T &v, const auto &delta) {
87 if constexpr (Dims == Dynamic) assert(delta.rows() == (int)v.size());
88 if constexpr (T::ColsAtCompileTime == 1)
89 v += delta;
90 else
91 v += delta.reshaped(v.rows(), v.cols());
92 }
93};
94
95template <typename T>
96struct params_trait<T, std::enable_if_t<is_sparse_matrix_v<T>>> {
97 using Scalar = typename T::Scalar;
98 static constexpr Index Dims = Dynamic;
99
100 static Index dims(const T &m) { return m.size(); }
101
102 template <typename T2>
103 static auto cast(const T &v) {
104 return v.template cast<T2>().eval();
105 }
106
107 static void PlusEq(T &v, const auto &delta) {
108 if constexpr (Dims == Dynamic) assert(delta.rows() == (int)v.size());
109 if constexpr (T::ColsAtCompileTime == 1)
110 v += delta;
111 else
112 v += delta.reshaped(v.rows(), v.cols());
113 }
114};
115
116template <typename _Scalar>
117struct params_trait<std::vector<_Scalar>> {
118 using T = typename std::vector<_Scalar>;
119 using Scalar = _Scalar;
120 using ScalarParamsTraits = params_trait<Scalar>;
121 static constexpr Index Dims = Dynamic;
122
123 static Index dims(const T &v) {
124 constexpr int ScalarDims = ScalarParamsTraits::Dims;
125 if constexpr (std::is_scalar_v<Scalar> || ScalarDims == 1) {
126 return static_cast<int>(v.size());
127 } else if constexpr (ScalarDims == Dynamic) {
128 int d = 0;
129 for (std::size_t i = 0; i < v.size(); ++i) d += ScalarParamsTraits::dims(v[i]);
130 return d;
131 } else {
132 return static_cast<int>(v.size()) * ScalarDims;
133 }
134 }
135
136 template <typename T2>
137 static auto cast(const T &v) {
138 using Scalar2 = std::decay_t<decltype(ScalarParamsTraits::template cast<T2>(std::declval<Scalar>()))>;
139 std::vector<Scalar2> o;
140 o.reserve(v.size());
141 for (auto &x : v) o.emplace_back(ScalarParamsTraits::template cast<T2>(x));
142 return o;
143 }
144
145 static void PlusEq(T &v, const auto &delta) {
146 for (std::size_t i = 0; i < v.size(); ++i) {
147 if constexpr (std::is_scalar_v<Scalar> || ScalarParamsTraits::Dims == 1)
148 v[i] += delta[i];
149 else if constexpr (ScalarParamsTraits::Dims != Dynamic) {
150 ScalarParamsTraits::PlusEq(
151 v[i], delta.template segment<ScalarParamsTraits::Dims>(i * ScalarParamsTraits::Dims));
152 } else {
153 ScalarParamsTraits::PlusEq(v[i], delta.segment(i, i * ScalarParamsTraits::dims(v[i])));
154 }
155 }
156 }
157};
158
159template <typename _Scalar, std::size_t N>
160struct params_trait<std::array<_Scalar, N>> {
161 using T = typename std::array<_Scalar, N>;
162 using Scalar = _Scalar;
163 using ScalarParamsTraits = params_trait<Scalar>;
164 static constexpr Index Dims =
165 ScalarParamsTraits::Dims == Dynamic ? Dynamic : N * ScalarParamsTraits::Dims;
166
167 static Index dims(const T &v) {
168 constexpr int ScalarDims = ScalarParamsTraits::Dims;
169 if constexpr (std::is_scalar_v<Scalar> || ScalarDims == 1) {
170 return N;
171 } else if constexpr (ScalarDims == Dynamic) {
172 int d = 0;
173 for (std::size_t i = 0; i < N; ++i) d += ScalarParamsTraits::dims(v[i]);
174 return d;
175 } else {
176 return static_cast<Index>(v.size()) * ScalarDims;
177 }
178 }
179
180 template <typename T2>
181 static auto cast(const T &v) {
182 using Scalar2 = std::decay_t<decltype(ScalarParamsTraits::template cast<T2>(std::declval<Scalar>()))>;
183 std::array<Scalar2, N> o;
184 for (std::size_t i = 0; i < N; ++i) o[i] = ScalarParamsTraits::template cast<T2>(v[i]);
185 return o;
186 }
187
188 static void PlusEq(T &v, const auto &delta) {
189 for (std::size_t i = 0; i < N; ++i) {
190 if constexpr (std::is_scalar_v<Scalar> || ScalarParamsTraits::Dims == 1)
191 v[i] += delta[i];
192 else if constexpr (ScalarParamsTraits::Dims != Dynamic) {
193 ScalarParamsTraits::PlusEq(
194 v[i], delta.template segment<ScalarParamsTraits::Dims>(i * ScalarParamsTraits::Dims));
195 } else {
196 ScalarParamsTraits::PlusEq(v[i], delta.segment(i, i * ScalarParamsTraits::dims(v[i])));
197 }
198 }
199 }
200};
201
202template <typename T1, typename T2>
203struct params_trait<std::pair<T1, T2>> {
204 using T = std::pair<T1, T2>;
205 using Scalar = typename params_trait<T1>::Scalar;
206 using Scalar1ParamsTraits = params_trait<T1>;
207 using Scalar2ParamsTraits = params_trait<T2>;
208 static constexpr Index Dims =
209 (Scalar1ParamsTraits::Dims == Dynamic || Scalar2ParamsTraits::Dims == Dynamic)
210 ? Dynamic
211 : Scalar1ParamsTraits::Dims + Scalar2ParamsTraits::Dims;
212
213 static Index dims(const T &v) {
214 return Scalar1ParamsTraits::dims(v.first) + Scalar2ParamsTraits::dims(v.second);
215 }
216
217 template <typename T3>
218 static auto cast(const T &v) {
219 using Scalar1 = std::decay_t<decltype(Scalar1ParamsTraits::template cast<T3>(std::declval<T1>()))>;
220 using Scalar2 = std::decay_t<decltype(Scalar2ParamsTraits::template cast<T3>(std::declval<T2>()))>;
221 std::pair<Scalar1, Scalar2> o{Scalar1ParamsTraits::template cast<T3>(v.first),
222 Scalar2ParamsTraits::template cast<T3>(v.second)};
223 return o;
224 }
225
226 static void PlusEq(T &v, const auto &delta) {
227 if constexpr (Scalar1ParamsTraits::Dims == Dynamic)
228 Scalar1ParamsTraits::PlusEq(v.first, delta.head(Scalar1ParamsTraits::dims(v.first)));
229 else
230 Scalar1ParamsTraits::PlusEq(v.first, delta.template head<Scalar1ParamsTraits::Dims>());
231 if constexpr (Scalar2ParamsTraits::Dims == Dynamic)
232 Scalar2ParamsTraits::PlusEq(v.second, delta.tail(Scalar2ParamsTraits::dims(v.second)));
233 else
234 Scalar2ParamsTraits::PlusEq(v.first, delta.template tail<Scalar2ParamsTraits::Dims>());
235 }
236};
237
238template <typename T>
239inline auto DynDims(const T &x) {
240 using ptrait = params_trait<T>;
241 if constexpr (ptrait::Dims == Dynamic)
242 return ptrait::dims(x);
243 else
244 return ptrait::Dims;
245}
246
247} // namespace tinyopt::traits
Definition parameter_traits.h:15