OpenKalman
Any.hpp
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2022-2025 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
17 #ifndef OPENKALMAN_ANYATOMICVECTORTYPES_HPP
18 #define OPENKALMAN_ANYATOMICVECTORTYPES_HPP
19 
20 #include <memory>
22 #include "linear-algebra/coordinates/interfaces/coordinate_descriptor_traits.hpp"
28 
30 {
36 #ifdef __cpp_concepts
37  template<values::number Scalar = double>
38 #else
39  template<typename Scalar = double>
40 #endif
41  struct Any
42  {
43  private:
44 
45  using Getter = std::function<Scalar(std::size_t)>;
46  using Setter = std::function<void(const Scalar&, std::size_t)>;
47 
48  struct Base
49  {
50  virtual ~Base() = default;
51  [[nodiscard]] virtual std::size_t dimension() const = 0;
52  [[nodiscard]] virtual std::size_t stat_dimension() const = 0;
53  [[nodiscard]] virtual bool is_euclidean() const = 0;
54  [[nodiscard]] virtual std::size_t hash_code() const = 0;
55  [[nodiscard]] virtual Scalar to_stat_space(const Getter& g, std::size_t euclidean_local_index) const = 0;
56  [[nodiscard]] virtual Scalar from_stat_space(const Getter& g, std::size_t local_index) const = 0;
57  [[nodiscard]] virtual Scalar get_wrapped_component(const Getter& g, std::size_t local_index) const = 0;
58  virtual void set_wrapped_component(const Setter& s, const Getter& g, const Scalar& x, std::size_t local_index) const = 0;
59  };
60 
61 
62  template <typename T>
63  struct Derived : Base
64  {
65  template<typename Arg>
66  explicit Derived(Arg&& arg) : my_t(std::forward<Arg>(arg)) {}
67 
68  [[nodiscard]] std::size_t dimension() const final { return get_dimension(my_t); }
69 
70  [[nodiscard]] std::size_t stat_dimension() const final { return get_stat_dimension(my_t); }
71 
72  [[nodiscard]] bool is_euclidean() const final { return get_is_euclidean(my_t); }
73 
74  [[nodiscard]] std::size_t hash_code() const final { return internal::get_hash_code(my_t); }
75 
76  [[nodiscard]] Scalar to_stat_space(const Getter& g, std::size_t euclidean_local_index) const final
77  {
78  return coordinates::to_stat_space(my_t, g, euclidean_local_index);
79  }
80 
81  [[nodiscard]] Scalar from_stat_space(const Getter& g, std::size_t local_index) const final
82  {
83  return coordinates::from_stat_space(my_t, g, local_index);
84  }
85 
86  [[nodiscard]] Scalar get_wrapped_component(const Getter& g, std::size_t local_index) const final
87  {
88  return coordinates::get_wrapped_component(my_t, g, local_index);
89  }
90 
91  void set_wrapped_component(const Setter& s, const Getter& g, const Scalar& x, std::size_t local_index) const final
92  {
93  coordinates::set_wrapped_component(my_t, s, g, x, local_index);
94  }
95 
96  private:
97 
98  T my_t;
99  };
100 
101  public:
102 
106 #ifdef __cpp_concepts
107  template <descriptor Arg>
108 #else
109  template<typename Arg, std::enable_if_t<descriptor<Arg>, int> = 0>
110 #endif
111  explicit constexpr
112  Any(Arg&& arg) : mBase {std::make_shared<Derived<std::decay_t<Arg>>>(std::forward<Arg>(arg))} {}
113 
114  private:
115 
116  const std::shared_ptr<Base> mBase;
117 
118 #ifdef __cpp_concepts
119  template<typename T>
120 #else
121  template<typename T, typename>
122 #endif
124 
125  };
126 
127 
128 } // namespace OpenKalman::coordinates
129 
130 
131 namespace OpenKalman::interface
132 {
137  template<typename Scalar>
138  struct coordinate_descriptor_traits<coordinates::Any<Scalar>>
139  {
140  private:
141 
142  using T = coordinates::Any<Scalar>;
143  using Getter = std::function<Scalar(std::size_t)>;
144  using Setter = std::function<void(const Scalar&, std::size_t)>;
145 
146  public:
147 
148  static constexpr bool is_specialized = true;
149 
150 
151  using scalar_type = Scalar;
152 
153 
154  static constexpr auto
155  dimension(const T& t) { return t.mBase->dimension(); }
156 
157 
158  static constexpr auto
159  stat_dimension(const T& t) { return t.mBase->stat_dimension(); }
160 
161 
162  static constexpr auto
163  is_euclidean(const T& t) { return t.mBase->is_euclidean(); }
164 
165 
166  static constexpr std::size_t
167  hash_code(const T& t) { return t.mBase->hash_code(); }
168 
169 
170 #ifdef __cpp_concepts
171  static constexpr values::value auto
172  to_euclidean_component(const T& t, const auto& g, const values::index auto& euclidean_local_index)
173  requires requires(std::size_t i){ {g(i)} -> std::convertible_to<scalar_type>; }
174 #else
175  template<typename Getter, typename L, std::enable_if_t<values::index<L> and
176  std::is_convertible_v<typename std::invoke_result<const Getter&, std::size_t>::type, scalar_type> and values::index<L>, int> = 0>
177  static constexpr auto
178  to_euclidean_component(const T& t, const Getter& g, const L& euclidean_local_index)
179 #endif
180  {
181  return t.mBase->to_stat_space(g, euclidean_local_index);
182  }
183 
184 
185 #ifdef __cpp_concepts
186  static constexpr values::value auto
187  from_euclidean_component(const T& t, const auto& g, const values::index auto& local_index)
188  requires requires(std::size_t i){ {g(i)} -> std::convertible_to<scalar_type>; }
189 #else
190  template<typename Getter, typename L, std::enable_if_t<values::index<L> and
191  std::is_convertible_v<typename std::invoke_result<const Getter&, std::size_t>::type, scalar_type>, int> = 0>
192  static constexpr auto
193  from_euclidean_component(const T& t, const Getter& g, const L& local_index)
194 #endif
195  {
196  return t.mBase->from_stat_space(g, local_index);
197  }
198 
199 
200 #ifdef __cpp_concepts
201  static constexpr values::value auto
202  get_wrapped_component(const T& t, const auto& g, const values::index auto& local_index)
203  requires requires(std::size_t i){ {g(i)} -> std::convertible_to<scalar_type>; }
204 #else
205  template<typename Getter, typename L, std::enable_if_t<values::index<L> and
206  std::is_convertible_v<typename std::invoke_result<const Getter&, std::size_t>::type, scalar_type>, int> = 0>
207  static constexpr auto
208  get_wrapped_component(const T& t, const Getter& g, const L& local_index)
209 #endif
210  {
211  return t.mBase->get_wrapped_component(g, local_index);
212  }
213 
214 
215 #ifdef __cpp_concepts
216  static constexpr void
217  set_wrapped_component(const T& t, const auto& s, const auto& g, const scalar_type& x, const values::index auto& local_index)
218  requires requires(std::size_t i){ s(x, i); s(g(i), i); }
219 #else
220  template<typename Setter, typename Getter, typename L, std::enable_if_t<values::index<L> and
221  std::is_invocable<const Setter&, const scalar_type&, std::size_t>::value and
222  std::is_invocable<const Setter&, typename std::invoke_result<const Getter&, std::size_t>::type, std::size_t>::value, int> = 0>
223  static constexpr void
224  set_wrapped_component(const T& t, const Setter& s, const Getter& g, const scalar_type& x, const L& local_index)
225 #endif
226  {
227  t.mBase->set_wrapped_component(s, g, x, local_index);
228  }
229 
230  };
231 
232 } // namespace OpenKalman::interface
233 
234 
235 namespace std
236 {
237 #ifdef __cpp_concepts
238  template<typename Scalar1, std::common_with<Scalar1> Scalar2>
239 #else
240  template<typename Scalar1, typename Scalar2>
241 #endif
242  struct common_type<OpenKalman::coordinates::Any<Scalar1>, OpenKalman::coordinates::Any<Scalar2>>
243  {
245  };
246 
247 
248 #ifdef __cpp_concepts
249  template<typename Scalar, OpenKalman::coordinates::descriptor U>
250 #else
251  template<typename Scalar, typename U>
252 #endif
253  struct common_type<OpenKalman::coordinates::Any<Scalar>, U>
254  {
256  };
257 
258 
259 #ifdef __cpp_concepts
260  template<OpenKalman::coordinates::descriptor T, typename Scalar>
261 #else
262  template<typename T, typename Scalar>
263 #endif
264  struct common_type<T, OpenKalman::coordinates::Any<Scalar>>
265  {
267  };
268 }
269 
270 #endif //OPENKALMAN_ANYATOMICVECTORTYPES_HPP
Definition: basics.hpp:41
constexpr auto get_wrapped_component(const T &t, const Getter &g, const L &local_index)
Gets an element from a matrix or tensor object and wraps the result.
Definition: get_wrapped_component.hpp:53
constexpr void set_wrapped_component(const T &t, const Setter &s, const Getter &g, const X &x, const L &local_index)
Set a component and then perform any required wrapping.
Definition: set_wrapped_component.hpp:55
Definition: tuple_reverse.hpp:103
Definition for to_stat_space.
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
Definition for coordinates::pattern.
Definition for from_stat_space.
decltype(auto) constexpr to_stat_space(const T &t, R &&data_view)
Maps an element from coordinates in modular space to coordinates in Euclidean space.
Definition: to_stat_space.hpp:54
constexpr auto get_dimension(const Arg &arg)
Get the vector dimension of coordinates::pattern Arg.
Definition: get_dimension.hpp:55
The root namespace for OpenKalman.
Definition: basics.hpp:34
Definition: compares_with.hpp:28
constexpr Any(Arg &&arg)
Construct from a coordinates::descriptor.
Definition: Any.hpp:112
constexpr auto get_is_euclidean(const Arg &arg)
Determine, whether coordinates::pattern Arg is euclidean.
Definition: get_is_euclidean.hpp:70
Definition for get_wrapped_component.
constexpr auto get_stat_dimension(const Arg &arg)
Get the vector dimension of coordinates::pattern Arg when transformed into statistical space...
Definition: get_stat_dimension.hpp:53
Traits for coordinates::pattern objects.
Definition: coordinate_descriptor_traits.hpp:41
constexpr bool index
T is an index value.
Definition: index.hpp:56
Definition for values::number.
constexpr auto from_stat_space(const T &t, const Getter &g, const L &local_index)
The inverse of to_stat_space.
Definition: from_stat_space.hpp:50
Definition: Any.hpp:41
Definition for set_wrapped_component.