OpenKalman
SquareRootCovariance.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 
11 #ifndef OPENKALMAN_SQUAREROOTCOVARIANCE_HPP
12 #define OPENKALMAN_SQUAREROOTCOVARIANCE_HPP
13 
14 
15 namespace OpenKalman
16 {
17  namespace oin = OpenKalman::internal;
18 
19  // ---------------------- //
20  // SquareRootCovariance //
21  // ---------------------- //
22 
23 #ifdef __cpp_concepts
24  template<fixed_pattern StaticDescriptor, covariance_nestable NestedMatrix> requires
25  (coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of_v<NestedMatrix, 0>) and
26  (not std::is_rvalue_reference_v<NestedMatrix>) and values::number<scalar_type_of_t<NestedMatrix>>
27 #else
28  template<typename StaticDescriptor, typename NestedMatrix>
29 #endif
30  struct SquareRootCovariance : oin::CovarianceImpl<SquareRootCovariance<StaticDescriptor, NestedMatrix>, NestedMatrix>
31  {
32 
33 #ifndef __cpp_concepts
34  static_assert(fixed_pattern<StaticDescriptor>);
35  static_assert(covariance_nestable<NestedMatrix>);
36  static_assert(coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of_v<NestedMatrix, 0>);
37  static_assert(not std::is_rvalue_reference_v<NestedMatrix>);
38  static_assert(values::number<scalar_type_of_t<NestedMatrix>>);
39 #endif
40 
41  // May be accessed externally through MatrixTraits:
43 
44  private:
45 
47  using typename Base::CholeskyNestedMatrix;
48  using Base::nested_object;
49  using Base::cholesky_nested_matrix;
50  using Base::synchronization_direction;
51  using Base::synchronize_forward;
52  using Base::synchronize_reverse;
53  using Base::mark_nested_matrix_changed;
54  using Base::mark_cholesky_nested_matrix_changed;
55  using Base::mark_synchronized;
56 
57 
58  // May be accessed externally through MatrixTraits:
59  static constexpr auto dim = index_dimension_of_v<NestedMatrix, 0>;
60 
61  // May be accessed externally through MatrixTraits:
62  static constexpr TriangleType triangle_type =
63  triangle_type_of_v<typename MatrixTraits<std::decay_t<NestedMatrix>>::template TriangularAdapterFrom<>>;
64 
65  // A triangular nested matrix type.
66  using NestedTriangular = std::conditional_t<triangular_matrix<NestedMatrix>, NestedMatrix,
67  typename MatrixTraits<std::decay_t<NestedMatrix>>::template TriangularAdapterFrom<triangle_type>>;
68 
69 
70  // A function that makes a self-contained covariance from a nested matrix.
71  template<typename C = StaticDescriptor, typename Arg>
72  static auto make(Arg&& arg)
73  {
74  return SquareRootCovariance<C, std::decay_t<Arg>>(std::forward<Arg>(arg));
75  }
76 
77 
81 #ifdef __cpp_concepts
82  template<self_adjoint_covariance M> requires (not diagonal_matrix<M> or identity_matrix<M> or zero<M>) and
83  (hermitian_matrix<nested_object_of_t<M>> == hermitian_matrix<NestedMatrix>)
84 #else
85  template<typename M, std::enable_if_t<self_adjoint_covariance<M> and
86  (not diagonal_matrix<M> or identity_matrix<M> or zero<M>) and
87  (hermitian_matrix<nested_object_of_t<M>> == hermitian_matrix<NestedMatrix>), int> = 0>
88 #endif
89  SquareRootCovariance(M&& m) : Base {std::forward<M>(m)} {}
90 
91 
92  public:
93  // ------------ //
94  // Constructors //
95  // ------------ //
96 
98 #ifdef __cpp_concepts
99  SquareRootCovariance() requires std::default_initializable<Base>
100 #else
101  template<typename T = Base, std::enable_if_t<std::is_default_constructible_v<T>, int> = 0>
103 #endif
104  : Base {} {}
105 
106 
110 #ifdef __cpp_concepts
111  template<triangular_covariance M> requires (not std::derived_from<std::decay_t<M>, SquareRootCovariance>) and
112  (triangle_type_of_v<M> == triangle_type_of_v<SquareRootCovariance>) and requires(M&& m) { Base {std::forward<M>(m)}; }
113 #else
114  template<typename M, std::enable_if_t<
115  triangular_covariance<M> and (not std::is_base_of_v<SquareRootCovariance, std::decay_t<M>>) and
117  std::is_constructible_v<Base, M&&>, int> = 0>
118 #endif
119  SquareRootCovariance(M&& m) : Base {std::forward<M>(m)} {}
120 
121 
125 #ifdef __cpp_concepts
126  template<covariance_nestable M> requires requires(M&& m) { Base {std::forward<M>(m)}; }
127 #else
128  template<typename M, std::enable_if_t<covariance_nestable<M> and
129  std::is_constructible_v<Base, M&&>, int> = 0>
130 #endif
131  explicit SquareRootCovariance(M&& m) : Base {std::forward<M>(m)} {}
132 
133 
140 #ifdef __cpp_concepts
141  template<typed_matrix M> requires (square_shaped<M> or (diagonal_matrix<NestedMatrix> and vector<M>)) and
142  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor> and
143  requires(M&& m) { Base {oin::to_covariance_nestable<NestedTriangular>(std::forward<M>(m))}; }
144 #else
145  template<typename M, std::enable_if_t<typed_matrix<M> and
146  (square_shaped<M> or (diagonal_matrix<NestedMatrix> and vector<M>)) and
147  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor> and
148  std::is_constructible_v<Base,
149  decltype(oin::to_covariance_nestable<NestedTriangular>(std::declval<M&&>()))>, int> = 0>
150 #endif
151  explicit SquareRootCovariance(M&& m)
152  : Base {oin::to_covariance_nestable<NestedTriangular>(std::forward<M>(m))} {}
153 
154 
161 #ifdef __cpp_concepts
162  template<typed_matrix_nestable M> requires (not covariance_nestable<M>) and
163  (square_shaped<M> or (diagonal_matrix<NestedMatrix> and vector<M>)) and
164  requires(M&& m) { Base {oin::to_covariance_nestable<NestedTriangular>(std::forward<M>(m))}; }
165 #else
166  template<typename M, std::enable_if_t<typed_matrix_nestable<M> and (not covariance_nestable<M>) and
167  (square_shaped<M> or (diagonal_matrix<NestedMatrix> and vector<M>)) and
168  std::is_constructible_v<Base,
169  decltype(oin::to_covariance_nestable<NestedTriangular>(std::declval<M&&>()))>, int> = 0>
170 #endif
171  explicit SquareRootCovariance(M&& m)
172  : Base {oin::to_covariance_nestable<NestedTriangular>(std::forward<M>(m))} {}
173 
174 
176 #ifdef __cpp_concepts
177  template<std::convertible_to<const Scalar> ... Args> requires (sizeof...(Args) > 0) and
178  requires(Args ... args) { Base {make_dense_object_from<NestedTriangular>(static_cast<const Scalar>(args)...)};
179  }
180 #else
181  template<typename ... Args, std::enable_if_t<(std::is_convertible_v<Args, const Scalar> and ...) and
182  ((diagonal_matrix<NestedMatrix> and sizeof...(Args) == dim) or
183  (sizeof...(Args) == dim * dim)) and std::is_constructible_v<Base, NestedTriangular&&>, int> = 0>
184 #endif
185  SquareRootCovariance(Args ... args)
186  : Base {make_dense_object_from<NestedTriangular>(static_cast<const Scalar>(args)...)} {}
187 
188 
189  // ---------------------- //
190  // Assignment Operators //
191  // ---------------------- //
192 
197 #ifdef __cpp_concepts
198  template<triangular_covariance Arg> requires (not std::derived_from<std::decay_t<Arg>, SquareRootCovariance>) and
199  (triangle_type_of_v<Arg> == triangle_type_of_v<SquareRootCovariance>) and
200  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor> and
201  std::assignable_from<std::add_lvalue_reference_t<NestedMatrix>, nested_object_of_t<Arg&&>>
202 #else
203  template<typename Arg, std::enable_if_t<triangular_covariance<Arg> and
204  (not std::is_base_of_v<SquareRootCovariance, std::decay_t<Arg>>) and
205  (triangle_type_of<Arg>::value == triangle_type_of<SquareRootCovariance>::value) and
206  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor> and
207  std::is_assignable_v<std::add_lvalue_reference_t<NestedMatrix>, nested_object_of_t<Arg&&>>, int> = 0>
208 #endif
209  auto& operator=(Arg&& other)
210  {
211  if constexpr (not zero<NestedMatrix> and not identity_matrix<NestedMatrix>)
212  {
213  Base::operator=(std::forward<Arg>(other));
214  }
215  return *this;
216  }
217 
218 
222 #ifdef __cpp_concepts
223  template<typed_matrix Arg> requires square_shaped<Arg> and
224  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor> and
225  std::assignable_from<std::add_lvalue_reference_t<NestedMatrix>, NestedTriangular>
226 #else
227  template<typename Arg, std::enable_if_t<typed_matrix<Arg> and square_shaped<Arg> and
228  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor> and
229  std::is_assignable_v<std::add_lvalue_reference_t<NestedMatrix>, NestedTriangular>, int> = 0>
230 #endif
231  auto& operator=(Arg&& other)
232  {
233  if constexpr (not zero<NestedMatrix> and not identity_matrix<NestedMatrix>)
234  {
235  Base::operator=(oin::to_covariance_nestable<NestedTriangular>(std::forward<Arg>(other)));
236  }
237  return *this;
238  }
239 
240 
244 #ifdef __cpp_concepts
245  template<covariance_nestable Arg> requires std::assignable_from<std::add_lvalue_reference_t<NestedMatrix>, Arg&&>
246 #else
247  template<typename Arg, std::enable_if_t<covariance_nestable<Arg> and
248  std::is_assignable_v<std::add_lvalue_reference_t<NestedMatrix>, int> = 0>
249 #endif
250  auto& operator=(Arg&& other)
251  {
252  if constexpr (not zero<NestedMatrix> and not identity_matrix<NestedMatrix>)
253  {
254  Base::operator=(std::forward<Arg>(other));
255  }
256  return *this;
257  }
258 
259 
263 #ifdef __cpp_concepts
264  template<typed_matrix_nestable Arg> requires (not covariance_nestable<Arg>) and square_shaped<Arg> and
265  std::assignable_from<std::add_lvalue_reference_t<NestedMatrix>, NestedTriangular>
266 #else
267  template<typename Arg, std::enable_if_t<typed_matrix_nestable<Arg> and (not covariance_nestable<Arg>) and
268  square_shaped<Arg> and std::is_assignable_v<std::add_lvalue_reference_t<NestedMatrix>, NestedTriangular>, int> = 0>
269 #endif
270  auto& operator=(Arg&& other)
271  {
272  if constexpr (not zero<NestedMatrix> and not identity_matrix<NestedMatrix>)
273  {
274  Base::operator=(oin::to_covariance_nestable<NestedTriangular>(std::forward<Arg>(other)));
275  }
276  return *this;
277  }
278 
279 
285 #ifdef __cpp_concepts
286  template<typename Arg> requires (not std::is_const_v<std::remove_reference_t<NestedMatrix>>) and
287  ((triangular_covariance<Arg> and triangle_type_of_v<Arg> == triangle_type_of_v<SquareRootCovariance>) or
288  (typed_matrix<Arg> and square_shaped<Arg>)) and
289  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor>
290 #else
291  template<typename Arg, std::enable_if_t<(not std::is_const_v<std::remove_reference_t<NestedMatrix>>) and
292  ((triangular_covariance<Arg> and triangle_type_of<Arg>::value == triangle_type_of<SquareRootCovariance>::value) or
293  (typed_matrix<Arg> and square_shaped<Arg>)) and
294  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor>, int> = 0>
295 #endif
296  auto& operator+=(const Arg& arg)
297  {
298  if constexpr(triangular_matrix<NestedMatrix>) // Case 1 or 2
299  {
300  nested_object() += oin::to_covariance_nestable<NestedMatrix>(arg);
301  mark_nested_matrix_changed();
302  }
303  else // Case 3 or 4
304  {
305  if (synchronization_direction() > 0) synchronize_forward();
306  cholesky_nested_matrix() += oin::to_covariance_nestable<NestedTriangular>(arg);
307  if (synchronization_direction() > 0)
308  {
309  Base::synchronize_reverse();
310  }
311  else
312  {
313  mark_cholesky_nested_matrix_changed();
314  }
315  }
316  return *this;
317  }
318 
319 
324 #ifdef __cpp_concepts
325  auto& operator+=(const SquareRootCovariance& arg)
326  requires (not std::is_const_v<std::remove_reference_t<NestedMatrix>>)
327 #else
328  template<typename T = NestedMatrix, std::enable_if_t<(not std::is_const_v<std::remove_reference_t<T>>), int> = 0>
329  auto& operator+=(const SquareRootCovariance& arg)
330 #endif
331  {
332  return operator+=<const SquareRootCovariance&>(arg);
333  }
334 
335 
341 #ifdef __cpp_concepts
342  template<typename Arg> requires (not std::is_const_v<std::remove_reference_t<NestedMatrix>>) and
343  ((triangular_covariance<Arg> and triangle_type_of_v<Arg> == triangle_type_of_v<SquareRootCovariance>) or
344  (typed_matrix<Arg> and square_shaped<Arg>)) and
345  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor>
346 #else
347  template<typename Arg, std::enable_if_t<(not std::is_const_v<std::remove_reference_t<NestedMatrix>>) and
348  ((triangular_covariance<Arg> and triangle_type_of<Arg>::value == triangle_type_of<SquareRootCovariance>::value) or
349  (typed_matrix<Arg> and square_shaped<Arg>)) and
350  compares_with<vector_space_descriptor_of_t<Arg, 0>, StaticDescriptor>, int> = 0>
351 #endif
352  auto& operator-=(const Arg& arg)
353  {
354  if constexpr(triangular_matrix<NestedMatrix>)
355  {
356  nested_object() -= oin::to_covariance_nestable<NestedMatrix>(arg);
357  mark_nested_matrix_changed();
358  }
359  else
360  {
361  if (synchronization_direction() > 0) synchronize_forward();
362  cholesky_nested_matrix() -= oin::to_covariance_nestable<NestedTriangular>(arg);
363  if (synchronization_direction() > 0)
364  {
365  synchronize_reverse();
366  }
367  else
368  {
369  mark_cholesky_nested_matrix_changed();
370  }
371  }
372  return *this;
373  }
374 
375 
380 #ifdef __cpp_concepts
381  auto& operator-=(const SquareRootCovariance& arg)
382  requires (not std::is_const_v<std::remove_reference_t<NestedMatrix>>)
383 #else
384  template<typename T = NestedMatrix, std::enable_if_t<(not std::is_const_v<std::remove_reference_t<T>>), int> = 0>
385  auto& operator-=(const SquareRootCovariance& arg)
386 #endif
387  {
388  return operator-=<const SquareRootCovariance&>(arg);
389  }
390 
391 
392 #ifdef __cpp_concepts
393  template<std::convertible_to<Scalar> S> requires (not std::is_const_v<std::remove_reference_t<NestedMatrix>>)
394 #else
395  template<typename S, std::enable_if_t<std::is_convertible_v<S, Scalar> and
396  (not std::is_const_v<std::remove_reference_t<NestedMatrix>>), int> = 0>
397 #endif
398  auto& operator*=(const S s)
399  {
400  if constexpr(triangular_matrix<NestedMatrix>)
401  {
402  nested_object() *= static_cast<const Scalar>(s);
403  mark_nested_matrix_changed();
404  }
405  else
406  {
407  if (synchronization_direction() >= 0) nested_object() *= static_cast<const Scalar>(s) * s;
408  if (synchronization_direction() <= 0) cholesky_nested_matrix() *= static_cast<const Scalar>(s);
409  }
410  return *this;
411  }
412 
413 
414 #ifdef __cpp_concepts
415  template<std::convertible_to<Scalar> S> requires (not std::is_const_v<std::remove_reference_t<NestedMatrix>>)
416 #else
417  template<typename S, std::enable_if_t<std::is_convertible_v<S, Scalar> and
418  (not std::is_const_v<std::remove_reference_t<NestedMatrix>>), int> = 0>
419 #endif
420  auto& operator/=(const S s)
421  {
422  if constexpr(triangular_matrix<NestedMatrix>)
423  {
424  nested_object() /= static_cast<const Scalar>(s);
425  mark_nested_matrix_changed();
426  }
427  else
428  {
429  if (synchronization_direction() >= 0) nested_object() /= static_cast<const Scalar>(s) * s;
430  if (synchronization_direction() <= 0) cholesky_nested_matrix() /= static_cast<const Scalar>(s);
431  }
432  return *this;
433  }
434 
435 
442 #ifdef __cpp_concepts
443  template<triangular_covariance Arg> requires (triangle_type_of_v<Arg> == triangle_type_of_v<SquareRootCovariance>) and
444  (not std::is_const_v<std::remove_reference_t<NestedMatrix>>)
445 #else
446  template<typename Arg, std::enable_if_t<triangular_covariance<Arg> and
447  (triangle_type_of<Arg>::value == triangle_type_of<SquareRootCovariance>::value) and
448  (not std::is_const_v<std::remove_reference_t<NestedMatrix>>), int> = 0>
449 #endif
450  auto& operator*=(const Arg& arg)
451  {
452  if constexpr(triangular_matrix<NestedMatrix>)
453  {
454  nested_object() *= oin::to_covariance_nestable<NestedMatrix>(arg);
455  mark_nested_matrix_changed();
456  }
457  else
458  {
459  if (synchronization_direction() > 0) synchronize_forward();
460  cholesky_nested_matrix() *= oin::to_covariance_nestable<NestedTriangular>(arg);
461  if (synchronization_direction() > 0)
462  {
463  synchronize_reverse();
464  }
465  else
466  {
467  mark_cholesky_nested_matrix_changed();
468  }
469  }
470  return *this;
471  }
472 
473 
474  // ------- //
475  // Other //
476  // ------- //
477 
484  auto square() &
485  {
486  if constexpr ((not diagonal_matrix<NestedMatrix>) or identity_matrix<NestedMatrix> or zero<NestedMatrix>)
487  {
489  }
490  else
491  {
492  auto n = cholesky_square(nested_object());
493  return Covariance<StaticDescriptor, decltype(n)> {std::move(n)};
494  }
495  }
496 
497 
499  auto square() const &
500  {
501  if constexpr ((not diagonal_matrix<NestedMatrix>) or identity_matrix<NestedMatrix> or zero<NestedMatrix>)
502  {
504  }
505  else
506  {
507  auto n = cholesky_square(nested_object());
508  return Covariance<StaticDescriptor, decltype(n)> {std::move(n)};
509  }
510  }
511 
512 
514  auto square() &&
515  {
516  if constexpr ((not diagonal_matrix<NestedMatrix>) or identity_matrix<NestedMatrix> or zero<NestedMatrix>)
517  {
519  }
520  else
521  {
522  auto n = cholesky_square(std::move(*this).nested_object());
523  return Covariance<StaticDescriptor, decltype(n)> {std::move(n)};
524  }
525  }
526 
527 
529  auto square() const &&
530  {
531  if constexpr ((not diagonal_matrix<NestedMatrix>) or identity_matrix<NestedMatrix> or zero<NestedMatrix>)
532  {
534  }
535  else
536  {
537  auto n = cholesky_square(std::move(*this).nested_object());
538  return Covariance<StaticDescriptor, decltype(n)> {std::move(n)};
539  }
540  }
541 
542 
546 #ifdef __cpp_concepts
547  template<typed_matrix U> requires compares_with<vector_space_descriptor_of_t<U, 0>, StaticDescriptor> and
548  (not std::is_const_v<std::remove_reference_t<NestedMatrix>>)
549 #else
550  template<typename U, std::enable_if_t<typed_matrix<U> and
551  compares_with<vector_space_descriptor_of_t<U, 0>, StaticDescriptor> and
552  (not std::is_const_v<std::remove_reference_t<NestedMatrix>>), int> = 0>
553 #endif
554  auto& rank_update(const U& u, const Scalar alpha = 1) &
555  {
556  if (synchronization_direction() < 0) synchronize_reverse();
557  OpenKalman::rank_update(nested_object(), OpenKalman::nested_object(u), alpha);
558  mark_nested_matrix_changed();
559  return *this;
560  }
561 
562 
566 #ifdef __cpp_concepts
567  template<typed_matrix U> requires compares_with<vector_space_descriptor_of_t<U, 0>, StaticDescriptor>
568 #else
569  template<typename U, std::enable_if_t<typed_matrix<U> and
570  compares_with<vector_space_descriptor_of_t<U, 0>, StaticDescriptor>, int> = 0>
571 #endif
572  auto rank_update(const U& u, const Scalar alpha = 1) &&
573  {
574  if (synchronization_direction() < 0) synchronize_reverse();
575  return make(OpenKalman::rank_update(nested_object(), OpenKalman::nested_object(u), alpha));
576  }
577 
578  private:
579 
580 #ifdef __cpp_concepts
581  template<typename, typename>
582 #else
583  template<typename, typename, typename>
584 #endif
585  friend struct oin::CovarianceBase;
586 
587 
588  template<typename, typename>
589  friend struct oin::CovarianceImpl;
590 
591 
592  template<typename, typename>
593  friend struct oin::CovarianceBase3Impl;
594 
595 
596 #ifdef __cpp_concepts
597  template<fixed_pattern C, covariance_nestable N> requires
598  (coordinates::dimension_of_v<C> == index_dimension_of_v<N, 0>) and (not std::is_rvalue_reference_v<N>)
599 #else
600  template<typename, typename>
601 #endif
602  friend struct SquareRootCovariance;
603 
604 
605 #ifdef __cpp_concepts
606  template<fixed_pattern C, covariance_nestable N> requires
607  (coordinates::dimension_of_v<C> == index_dimension_of_v<N, 0>) and (not std::is_rvalue_reference_v<N>)
608 #else
609  template<typename, typename>
610 #endif
611  friend struct Covariance;
612 
613  };
614 
615 
616  // ------------------------------- //
617  // Deduction guides //
618  // ------------------------------- //
619 
623 #ifdef __cpp_concepts
624  template<covariance_nestable M>
625 #else
626  template<typename M, std::enable_if_t<covariance_nestable<M>, int> = 0>
627 #endif
629 
630 
634 #ifdef __cpp_concepts
635  template<typed_matrix M> requires square_shaped<M>
636 #else
637  template<typename M, std::enable_if_t<typed_matrix<M> and square_shaped<M>, int> = 0>
638 #endif
640  typename MatrixTraits<std::decay_t<nested_object_of_t<M>>>::template TriangularAdapterFrom<>>;
641 
642 
646 #ifdef __cpp_concepts
647  template<typed_matrix_nestable M> requires (not covariance_nestable<M>) and square_shaped<M>
648 #else
649  template<typename M, std::enable_if_t<
650  typed_matrix_nestable<M> and (not covariance_nestable<M>) and square_shaped<M>, int> = 0>
651 #endif
653  typename MatrixTraits<std::decay_t<M>>::template TriangularAdapterFrom<>>;
654 
655 
656  // ---------------- //
657  // Make Functions //
658  // ---------------- //
659 
665 #ifdef __cpp_concepts
666  template<fixed_pattern StaticDescriptor, covariance_nestable Arg> requires
667  (coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of_v<Arg, 0>)
668 #else
669  template<typename StaticDescriptor, typename Arg, std::enable_if_t<fixed_pattern<StaticDescriptor> and
670  covariance_nestable<Arg> and (coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of<Arg, 0>::value), int> = 0>
671 #endif
672  inline auto
674  {
675  return SquareRootCovariance<StaticDescriptor, passable_t<Arg>>(std::forward<Arg>(arg));
676  }
677 
678 
685 #ifdef __cpp_concepts
686  template<covariance_nestable Arg>
687 #else
688  template<typename Arg, std::enable_if_t<covariance_nestable<Arg>, int> = 0>
689 #endif
690  inline auto
692  {
693  using C = Dimensions<index_dimension_of_v<Arg, 0>>;
694  return make_square_root_covariance<C>(std::forward<Arg>(arg));
695  }
696 
697 
705 #ifdef __cpp_concepts
706  template<fixed_pattern StaticDescriptor, TriangleType triangle_type = TriangleType::lower, typed_matrix_nestable Arg>
707  requires (not covariance_nestable<Arg>) and
708  (triangle_type == TriangleType::lower or triangle_type == TriangleType::upper) and
709  (coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of_v<Arg, 0>) and (coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of_v<Arg, 1>)
710 #else
711  template<typename StaticDescriptor, TriangleType triangle_type = TriangleType::lower, typename Arg, std::enable_if_t<
712  fixed_pattern<StaticDescriptor> and typed_matrix_nestable<Arg> and (not covariance_nestable<Arg>) and
713  (triangle_type == TriangleType::lower or triangle_type == TriangleType::upper) and
714  (coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of<Arg, 0>::value) and
715  (coordinates::dimension_of_v<StaticDescriptor> == index_dimension_of<Arg, 1>::value), int> = 0>
716 #endif
717  inline auto
719  {
720  using T = typename MatrixTraits<std::decay_t<Arg>>::template TriangularAdapterFrom<triangle_type>;
721  return SquareRootCovariance<StaticDescriptor, T>(std::forward<Arg>(arg));
722  }
723 
724 
731 #ifdef __cpp_concepts
732  template<TriangleType triangle_type = TriangleType::lower, typed_matrix_nestable Arg> requires
733  (not covariance_nestable<Arg>) and
734  (triangle_type == TriangleType::lower or triangle_type == TriangleType::upper) and square_shaped<Arg>
735 #else
736  template<TriangleType triangle_type = TriangleType::lower, typename Arg, std::enable_if_t<
737  typed_matrix_nestable<Arg> and (not covariance_nestable<Arg>) and
738  (triangle_type == TriangleType::lower or triangle_type == TriangleType::upper) and square_shaped<Arg>, int> = 0>
739 #endif
740  inline auto
741  make_square_root_covariance(Arg&& arg)
742  {
743  using C = Dimensions<index_dimension_of_v<Arg, 0>>;
744  return make_square_root_covariance<C, triangle_type>(std::forward<Arg>(arg));
745  }
746 
747 
752 #ifdef __cpp_concepts
753  template<fixed_pattern StaticDescriptor, TriangleType triangle_type, typed_matrix_nestable Arg> requires square_shaped<Arg>
754 #else
755  template<typename StaticDescriptor, TriangleType triangle_type, typename Arg,
756  std::enable_if_t<fixed_pattern<StaticDescriptor> and typed_matrix_nestable<Arg> and square_shaped<Arg>, int> = 0>
757 #endif
758  inline auto
760  {
761  using B = std::conditional_t<triangle_type == TriangleType::diagonal,
762  typename MatrixTraits<std::decay_t<Arg>>::template DiagonalMatrixFrom<>,
763  typename MatrixTraits<std::decay_t<Arg>>::template TriangularAdapterFrom<triangle_type>>;
765  }
766 
767 
772 #ifdef __cpp_concepts
773  template<fixed_pattern StaticDescriptor, typename Arg> requires
774  (covariance_nestable<Arg> or typed_matrix_nestable<Arg>) and square_shaped<Arg>
775 #else
776  template<typename StaticDescriptor, typename Arg, std::enable_if_t<
777  (covariance_nestable<Arg> or typed_matrix_nestable<Arg>) and square_shaped<Arg>, int> = 0>
778 #endif
779  inline auto
781  {
782  constexpr TriangleType template_type = triangle_type_of_v<typename MatrixTraits<std::decay_t<Arg>>::template TriangularAdapterFrom<>>;
783  using B = std::conditional_t<diagonal_matrix<Arg>,
784  typename MatrixTraits<std::decay_t<Arg>>::template DiagonalMatrixFrom<>,
785  std::conditional_t<hermitian_matrix<Arg>,
786  typename MatrixTraits<std::decay_t<Arg>>::template SelfAdjointMatrixFrom<template_type>,
787  typename MatrixTraits<std::decay_t<Arg>>::template TriangularAdapterFrom<template_type>>>;
789  }
790 
791 
797 #ifdef __cpp_concepts
798  template<typename Arg> requires (covariance_nestable<Arg> or typed_matrix_nestable<Arg>) and square_shaped<Arg>
799 #else
800  template<typename Arg, std::enable_if_t<(covariance_nestable<Arg> or typed_matrix_nestable<Arg>) and
801  square_shaped<Arg>, int> = 0>
802 #endif
803  inline auto
805  {
806  using C = Dimensions<index_dimension_of_v<Arg, 0>>;
807  return make_square_root_covariance<C, Arg>();
808  }
809 
810 
815 #ifdef __cpp_concepts
816  template<TriangleType triangle_type, typed_matrix_nestable Arg> requires square_shaped<Arg>
817 #else
818  template<TriangleType triangle_type, typename Arg, std::enable_if_t<
819  typed_matrix_nestable<Arg> and square_shaped<Arg>, int> = 0>
820 #endif
821  inline auto
823  {
824  using C = Dimensions<index_dimension_of_v<Arg, 0>>;
825  return make_square_root_covariance<C, triangle_type, Arg>();
826  }
827 
828 
833 #ifdef __cpp_concepts
834  template<triangular_covariance Arg>
835 #else
836  template<typename Arg, std::enable_if_t<triangular_covariance<Arg>, int> = 0>
837 #endif
838  inline auto
839  make_square_root_covariance(Arg&& arg)
840  {
842  return SquareRootCovariance<C, nested_object_of_t<Arg>>(std::forward<Arg>(arg));
843  }
844 
845 
850 #ifdef __cpp_concepts
851  template<triangular_covariance Arg>
852 #else
853  template<typename Arg, std::enable_if_t<triangular_covariance<Arg>, int> = 0>
854 #endif
855  inline auto
857  {
859  using B = nested_object_of_t<Arg>;
860  return make_square_root_covariance<C, B>();
861  }
862 
863 
868 #ifdef __cpp_concepts
869  template<TriangleType triangle_type = TriangleType::lower, typed_matrix Arg> requires
870  (triangle_type == TriangleType::lower or triangle_type == TriangleType::upper) and square_shaped<Arg>
871 #else
872  template<TriangleType triangle_type = TriangleType::lower, typename Arg, std::enable_if_t<typed_matrix<Arg> and
873  (triangle_type == TriangleType::lower or triangle_type == TriangleType::upper) and square_shaped<Arg>, int> = 0>
874 #endif
875  inline auto
876  make_square_root_covariance(Arg&& arg)
877  {
879  return make_square_root_covariance<C, triangle_type>(nested_object(std::forward<Arg>(arg)));
880  }
881 
882 
887 #ifdef __cpp_concepts
888  template<TriangleType triangle_type, typed_matrix Arg> requires square_shaped<Arg>
889 #else
890  template<TriangleType triangle_type, typename Arg, std::enable_if_t<
891  typed_matrix<Arg> and square_shaped<Arg>, int> = 0>
892 #endif
893  inline auto
895  {
897  using B = nested_object_of_t<Arg>;
898  return make_square_root_covariance<C, triangle_type, B>();
899  }
900 
901 
906 #ifdef __cpp_concepts
907  template<typed_matrix Arg> requires square_shaped<Arg>
908 #else
909  template<typename Arg, std::enable_if_t<typed_matrix<Arg> and square_shaped<Arg>, int> = 0>
910 #endif
911  inline auto
913  {
915  using B = nested_object_of_t<Arg>;
916  return make_square_root_covariance<C, B>();
917  }
918 
919 
920  // ------------------------- //
921  // Interfaces //
922  // ------------------------- //
923 
924  namespace interface
925  {
926  template<typename Coeffs, typename NestedMatrix>
927  struct indexible_object_traits<SquareRootCovariance<Coeffs, NestedMatrix>>
928  {
929  using scalar_type = scalar_type_of_t<NestedMatrix>;
930 
931  template<typename Arg>
932  static constexpr auto count_indices(const Arg& arg) { return std::integral_constant<std::size_t, 2>{}; }
933 
934  template<typename Arg, typename N>
935  static constexpr auto get_vector_space_descriptor(Arg&& arg, N)
936  {
937  return std::forward<Arg>(arg).my_dimension;
938  }
939 
940 
941  template<typename Arg>
942  static decltype(auto) nested_object(Arg&& arg)
943  {
944  if constexpr (hermitian_matrix<NestedMatrix>)
945  return std::forward<Arg>(arg).get_self_adjoint_nested_matrix();
946  else
947  return std::forward<Arg>(arg).get_triangular_nested_matrix();
948  }
949 
950 
951  template<typename Arg>
952  static constexpr auto get_constant(const Arg& arg)
953  {
954  if constexpr (zero<NestedMatrix>)
955  return constant_coefficient{arg.nestedExpression()};
956  else
957  return std::monostate {};
958  }
959 
960 
961  template<typename Arg>
962  static constexpr auto get_constant_diagonal(const Arg& arg)
963  {
964  return constant_diagonal_coefficient {arg.nestedExpression()};
965  }
966 
967 
968  template<Applicability b>
969  static constexpr bool one_dimensional = OpenKalman::one_dimensional<NestedMatrix, b>;
970 
971 
972  template<Applicability b>
973  static constexpr bool is_square = true;
974 
975 
976  template<TriangleType t>
977  static constexpr bool is_triangular = triangular_matrix<NestedMatrix, t> or
978  hermitian_adapter<NestedMatrix, t == TriangleType::upper ? HermitianAdapterType::upper : HermitianAdapterType::lower>;
979 
980 
981  static constexpr bool is_triangular_adapter = false;
982 
983 
984  static constexpr bool is_hermitian = false;
985 
986 
987  #ifdef __cpp_lib_concepts
988  template<typename Arg, typename...I> requires
989  element_gettable<decltype(std::declval<Arg&&>().get_triangular_nested_matrix()), sizeof...(I)>
990  #else
991  template<typename Arg, typename...I, std::enable_if_t<
992  element_gettable<decltype(std::declval<Arg&&>().get_triangular_nested_matrix()), sizeof...(I)>, int> = 0>
993  #endif
994  static constexpr auto get(Arg&& arg, I...i)
995  {
996  return std::forward<Arg>(arg)(i...);
997  }
998 
999 
1000  #ifdef __cpp_lib_concepts
1001  template<typename Arg, typename...I> requires
1002  writable_by_component<decltype(std::declval<Arg&>().get_triangular_nested_matrix()), sizeof...(I)>
1003  #else
1004  template<typename Arg, typename...I, std::enable_if_t<
1005  writable_by_component<decltype(std::declval<Arg&>().get_triangular_nested_matrix()), sizeof...(I)>, int> = 0>
1006  #endif
1007  static constexpr void set(Arg& arg, const scalar_type_of_t<Arg>& s, I...i)
1008  {
1009  arg.set_component(s, i...);
1010  }
1011 
1012  static constexpr bool is_writable = library_interface<std::decay_t<NestedMatrix>>::is_writable;
1013 
1014 
1015 #ifdef __cpp_lib_concepts
1016  template<typename Arg> requires one_dimensional<NestedMatrix> and raw_data_defined_for<NestedMatrix>
1017 #else
1018  template<typename Arg, std::enable_if_t<one_dimensional<NestedMatrix> and raw_data_defined_for<NestedMatrix>, int> = 0>
1019 #endif
1020  static constexpr auto * const
1021  raw_data(Arg& arg) { return internal::raw_data(arg.nested_object()); }
1022 
1023 
1024  static constexpr Layout layout = one_dimensional<NestedMatrix> ? layout_of_v<NestedMatrix> : Layout::none;
1025 
1026  };
1027 
1028  } // namespace interface
1029 
1030 
1031 }
1032 
1033 
1034 #endif //OPENKALMAN_SQUAREROOTCOVARIANCE_HPP
1035 
constexpr auto count_indices(const T &t)
Get the number of indices available to address the components of an indexible object.
Definition: count_indices.hpp:33
typename nested_object_of< T >::type nested_object_of_t
Helper type for nested_object_of.
Definition: nested_object_of.hpp:66
auto make_square_root_covariance(Arg &&arg)
Make a SquareRootCovariance from a covariance_nestable, specifying the coefficients.
Definition: SquareRootCovariance.hpp:673
constexpr bool one_dimensional
Specifies that a type is one-dimensional in every index.
Definition: one_dimensional.hpp:83
TriangleType
The type of a triangular matrix.
Definition: global-definitions.hpp:60
Definition: indexible_object_traits.hpp:36
auto & operator=(Arg &&other)
Assign from a compatible triangular_covariance.
Definition: SquareRootCovariance.hpp:209
auto & operator=(Arg &&other)
Assign from a compatible typed_matrix (assumed, without checking, to be triangular).
Definition: SquareRootCovariance.hpp:231
Definition: CovarianceImpl.hpp:39
No storage layout (e.g., if the elements are calculated rather than stored).
typename scalar_type_of< T >::type scalar_type_of_t
helper template for scalar_type_of.
Definition: scalar_type_of.hpp:54
constexpr bool number
T is a numerical type.
Definition: number.hpp:33
An upper-right triangular matrix.
decltype(auto) constexpr cholesky_square(A &&a)
Take the Cholesky square of a triangular_matrix.
Definition: cholesky_square.hpp:33
SquareRootCovariance()
Default constructor.
Definition: SquareRootCovariance.hpp:102
Definition: CovarianceBase3Impl.hpp:35
The constant associated with T, assuming T is a constant_matrix.
Definition: constant_coefficient.hpp:36
The upper or lower triangle Cholesky factor (square root) of a covariance matrix. ...
Definition: forward-class-declarations.hpp:559
The root namespace for OpenKalman.
Definition: basics.hpp:34
An interface to various routines from the linear algebra library associated with indexible object T...
Definition: library_interface.hpp:37
SquareRootCovariance(Args ... args)
Construct from Scalar coefficients. Assumes matrix is triangular, and only reads lower left triangle...
Definition: SquareRootCovariance.hpp:185
The constant associated with T, assuming T is a constant_diagonal_matrix.
Definition: constant_diagonal_coefficient.hpp:32
Definition: CovarianceBase1.hpp:34
SquareRootCovariance(M &&m)
Construct from a covariance_nestable.
Definition: SquareRootCovariance.hpp:131
SquareRootCovariance(M &&m)
Construct from another triangular_covariance.
Definition: SquareRootCovariance.hpp:119
typename vector_space_descriptor_of< T, N >::type vector_space_descriptor_of_t
helper template for vector_space_descriptor_of.
Definition: vector_space_descriptor_of.hpp:56
Layout
The layout format of a multidimensional array.
Definition: global-definitions.hpp:47
The common TriangleType associated with a set of triangular matrices.
Definition: triangle_type_of.hpp:29
A self-adjoint Covariance matrix.
Definition: Covariance.hpp:30
A diagonal matrix (both a lower-left and an upper-right triangular matrix).
The dimension of an index for a matrix, expression, or array.
Definition: index_dimension_of.hpp:34
scalar_type_of_t< NestedMatrix > Scalar
Scalar type for this matrix.
Definition: SquareRootCovariance.hpp:42
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:34
SquareRootCovariance(M &&) -> SquareRootCovariance< Dimensions< index_dimension_of_v< M, 0 >>, passable_t< M >>
Deduce SquareRootCovariance type from a covariance_nestable.
A lower-left triangular matrix.
Definition: basics.hpp:48
constexpr bool hermitian_matrix
Specifies that a type is a hermitian matrix (assuming it is square_shaped).
Definition: hermitian_matrix.hpp:50
constexpr auto get_vector_space_descriptor(const T &t, const N &n)
Get the coordinates::pattern object for index N of indexible object T.
Definition: get_vector_space_descriptor.hpp:56