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_DESCRIPTOR_ANY_HPP
18 #define OPENKALMAN_DESCRIPTOR_ANY_HPP
19 
20 #include <memory>
22 #include "coordinates/interfaces/coordinate_descriptor_traits.hpp"
29 
31 {
37 #ifdef __cpp_concepts
38  template<values::number S = double> requires std::same_as<S, std::decay_t<S>>
39 #else
40  template<typename S = double>
41 #endif
42  struct Any;
43 
44 
45  namespace detail
46  {
50  template<typename T>
51  struct is_Any : std::false_type {};
52 
53  template<typename S>
54  struct is_Any<Any<S>> : std::true_type {};
55  }
56 
57 
58 #ifdef __cpp_concepts
59  template<values::number S> requires std::same_as<S, std::decay_t<S>>
60 #else
61  template<typename S>
62 #endif
63  struct Any
64  {
65  private:
66 
67  using Getter = std::function<S(std::size_t)>;
68 
69  struct Base
70  {
71  virtual ~Base() = default;
72  [[nodiscard]] virtual std::size_t dimension() const = 0;
73  [[nodiscard]] virtual std::size_t stat_dimension() const = 0;
74  [[nodiscard]] virtual bool is_euclidean() const = 0;
75  [[nodiscard]] virtual std::size_t hash_code() const = 0;
76  [[nodiscard]] virtual Getter to_stat_space(Getter g) const = 0;
77  [[nodiscard]] virtual Getter from_stat_space(Getter g) const = 0;
78  [[nodiscard]] virtual Getter wrap(Getter g) const = 0;
79  };
80 
81 
82  template <typename T>
83  struct Derived : Base
84  {
85  template<typename Arg>
86  explicit Derived(Arg&& arg) : my_t(std::forward<Arg>(arg)) {}
87 
88  [[nodiscard]] std::size_t dimension() const final { return internal::get_descriptor_dimension(my_t); }
89 
90  [[nodiscard]] std::size_t stat_dimension() const final { return internal::get_descriptor_stat_dimension(my_t); }
91 
92  [[nodiscard]] bool is_euclidean() const final { return internal::get_descriptor_is_euclidean(my_t); }
93 
94  [[nodiscard]] std::size_t hash_code() const final { return internal::get_descriptor_hash_code(my_t); }
95 
96  [[nodiscard]] Getter to_stat_space(Getter g) const final
97  {
98  if constexpr (euclidean_pattern<T>)
99  {
100  return std::move(g);
101  }
102  else
103  {
104  return [stat_data = coordinates::to_stat_space(my_t, collections::views::generate(std::move(g), get_dimension(my_t)))]
105  (std::size_t i) -> S { return collections::get_element(stat_data, i); };
106  }
107  }
108 
109  [[nodiscard]] Getter from_stat_space(Getter g) const final
110  {
111  if constexpr (euclidean_pattern<T>)
112  {
113  return std::move(g);
114  }
115  else
116  {
117  return [data = coordinates::from_stat_space(my_t, collections::views::generate(std::move(g), get_stat_dimension(my_t)))]
118  (std::size_t i) -> S { return collections::get_element(data, i); };
119  }
120  }
121 
122  [[nodiscard]] Getter wrap(Getter g) const final
123  {
124  if constexpr (euclidean_pattern<T>)
125  {
126  return std::move(g);
127  }
128  else
129  {
130  return [data = coordinates::wrap(my_t, collections::views::generate(std::move(g), get_dimension(my_t)))]
131  (std::size_t i) -> S { return collections::get_element(data, i); };
132  }
133  }
134 
135  private:
136 
137  T my_t;
138  };
139 
140  public:
141 
145 #ifdef __cpp_concepts
146  template <descriptor Arg> requires (not detail::is_Any<std::decay_t<Arg>>::value)
147 #else
148  template<typename Arg, std::enable_if_t<descriptor<Arg> and (not detail::is_Any<std::decay_t<Arg>>::value), int> = 0>
149 #endif
150  constexpr
151  Any(Arg&& arg) : mBase {std::make_shared<Derived<std::decay_t<Arg>>>(std::forward<Arg>(arg))} {}
152 
153 
154 #ifndef __cpp_concepts
155  // Addresses an issue with a version of clang in c++17
156  constexpr Any() : mBase {std::make_shared<Derived<std::integral_constant<std::size_t, 0>>>(std::integral_constant<std::size_t, 0>{})} {}
157 #endif
158 
159  private:
160 
161  const std::shared_ptr<Base> mBase;
162 
163 #ifdef __cpp_concepts
164  template<typename T>
165 #else
166  template<typename T, typename>
167 #endif
169 
170  };
171 
172 }
173 
174 
175 namespace OpenKalman::interface
176 {
181  template<typename S>
182  struct coordinate_descriptor_traits<coordinates::Any<S>>
183  {
184  private:
185 
186  using T = coordinates::Any<S>;
187 
188  public:
189 
190  static constexpr bool is_specialized = true;
191 
192 
193  static constexpr auto dimension = [](const T& t) -> std::size_t { return t.mBase->dimension(); };
194 
195 
196  static constexpr auto stat_dimension = [](const T& t) -> std::size_t { return t.mBase->stat_dimension(); };
197 
198 
199  static constexpr auto is_euclidean = [](const T& t) -> bool { return t.mBase->is_euclidean(); };
200 
201 
202  static constexpr auto hash_code = [](const T& t) -> std::size_t { return t.mBase->hash_code(); };
203 
204 
205  static constexpr auto
206  to_stat_space = [](const T& t, auto&& data_view)
207  {
208  auto d = std::make_tuple(std::forward<decltype(data_view)>(data_view));
210  t.mBase->to_stat_space([d](std::size_t i){ return collections::get_element(std::get<0>(d), i); }),
211  t.mBase->stat_dimension());
212  };
213 
214 
215  static constexpr auto
216  from_stat_space = [](const T& t, auto&& data_view)
217  {
218  auto d = std::make_tuple(std::forward<decltype(data_view)>(data_view));
220  t.mBase->from_stat_space([d](std::size_t i){ return collections::get_element(std::get<0>(d), i); }),
221  t.mBase->dimension());
222  };
223 
224 
225  static constexpr auto
226  wrap = [](const T& t, auto&& data_view)
227  {
228  auto d = std::make_tuple(std::forward<decltype(data_view)>(data_view));
230  t.mBase->wrap([d](std::size_t i){ return collections::get_element(std::get<0>(d), i); }),
231  t.mBase->dimension());
232  };
233 
234  };
235 
236 }
237 
238 
239 namespace std
240 {
241  template<typename Scalar1, typename Scalar2>
242  struct common_type<OpenKalman::coordinates::Any<Scalar1>, OpenKalman::coordinates::Any<Scalar2>>
243  : std::conditional_t<
244  OpenKalman::stdex::common_with<Scalar1, Scalar2>,
245  OpenKalman::stdex::type_identity<OpenKalman::coordinates::Any<
246  typename std::conditional_t<
247  OpenKalman::stdex::common_with<Scalar1, Scalar2>,
248  common_type<Scalar1, Scalar2>,
249  OpenKalman::stdex::type_identity<double>>::type>>,
250  std::monostate> {};
251 
252 
253  template<typename S, typename T>
254  struct common_type<OpenKalman::coordinates::Any<S>, T>
255  : std::conditional_t<
256  OpenKalman::coordinates::descriptor<T>,
257  OpenKalman::stdex::type_identity<OpenKalman::coordinates::Any<S>>,
258  std::monostate> {};
259 }
260 
261 #endif
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:69
Definition: basics.hpp:41
decltype(auto) constexpr to_stat_space(const T &t, R &&data_view)
Maps a range reflecting vector-space data to a corresponding range in a vector space for directional ...
Definition: to_stat_space.hpp:44
decltype(auto) constexpr wrap(const T &t, R &&data_view)
wraps a range reflecting vector-space data to its primary range.
Definition: wrap.hpp:59
constexpr Any(Arg &&arg)
Construct from a coordinates::descriptor.
Definition: Any.hpp:151
Definition for coordinates::to_stat_space.
Definition for coordinates::wrap.
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
Definition for collections::from_stat_space.
constexpr auto get_dimension(const Arg &arg)
Get the vector dimension of coordinates::pattern Arg.
Definition: get_dimension.hpp:54
The root namespace for OpenKalman.
Definition: basics.hpp:34
The namespace for features relating to coordinates::pattern object.
Definition: compares_with.hpp:25
Definition for get_descriptor_hash_code.
Inclusion file for collections.
Traits for coordinates::pattern objects.
Definition: coordinate_descriptor_traits.hpp:36
constexpr detail::generate_adaptor generate
a collection_view generator associated with generate_view.
Definition: generate.hpp:335
decltype(auto) constexpr get_element(Arg &&arg, I i)
A generalization of std::get and the range subscript operator.
Definition: get_element.hpp:122
decltype(auto) constexpr from_stat_space(const T &t, R &&stat_data_view)
Maps a range in a vector space for directional-statistics back to a range reflecting vector-space dat...
Definition: from_stat_space.hpp:44
Tests whether the argument is an instance of of type Any.
Definition: Any.hpp:51
Definition: Any.hpp:42