OpenKalman
CovarianceImpl.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) 2018-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_COVARIANCEIMPL_HPP
18 #define OPENKALMAN_COVARIANCEIMPL_HPP
19 
20 
21 namespace OpenKalman::internal
22 {
23 
24  // ---------------- //
25  // CovarianceImpl //
26  // ---------------- //
27 
34 #ifdef __cpp_concepts
35  template<typename Derived, typename NestedMatrix>
36 #else
37  template<typename Derived, typename NestedMatrix>
38 #endif
39  struct CovarianceImpl : CovarianceBase<Derived, NestedMatrix>
40  {
41 
42 #ifndef __cpp_concepts
43  static_assert(covariance<Derived>);
44  static_assert(covariance_nestable<NestedMatrix>);
45 #endif
46 
48 
49  private:
50 
52 
53  protected:
54  using typename Base::CholeskyNestedMatrix;
55  using Base::nested_object;
56  using Base::cholesky_nested_matrix;
57  using Base::synchronization_direction;
58  using Base::synchronize_forward;
59  using Base::synchronize_reverse;
60  using Base::mark_nested_matrix_changed;
61  using Base::mark_cholesky_nested_matrix_changed;
62  using Base::mark_synchronized;
63 
64 
65  public:
66 
67  using Base::Base;
68 
69  using Base::operator=;
70 
71 
78 #ifdef __cpp_concepts
79  template<std::invocable<NestedMatrix&> F1, std::invocable<CholeskyNestedMatrix&> F2>
80 #else
81  template<typename F1, typename F2, std::enable_if_t<
82  std::is_invocable_v<F1, NestedMatrix&> and std::is_invocable_v<F2, CholeskyNestedMatrix&>, int> = 0>
83 #endif
84  auto covariance_op(const F1& f1, const F2& f2) const &
85  {
86  using Derived2 = decltype(to_dense_object<Derived>(f1(nested_object())));
87  using R = equivalent_self_contained_t<Derived2>;
88  if (synchronization_direction() >= 0)
89  {
90  R r {f1(nested_object())};
91  if constexpr (not case1or2<Derived, decltype(f1(nested_object()))>)
92  {
93  if (r.synchronization_direction() > 0 and synchronization_direction() <= 0)
94  {
95  r.cholesky_nested_matrix() =
96  to_covariance_nestable<decltype(r.cholesky_nested_matrix())>(f2(cholesky_nested_matrix()));
97  r.mark_synchronized();
98  }
99  }
100  return r;
101  }
102  else
103  {
104  return R {f2(cholesky_nested_matrix())};
105  }
106  }
107 
108 
110 #ifdef __cpp_concepts
111  template<std::invocable<NestedMatrix&> F1, std::invocable<CholeskyNestedMatrix&> F2>
112 #else
113  template<typename F1, typename F2, std::enable_if_t<
114  std::is_invocable_v<F1, NestedMatrix&> and std::is_invocable_v<F2, CholeskyNestedMatrix&>, int> = 0>
115 #endif
116  auto covariance_op(const F1& f1, const F2& f2) const &&
117  {
118  using Derived2 = decltype(to_dense_object<Derived>(f1(std::move(*this).nested_object())));
119  using R = equivalent_self_contained_t<Derived2>;
120  if (synchronization_direction() >= 0)
121  {
122  R r {f1(std::move(*this).nested_object())};
123  if constexpr (not case1or2<Derived, decltype(f1(std::move(*this).nested_object()))>)
124  {
125  if (r.synchronization_direction() > 0 and synchronization_direction() <= 0)
126  {
127  r.cholesky_nested_matrix() =
128  to_covariance_nestable<decltype(r.cholesky_nested_matrix())>(f2(std::move(*this).cholesky_nested_matrix()));
129  r.mark_synchronized();
130  }
131  }
132  return r;
133  }
134  else
135  {
136  return R {f2(std::move(*this).cholesky_nested_matrix())};
137  }
138  }
139 
140 
142 #ifdef __cpp_concepts
143  template<std::invocable<NestedMatrix&> F> requires std::invocable<F, CholeskyNestedMatrix&>
144 #else
145  template<typename F, std::enable_if_t<
146  std::is_invocable_v<F, NestedMatrix&> and std::is_invocable_v<F, CholeskyNestedMatrix&>, int> = 0>
147 #endif
148  auto covariance_op(const F& f) const &
149  {
150  return covariance_op(f, f);
151  }
152 
153 
155 #ifdef __cpp_concepts
156  template<std::invocable<NestedMatrix&> F> requires std::invocable<F, CholeskyNestedMatrix&>
157 #else
158  template<typename F, std::enable_if_t<
159  std::is_invocable_v<F, NestedMatrix&> and std::is_invocable_v<F, CholeskyNestedMatrix&>, int> = 0>
160 #endif
161  auto covariance_op(const F& f) const &&
162  {
163  return std::move(*this).covariance_op(f, f);
164  }
165 
166  protected:
167 
168  template<bool direct_nested>
169  decltype(auto) get_nested_matrix_impl() &
170  {
171  if constexpr (direct_nested)
172  {
173  if (synchronization_direction() < 0) synchronize_reverse();
174  return nested_object();
175  }
176  else
177  {
178  if (synchronization_direction() > 0) synchronize_forward();
179  return cholesky_nested_matrix();
180  }
181  }
182 
183 
184  template<bool direct_nested>
185  decltype(auto) get_nested_matrix_impl() const &
186  {
187  if constexpr (direct_nested)
188  {
189  if (synchronization_direction() < 0) synchronize_reverse();
190  return nested_object();
191  }
192  else
193  {
194  if (synchronization_direction() > 0) synchronize_forward();
195  return cholesky_nested_matrix();
196  }
197  }
198 
199 
200  template<bool direct_nested>
201  decltype(auto) get_nested_matrix_impl() &&
202  {
203  if constexpr (direct_nested)
204  {
205  if (synchronization_direction() < 0) std::move(*this).synchronize_reverse();
206  return std::move(*this).nested_object();
207  }
208  else
209  {
210  if (synchronization_direction() > 0) std::move(*this).synchronize_forward();
211  return std::move(*this).cholesky_nested_matrix();
212  }
213  }
214 
215 
216  template<bool direct_nested>
217  decltype(auto) get_nested_matrix_impl() const &&
218  {
219  if constexpr (direct_nested)
220  {
221  if (synchronization_direction() < 0) std::move(*this).synchronize_reverse();
222  return std::move(*this).nested_object();
223  }
224  else
225  {
226  if (synchronization_direction() > 0) std::move(*this).synchronize_forward();
227  return std::move(*this).cholesky_nested_matrix();
228  }
229  }
230 
231  public:
232 
237  {
238  return this->get_nested_matrix_impl<hermitian_matrix<NestedMatrix>>();
239  }
240 
241 
243  decltype(auto) get_self_adjoint_nested_matrix() const &
244  {
245  return this->get_nested_matrix_impl<hermitian_matrix<NestedMatrix>>();
246  }
247 
248 
250  decltype(auto) get_self_adjoint_nested_matrix() &&
251  {
252  return std::move(*this).template get_nested_matrix_impl<hermitian_matrix<NestedMatrix>>();
253  }
254 
255 
257  decltype(auto) get_self_adjoint_nested_matrix() const &&
258  {
259  return std::move(*this).template get_nested_matrix_impl<hermitian_matrix<NestedMatrix>>();
260  }
261 
262 
266  decltype(auto) get_triangular_nested_matrix() &
267  {
268  return this->get_nested_matrix_impl<triangular_matrix<NestedMatrix>>();
269  }
270 
271 
273  decltype(auto) get_triangular_nested_matrix() const &
274  {
275  return this->get_nested_matrix_impl<triangular_matrix<NestedMatrix>>();
276  }
277 
278 
280  decltype(auto) get_triangular_nested_matrix() &&
281  {
282  return std::move(*this).template get_nested_matrix_impl<triangular_matrix<NestedMatrix>>();
283  }
284 
285 
287  decltype(auto) get_triangular_nested_matrix() const &&
288  {
289  return std::move(*this).template get_nested_matrix_impl<triangular_matrix<NestedMatrix>>();
290  }
291 
292 
296  auto determinant() const
297  {
298  if constexpr (triangular_covariance<Derived> and not triangular_matrix<NestedMatrix>)
299  {
300  if (synchronization_direction() > 0)
301  {
302  return square_root(OpenKalman::determinant(nested_object()));
303  }
304  else
305  {
306  return OpenKalman::determinant(cholesky_nested_matrix());
307  }
308  }
309  else if constexpr (self_adjoint_covariance<Derived> and not hermitian_matrix<NestedMatrix>)
310  {
311  if (synchronization_direction() > 0)
312  {
314  return d * d;
315  }
316  else
317  {
318  return OpenKalman::determinant(cholesky_nested_matrix());
319  }
320  }
321  else
322  {
323  if (synchronization_direction() < 0)
324  {
325  if constexpr (triangular_covariance<Derived>)
326  {
327  return square_root(OpenKalman::determinant(cholesky_nested_matrix()));
328  }
329  else
330  {
331  auto d = OpenKalman::determinant(cholesky_nested_matrix());
332  return d * d;
333  }
334  }
335  else
336  {
338  }
339  }
340  }
341 
342 
349 #ifdef __cpp_concepts
350  auto operator() (std::size_t i, std::size_t j)
351  requires writable_by_component<NestedMatrix, 2> and element_gettable<NestedMatrix, 2>
352 #else
353  template<typename T = NestedMatrix, std::enable_if_t<writable_by_component<T, 2> and element_gettable<T, 2>, int> = 0>
354  auto operator() (std::size_t i, std::size_t j)
355 #endif
356  {
357  return Base::operator()(i, j);
358  }
359 
360 
362 #ifdef __cpp_concepts
363  auto operator() (std::size_t i, std::size_t j) const requires element_gettable<NestedMatrix, 2>
364 #else
365  template<typename T = NestedMatrix, std::enable_if_t<element_gettable<T, 2>, int> = 0>
366  auto operator() (std::size_t i, std::size_t j) const
367 #endif
368  {
369  return Base::operator()(i, j);
370  }
371 
372 
378 #ifdef __cpp_concepts
379  auto operator[] (std::size_t i) requires writable_by_component<NestedMatrix, 1> and element_gettable<NestedMatrix, 1>
380 #else
381  template<typename T = NestedMatrix, std::enable_if_t<writable_by_component<T, 1> and element_gettable<T, 1>, int> = 0>
382  auto operator[] (std::size_t i)
383 #endif
384  {
385  return Base::operator[](i);
386  }
387 
388 
390 #ifdef __cpp_concepts
391  auto operator[] (std::size_t i) const requires element_gettable<NestedMatrix, 1>
392 #else
393  template<typename T = NestedMatrix, std::enable_if_t<element_gettable<T, 1>, int> = 0>
394  auto operator[] (std::size_t i) const
395 #endif
396  {
397  return Base::operator[](i);
398  }
399 
400 
402 #ifdef __cpp_concepts
403  auto operator() (std::size_t i) requires writable_by_component<NestedMatrix, 1> and element_gettable<NestedMatrix, 1>
404 #else
405  template<typename T = NestedMatrix, std::enable_if_t<writable_by_component<T, 1> and element_gettable<T, 1>, int> = 0>
406  auto operator() (std::size_t i)
407 #endif
408  {
409  return Base::operator[](i);
410  }
411 
412 
414 #ifdef __cpp_concepts
415  auto operator() (std::size_t i) const
416  requires element_gettable<NestedMatrix, 1>
417 #else
418  template<typename T = NestedMatrix, std::enable_if_t<element_gettable<T, 1>, int> = 0>
419  auto operator() (std::size_t i) const
420 #endif
421  {
422  return Base::operator[](i);
423  }
424 
425 
429 #ifdef __cpp_concepts
430  void set_component(const Scalar s, const std::size_t i, const std::size_t j) requires writable_by_component<NestedMatrix, 2>
431 #else
432  template<typename T = NestedMatrix, std::enable_if_t<writable_by_component<T, 2>, int> = 0>
433  void set_component(const Scalar s, const std::size_t i, const std::size_t j)
434 #endif
435  {
436  Base::set_component(s, i, j);
437  }
438 
439 
443 #ifdef __cpp_concepts
444  void set_component(const Scalar s, const std::size_t i) requires writable_by_component<NestedMatrix, 1>
445 #else
446  template<typename T = NestedMatrix, std::enable_if_t<writable_by_component<T, 1>, int> = 0>
447  void set_component(const Scalar s, const std::size_t i)
448 #endif
449  {
450  Base::set_component(s, i);
451  }
452 
453 
454  };
455 
456 
457 } // OpenKalman::internal
458 
459 #endif //OPENKALMAN_COVARIANCEIMPL_HPP
auto covariance_op(const F1 &f1, const F2 &f2) const &&
Definition: CovarianceImpl.hpp:116
Definition: CovarianceImpl.hpp:39
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
void set_component(const Scalar s, const std::size_t i)
Set an element of the cholesky nested matrix.
Definition: CovarianceImpl.hpp:447
auto covariance_op(const F &f) const &
Definition: CovarianceImpl.hpp:148
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: CovarianceImpl.hpp:433
auto operator()(std::size_t i, std::size_t j)
Get or set element (i, j) of the covariance matrix.
Definition: CovarianceImpl.hpp:354
Definition: CovarianceBase1.hpp:34
constexpr auto determinant(Arg &&arg)
Take the determinant of a matrix.
Definition: determinant.hpp:44
auto covariance_op(const F &f) const &&
Definition: CovarianceImpl.hpp:161
decltype(auto) get_self_adjoint_nested_matrix() &
Definition: CovarianceImpl.hpp:236
scalar_type_of_t< NestedMatrix > Scalar
Scalar type for this matrix.
Definition: CovarianceImpl.hpp:47
decltype(auto) get_triangular_nested_matrix() &
Definition: CovarianceImpl.hpp:266
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:34
Definition: basics.hpp:48
auto operator[](std::size_t i)
Get or set element i of the covariance matrix, if it is a vector.
Definition: CovarianceImpl.hpp:382
auto determinant() const
Definition: CovarianceImpl.hpp:296