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