OpenKalman
CovarianceBase3Impl.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) 2020-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_COVARIANCEBASE3IMPL_HPP
18 #define OPENKALMAN_COVARIANCEBASE3IMPL_HPP
19 
20 #include <utility>
21 
22 namespace OpenKalman::internal
23 {
24  // ======================================CASE 3======================================
34  template<typename Derived, typename NestedMatrix>
35  struct CovarianceBase3Impl : AdapterBase<Derived, NestedMatrix>
36  {
37  private:
38 
40 
41  using Scalar = scalar_type_of_t<NestedMatrix>;
42 
43  protected:
44 
45  using CholeskyNestedMatrix = std::conditional_t<
46  diagonal_matrix<NestedMatrix>,
47  typename MatrixTraits<std::decay_t<NestedMatrix>>::template DiagonalMatrixFrom<>,
48  std::conditional_t<triangular_matrix<NestedMatrix>,
49  typename MatrixTraits<std::decay_t<NestedMatrix>>::template SelfAdjointMatrixFrom<>,
50  typename MatrixTraits<std::decay_t<NestedMatrix>>::template TriangularAdapterFrom<>>>;
51 
52 
53  // The cholesky nested matrix one would expect given whether the covariance is a square root.
54  mutable CholeskyNestedMatrix cholesky_nested;
55 
56 
57  // The synchronization state. 0 == synchronized, 1 = forward, -1 = reverse.
58  mutable int synch_direction;
59 
60 
65  auto& cholesky_nested_matrix() & { return cholesky_nested; }
66 
68  const auto& cholesky_nested_matrix() const & { return cholesky_nested; }
69 
71  auto&& cholesky_nested_matrix() && { return std::move(cholesky_nested); }
72 
74  const auto&& cholesky_nested_matrix() const && { return std::move(cholesky_nested); }
75 
76 
81  int synchronization_direction() const { return synch_direction; }
82 
83 
88  void synchronize_forward() const &
89  {
90  cholesky_nested = to_covariance_nestable<CholeskyNestedMatrix>(Base::nested_object());
91  synch_direction = 0;
92  }
93 
94 
96  void synchronize_forward() const &&
97  {
98  cholesky_nested = to_covariance_nestable<CholeskyNestedMatrix>(std::move(*this).nested_object());
99  synch_direction = -1;
100  }
101 
102 
107  void mark_nested_matrix_changed() const { synch_direction = 1; }
108 
109 
114  void mark_cholesky_nested_matrix_changed() const { synch_direction = -1; }
115 
116 
121  void mark_synchronized() const { synch_direction = 0; }
122 
123 
125 #ifdef __cpp_concepts
126  CovarianceBase3Impl() requires std::default_initializable<NestedMatrix>
127 #else
128  template<typename T = NestedMatrix, std::enable_if_t<std::is_default_constructible_v<T>, int> = 0>
130 #endif
131  : Base {}, synch_direction {} {}
132 
133 
135  CovarianceBase3Impl(const CovarianceBase3Impl& other) = default;
136 
137 
139  CovarianceBase3Impl(CovarianceBase3Impl&& other) noexcept = default;
140 
141 
147 #ifdef __cpp_concepts
148  template<typename Arg> requires (triangular_matrix<Arg> == triangular_matrix<NestedMatrix>) and
149  (not diagonal_matrix<Arg>)
150 #else
151  template<typename Arg, std::enable_if_t<(triangular_matrix<Arg> == triangular_matrix<NestedMatrix>) and
152  (not diagonal_matrix<Arg>), int> = 0>
153 #endif
154  CovarianceBase3Impl(Arg&& arg, int sd)
155  : Base {std::forward<Arg>(arg)}, cholesky_nested {}, synch_direction {sd} {}
156 
157 
163 #ifdef __cpp_concepts
164  template<typename Arg> requires (triangular_matrix<Arg> != triangular_matrix<NestedMatrix>) or diagonal_matrix<Arg>
165 #else
166  template<typename Arg, std::enable_if_t<(triangular_matrix<Arg> != triangular_matrix<NestedMatrix>) or
167  diagonal_matrix<Arg>, int> = 0>
168 #endif
169  CovarianceBase3Impl(Arg&& arg, int sd)
170  : Base {}, cholesky_nested {std::forward<Arg>(arg)}, synch_direction {sd} {}
171 
172 
179  template<typename N, typename CN>
180  CovarianceBase3Impl(N&& n, CN&& cn, int sd)
181  : Base {std::forward<N>(n)}, cholesky_nested {std::forward<CN>(cn)}, synch_direction {sd} {}
182 
183 
184  public:
185 
187  auto& operator=(const CovarianceBase3Impl& other)
188  {
189  if constexpr (not zero<NestedMatrix> and not identity_matrix<NestedMatrix>) if (this != &other)
190  {
191  if (synch_direction >= 0) Base::nested_object() = other.nested_object();
192  if (synch_direction <= 0) cholesky_nested = other.cholesky_nested_matrix();
193  synch_direction = other.synch_direction;
194  }
195  return *this;
196  }
197 
198 
200  auto& operator=(CovarianceBase3Impl&& other) noexcept
201  {
202  if constexpr (not zero<NestedMatrix> and not identity_matrix<NestedMatrix>) if (this != &other)
203  {
204  if (synch_direction >= 0) Base::nested_object() = std::move(other.nested_object());
205  if (synch_direction <= 0) cholesky_nested = std::move(other.cholesky_nested_matrix());
206  synch_direction = other.synch_direction;
207  }
208  return *this;
209  }
210 
211 
216 #ifdef __cpp_concepts
217  template<covariance Arg> requires (not std::derived_from<std::decay_t<Arg>, CovarianceBase3Impl>)
218 #else
219  template<typename Arg, std::enable_if_t<covariance<Arg> and
220  (not std::is_base_of_v<CovarianceBase3Impl, std::decay_t<Arg>>), int> = 0>
221 #endif
222  auto& operator=(Arg&& arg)
223  {
224  if constexpr(not (zero<nested_object_of_t<Arg>> and zero<NestedMatrix>) and
225  not (identity_matrix<nested_object_of_t<Arg>> and identity_matrix<NestedMatrix>))
226  {
227  if constexpr (case1or2<Arg>)
228  {
229  // Arg is Case 1 or 2
230  if constexpr (triangular_matrix<nested_object_of_t<Arg>> == triangular_matrix<NestedMatrix> and
231  not diagonal_matrix<Arg>)
232  {
233  Base::nested_object() = to_covariance_nestable<NestedMatrix>(std::forward<Arg>(arg));
234  mark_nested_matrix_changed();
235  }
236  else
237  {
238  cholesky_nested = to_covariance_nestable<CholeskyNestedMatrix>(std::forward<Arg>(arg));
239  mark_cholesky_nested_matrix_changed();
240  }
241  }
242  else
243  {
244  // Arg is Case 3 or 4
245  if (synch_direction >= 0)
246  {
247  Base::nested_object() = to_covariance_nestable<NestedMatrix>(std::forward<Arg>(arg));
248  }
249  if (synch_direction <= 0)
250  {
251  cholesky_nested = to_covariance_nestable<CholeskyNestedMatrix>(std::forward<Arg>(arg));
252  }
253  synch_direction = arg.synchronization_direction();
254  }
255  }
256  return *this;
257  }
258 
259 
263 #ifdef __cpp_concepts
264  template<covariance_nestable Arg>
265 #else
266  template<typename Arg, std::enable_if_t<covariance_nestable<Arg>, int> = 0>
267 #endif
268  auto& operator=(Arg&& arg)
269  {
270  if constexpr(not (zero<Arg> and zero<NestedMatrix>) and
271  not (identity_matrix<Arg> and identity_matrix<NestedMatrix>))
272  {
273  if constexpr(triangular_matrix<Arg> == triangular_matrix<NestedMatrix> and not diagonal_matrix<Arg>)
274  {
275  Base::nested_object() = to_covariance_nestable<NestedMatrix>(std::forward<Arg>(arg));
276  mark_nested_matrix_changed();
277  }
278  else
279  {
280  cholesky_nested = to_covariance_nestable<CholeskyNestedMatrix>(std::forward<Arg>(arg));
281  mark_cholesky_nested_matrix_changed();
282  }
283  }
284  return *this;
285  }
286 
287 
294  auto operator() (std::size_t i, std::size_t j)
295  {
296  if constexpr(writable_by_component<CholeskyNestedMatrix, 2>)
297  return ElementAccessor(cholesky_nested, i, j,
298  [this] { if (synch_direction > 0) synchronize_forward(); },
299  [this] { mark_cholesky_nested_matrix_changed(); });
300  else
301  return ElementAccessor(cholesky_nested_matrix(), i, j,
302  [this] { if (synch_direction > 0) synchronize_forward(); });
303  }
304 
306  auto operator() (std::size_t i, std::size_t j) const
307  {
308  return ElementAccessor(cholesky_nested, i, j, [this] { if (synch_direction > 0) synchronize_forward(); });
309  }
310 
311 
317  auto operator[] (std::size_t i)
318  {
319  if constexpr(writable_by_component<CholeskyNestedMatrix, 1>)
320  return ElementAccessor(cholesky_nested, i,
321  [this] { if (synch_direction > 0) synchronize_forward(); },
322  [this] { mark_cholesky_nested_matrix_changed(); });
323  else
324  return ElementAccessor(cholesky_nested, i,
325  [this] { if (synch_direction > 0) synchronize_forward(); });
326  }
327 
328 
330  auto operator[] (std::size_t i) const
331  {
332  return ElementAccessor(cholesky_nested, i, [this] { if (synch_direction > 0) synchronize_forward(); });
333  }
334 
335 
339  void set_component(const Scalar s, const std::size_t i, const std::size_t j)
340  {
341  if (synch_direction > 0) synchronize_forward();
342  OpenKalman::set_component(cholesky_nested, s, i, j);
343  mark_cholesky_nested_matrix_changed();
344  }
345 
346 
350  void set_component(const Scalar s, const std::size_t i)
351  {
352  if (synch_direction > 0) synchronize_forward();
353  OpenKalman::set_component(cholesky_nested, s, i);
354  mark_cholesky_nested_matrix_changed();
355  }
356 
357  };
358 
359 
360 }
361 
362 #endif //OPENKALMAN_COVARIANCEBASE3IMPL_HPP
Definition: ElementAccessor.hpp:34
typename nested_object_of< T >::type nested_object_of_t
Helper type for nested_object_of.
Definition: nested_object_of.hpp:66
auto && cholesky_nested_matrix() &&
Definition: CovarianceBase3Impl.hpp:71
constexpr NestedMatrix & nested_object() &
Get the nested object.
Definition: AdapterBase.hpp:97
Arg && set_component(Arg &&arg, const scalar_type_of_t< Arg > &s, const Indices &indices)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: set_component.hpp:51
typename scalar_type_of< T >::type scalar_type_of_t
helper template for scalar_type_of.
Definition: scalar_type_of.hpp:54
auto operator()(std::size_t i, std::size_t j)
Get or set element (i, j) of the covariance matrix.
Definition: CovarianceBase3Impl.hpp:294
auto operator[](std::size_t i)
Get or set element i of the covariance matrix.
Definition: CovarianceBase3Impl.hpp:317
Definition: AdapterBase.hpp:36
Definition: CovarianceBase3Impl.hpp:35
auto & operator=(CovarianceBase3Impl &&other) noexcept
Move assignment operator.
Definition: CovarianceBase3Impl.hpp:200
constexpr bool triangular_matrix
Specifies that a type is a triangular matrix (upper, lower, or diagonal).
Definition: triangular_matrix.hpp:37
constexpr bool zero
Specifies that a type is known at compile time to be a constant matrix of value zero.
Definition: zero.hpp:43
constexpr bool identity_matrix
Specifies that a type is an identity matrix.
Definition: identity_matrix.hpp:45
void set_component(const Scalar s, const std::size_t i, const std::size_t j)
Set an element of the cholesky nested matrix.
Definition: CovarianceBase3Impl.hpp:339
CovarianceBase3Impl()
Default constructor.
Definition: CovarianceBase3Impl.hpp:129
const auto && cholesky_nested_matrix() const &&
Definition: CovarianceBase3Impl.hpp:74
void set_component(const Scalar s, const std::size_t i)
Set an element of the cholesky nested matrix.
Definition: CovarianceBase3Impl.hpp:350
auto & operator=(Arg &&arg)
Assign from a covariance_nestable.
Definition: CovarianceBase3Impl.hpp:268
const auto & cholesky_nested_matrix() const &
Definition: CovarianceBase3Impl.hpp:68
auto & operator=(const CovarianceBase3Impl &other)
Copy assignment operator.
Definition: CovarianceBase3Impl.hpp:187
Definition: basics.hpp:48