OpenKalman
EigenAdapterBase.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) 2019-2021 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_EIGENADAPTERBASE_HPP
18 #define OPENKALMAN_EIGENADAPTERBASE_HPP
19 
20 namespace OpenKalman::Eigen3
21 {
22  template<typename Derived, typename Base>
23  struct EigenAdapterBase : Base, EigenCustomBase,
24  Eigen::internal::no_assignment_operator // Override all Eigen assignment operators
25  {
26  using Scalar = typename Eigen::internal::traits<Derived>::Scalar;
27  using RealScalar = typename Eigen::NumTraits<Scalar>::Real;
28  using Nested = typename Eigen::internal::ref_selector<Derived>::type;
29  using StorageKind = typename Eigen::internal::traits<Derived>::StorageKind;
30  using StorageIndex = typename Eigen::internal::traits<Derived>::StorageIndex;
31  enum CompileTimeTraits
32  {
33  RowsAtCompileTime = Eigen::internal::traits<Derived>::RowsAtCompileTime,
34  ColsAtCompileTime = Eigen::internal::traits<Derived>::ColsAtCompileTime,
35  Flags = Eigen::internal::traits<Derived>::Flags,
36  };
37 
38  EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(bool {has_dynamic_dimensions<Derived>})
39 
40 
41  EigenAdapterBase() = default;
42 
43  EigenAdapterBase(const EigenAdapterBase&) = default;
44 
45  EigenAdapterBase(EigenAdapterBase&&) = default;
46 
47  ~EigenAdapterBase() = default;
48 
49  constexpr EigenAdapterBase& operator=(const EigenAdapterBase& other) { return *this; }
50 
51  constexpr EigenAdapterBase& operator=(EigenAdapterBase&& other) { return *this; }
52 
53  using typename Base::Index;
54 
55 
61  constexpr Index
62  rows() const
63  {
64  return get_index_dimension_of<0>(static_cast<const Derived&>(*this));
65  }
66 
67 
73  constexpr Index
74  cols() const
75  {
76  return get_index_dimension_of<1>(static_cast<const Derived&>(*this));
77  }
78 
79 
80  constexpr decltype(auto)
81  data()
82 #ifdef __cpp_lib_concepts
83  requires interface::raw_data_defined_for<Derived&>
84 #endif
85  {
86  return OpenKalman::internal::raw_data(static_cast<Derived&>(*this));
87  }
88 
89 
90  constexpr decltype(auto)
91  data() const
92 #ifdef __cpp_lib_concepts
93  requires interface::raw_data_defined_for<const Derived&>
94 #endif
95  {
96  return OpenKalman::internal::raw_data(static_cast<const Derived&>(*this));
97  }
98 
99  private:
100 
101 #ifndef __cpp_concepts
102  template<typename T, typename = void>
103  struct has_outerStride : std::false_type {};
104 
105  template<typename T>
106  struct has_outerStride<T, std::void_t<decltype(std::declval<T>().outerStride())>> : std::true_type {};
107 
108  template<typename T, typename = void>
109  struct has_innerStride : std::false_type {};
110 
111  template<typename T>
112  struct has_innerStride<T, std::void_t<decltype(std::declval<T>().innerStride())>> : std::true_type {};
113 #endif
114 
115  public:
116 
117  constexpr Index
118  outerStride() const
119  {
120  if constexpr (layout_of_v<Derived> == Layout::stride)
121  return std::get<Base::IsRowMajor ? 0 : 1>(strides(static_cast<const Derived&>(*this)));
122  else if constexpr (Base::IsRowMajor)
123  return cols();
124  else
125  return rows();
126  }
127 
128 
129  constexpr Index
130  innerStride() const
131  {
132  if constexpr (layout_of_v<Derived> == Layout::stride)
133  return std::get<Base::IsRowMajor ? 1 : 0>(strides(static_cast<const Derived&>(*this)));
134  else
135  return 1;
136  }
137 
138 
143  [[deprecated("Use make_zero() instead.")]]
144  static constexpr auto Zero()
145  {
146  static_assert(not has_dynamic_dimensions<Derived>);
147  return make_zero<Derived>();
148  }
149 
150 
155  [[deprecated("Use make_zero() instead.")]]
156  static constexpr auto Zero(const Index r, const Index c)
157  {
158  return make_zero<Derived>(Dimensions{static_cast<std::size_t>(r)}, Dimensions{static_cast<std::size_t>(c)});
159  }
160 
161 
166  [[deprecated("Use make_identity_matrix_like() instead.")]]
167  static constexpr auto Identity()
168  {
169  if constexpr(square_shaped<Derived>)
170  return make_identity_matrix_like<Derived>();
171  else
172  return Base::Identity();
173  }
174 
175 
180  [[deprecated("Use make_identity_matrix_like() instead.")]]
181  static constexpr decltype(auto) Identity(const Index r, const Index c)
182  {
183  if constexpr (not dynamic_dimension<Derived, 0>) if (r != index_dimension_of_v<Derived, 0>)
184  throw std::invalid_argument {"In T::Identity(r, c), r (==" + std::to_string(r) +
185  ") does not equal the fixed rows of T (==" + std::to_string(index_dimension_of_v<Derived, 0>) + ")"};
186 
187  if constexpr (not dynamic_dimension<Derived, 1>) if (c != index_dimension_of_v<Derived, 0>)
188  throw std::invalid_argument {"In T::Identity(r, c), c (==" + std::to_string(c) +
189  ") does not equal the fixed columns of T (==" + std::to_string(index_dimension_of_v<Derived, 1>) + ")"};
190 
191  return make_identity_matrix_like<Derived>(static_cast<std::size_t>(r), static_cast<std::size_t>(c));
192  }
193 
194 
195  private:
196 
197  template<typename Arg>
198  constexpr auto& get_ultimate_nested_matrix_impl(Arg& arg)
199  {
200  auto& b = nested_object(arg);
201  using B = decltype(b);
202  static_assert(not std::is_const_v<std::remove_reference_t<B>>);
203  if constexpr(OpenKalman::internal::hermitian_expr<B> or OpenKalman::internal::triangular_expr<B> or
204  OpenKalman::internal::diagonal_expr<B> or euclidean_expr<B>)
205  {
206  return get_ultimate_nested_matrix(b);
207  }
208  else
209  {
210  return b;
211  }
212  }
213 
214 
215  template<typename Arg>
216  constexpr auto& get_ultimate_nested_matrix(Arg& arg)
217  {
218  if constexpr(OpenKalman::internal::hermitian_expr<Arg>)
219  {
220  if constexpr (hermitian_adapter_type_of_v<Arg> == TriangleType::diagonal) return arg;
221  else return get_ultimate_nested_matrix_impl(arg);
222  }
223  else if constexpr(OpenKalman::internal::triangular_expr<Arg>)
224  {
225  if constexpr(triangular_matrix<Arg, TriangleType::diagonal>) return arg;
226  else return get_ultimate_nested_matrix_impl(arg);
227  }
228  else
229  {
230  return get_ultimate_nested_matrix_impl(arg);
231  }
232  }
233 
234 
235  public:
236 
237 #ifdef __cpp_concepts
238  template<std::convertible_to<Scalar> S>
239 #else
240  template<typename S, std::enable_if_t<std::is_convertible_v<S, Scalar>, int> = 0>
241 #endif
242  auto operator<<(const S& s)
243  {
244  if constexpr(covariance<Derived>)
245  {
246  auto& xpr = static_cast<Derived&>(*this);
247  return Eigen::CovarianceCommaInitializer {xpr, static_cast<const Scalar&>(s)};
248  }
249  else
250  {
251  auto& xpr = get_ultimate_nested_matrix(static_cast<Derived&>(*this));
252  using Xpr = std::decay_t<decltype(xpr)>;
253  if constexpr(mean<Derived>)
254  {
255  return Eigen::MeanCommaInitializer<Derived, Xpr> {xpr, static_cast<const Scalar&>(s)};
256  }
257  else if constexpr((OpenKalman::internal::hermitian_expr<Xpr> or OpenKalman::internal::triangular_expr<Xpr>)
258  and diagonal_matrix<Xpr>)
259  {
260  return Eigen::DiagonalCommaInitializer {xpr, static_cast<const Scalar&>(s)};
261  }
262  else
263  {
264  return Eigen::CommaInitializer {xpr, static_cast<const Scalar&>(s)};
265  }
266  }
267  }
268 
269 
270 #ifdef __cpp_concepts
271  template<indexible Other>
272 #else
273  template<typename Other, std::enable_if_t<indexible<Other>, int> = 0>
274 #endif
275  auto operator<<(const Other& other)
276  {
277  if constexpr(covariance<Derived>)
278  {
279  auto& xpr = static_cast<Derived&>(*this);
280  return Eigen::CovarianceCommaInitializer {xpr, other};
281  }
282  else
283  {
284  auto& xpr = get_ultimate_nested_matrix(static_cast<Derived&>(*this));
285  using Xpr = std::decay_t<decltype(xpr)>;
286  if constexpr (mean<Derived>)
287  {
288  return Eigen::MeanCommaInitializer<Derived, Xpr> {xpr, other};
289  }
290  else if constexpr ((OpenKalman::internal::hermitian_expr<Xpr> or OpenKalman::internal::triangular_expr<Xpr>)
291  and diagonal_matrix<Xpr>)
292  {
293  return Eigen::DiagonalCommaInitializer {xpr, other};
294  }
295  else
296  {
297  return Eigen::CommaInitializer {xpr, other};
298  }
299  }
300  }
301 
302  };
303 
304 } // namespace OpenKalman::Eigen3
305 
306 
307 #endif //OPENKALMAN_EIGENADAPTERBASE_HPP
Definition: tuple_reverse.hpp:103
Alternative version of Eigen::CommaInitializer for Mean.
Definition: eigen-comma-initializers.hpp:26
static constexpr auto Identity()
Definition: EigenAdapterBase.hpp:167
Definition: eigen-forward-declarations.hpp:22
A generalization of the above: a custom stride is specified for each index.
static constexpr auto Zero(const Index r, const Index c)
Definition: EigenAdapterBase.hpp:156
Version of Eigen::CommaInitializer for diagonal versions of HermitianAdapter and TriangularAdapter.
Definition: eigen-comma-initializers.hpp:57
Alternative version of Eigen::CommaInitializer for Covariance and SquareRootCovariance.
Definition: eigen-comma-initializers.hpp:124
A diagonal matrix (both a lower-left and an upper-right triangular matrix).
static constexpr auto Zero()
Definition: EigenAdapterBase.hpp:144
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:34