tinyopt 700
Tinyopt, a lightweight, header only optimization library
Loading...
Searching...
No Matches
helpers.h
1// Copyright 2026 Julien Michot.
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include <tinyopt/math.h>
7#include <tinyopt/traits.h>
8
9/***
10 * @brief Macro helper to define a loss, see activations.h for examples.
11 * Not sure it was a good idea but look at activations.h, it's sooo slim!
12 */
13#define DefineLoss(name, code, jac_code) \
14 template <typename T, typename ExportJ> \
15 auto name(const T &x, const ExportJ &Jx_or_bool); \
16 /* Loss that only returns the final loss */ \
17 template <typename T> \
18 auto name(const T &x) { \
19 if constexpr (traits::is_pair_v<T>) { \
20 return name(x.first, x.second); \
21 } else { \
22 constexpr bool IsMatrix = traits::is_matrix_or_array_v<T> || traits::is_sparse_matrix_v<T>; \
23 if constexpr (IsMatrix) { /* matrix */ \
24 using Scalar = typename T::Scalar; \
25 return x.unaryExpr([](Scalar v) { return name<Scalar>(v); }).eval(); \
26 } else { /* scalar */ \
27 using Scalar = std::decay_t<T>; \
28 return Scalar((code)); \
29 } \
30 } \
31 } \
32 /* Loss that returns both the loss and the Jacobian */ \
33 template <typename T, typename ExportJ> \
34 auto name(const T &x, const ExportJ &Jx_or_bool) { \
35 constexpr bool HasJac = traits::is_matrix_or_scalar_v<std::decay_t<ExportJ>>; \
36 constexpr bool IsMatrix = traits::is_matrix_or_array_v<T> || traits::is_sparse_matrix_v<T>; \
37 const auto l = name(x); \
38 if constexpr (IsMatrix) { /* matrix */ \
39 using Scalar = typename T::Scalar; \
40 const auto J = ((jac_code)); \
41 if constexpr (HasJac) { \
42 return std::make_pair(l, (J * Jx_or_bool).matrix().eval()); \
43 } else { \
44 constexpr int DimsJ = traits::params_trait<T>::Dims; \
45 return std::make_pair(l, Matrix<Scalar, DimsJ, DimsJ>(J)); \
46 } \
47 } else { /* scalar */ \
48 if constexpr (HasJac) { \
49 return std::make_pair(l, (0 /*TODO*/ * Jx_or_bool).matrix().eval()); \
50 } else { \
51 return std::make_pair(l, 0 /*TODO*/); \
52 } \
53 } \
54 }
55
56/***
57 * @brief Macro helper to define a loss with a parameter `a`, see activations.h for examples
58 */
59#define DefineLoss2(name, code, jac_code) \
60 template <typename T, typename ExportJ, typename ParamType = float> \
61 auto name(const T &x, ParamType a, const ExportJ &Jx_or_bool); \
62 /* Loss that only returns the final loss */ \
63 template <typename T, typename ParamType = float> \
64 auto name(const T &x, ParamType a) { \
65 if constexpr (traits::is_pair_v<T>) { \
66 return name(x.first, x.second, a); \
67 } else { \
68 constexpr bool IsMatrix = traits::is_matrix_or_array_v<T> || traits::is_sparse_matrix_v<T>; \
69 if constexpr (IsMatrix) { /* matrix */ \
70 using Scalar = typename T::Scalar; \
71 return x.unaryExpr([a](Scalar v) -> Scalar { return name<Scalar>(v, a); }).eval(); \
72 } else { /* scalar */ \
73 using Scalar = std::decay_t<T>; \
74 return Scalar((code)); \
75 } \
76 } \
77 } \
78 /* Loss that returns both the loss and the Jacobian */ \
79 template <typename T, typename ExportJ, typename ParamType> \
80 auto name(const T &x, ParamType a, const ExportJ &Jx_or_bool) { \
81 constexpr bool HasJac = traits::is_matrix_or_scalar_v<std::decay_t<ExportJ>>; \
82 constexpr bool IsMatrix = traits::is_matrix_or_array_v<T> || traits::is_sparse_matrix_v<T>; \
83 const auto l = name(x, a); \
84 if constexpr (IsMatrix) { /* matrix */ \
85 using Scalar = typename T::Scalar; \
86 const auto J = ((jac_code)); \
87 if constexpr (HasJac) { \
88 return std::make_pair(l, (J * Jx_or_bool).matrix().eval()); \
89 } else { \
90 constexpr int DimsJ = traits::params_trait<T>::Dims; \
91 return std::make_pair(l, Matrix<Scalar, DimsJ, DimsJ>(J)); \
92 } \
93 } else { /* scalar */ \
94 if constexpr (HasJac) { \
95 return std::make_pair(l, ((0 /*TODO*/) * Jx_or_bool).matrix().eval()); \
96 } else { \
97 return std::make_pair(l, 0 /*TODO*/); \
98 } \
99 } \
100 }