OpenKalman
GaussianDistribution.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2017-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 
16 #ifndef OPENKALMAN_GAUSSIANDISTRIBUTION_HPP
17 #define OPENKALMAN_GAUSSIANDISTRIBUTION_HPP
18 
19 #include <iostream>
20 #include <adapters/details/adapters-interface.hpp>
21 
22 
23 namespace OpenKalman
24 {
25 #ifdef __cpp_concepts
26  template<
27  fixed_pattern StaticDescriptor,
28  typed_matrix_nestable MeanNestedMatrix,
29  covariance_nestable CovarianceNestedMatrix,
30  std::uniform_random_bit_generator random_number_engine> requires
31  (index_dimension_of_v<MeanNestedMatrix, 0> == index_dimension_of_v<CovarianceNestedMatrix, 0>) and
32  (index_dimension_of_v<MeanNestedMatrix, 1> == 1) and
33  (std::is_same_v<scalar_type_of_t<MeanNestedMatrix>,
34  scalar_type_of_t<CovarianceNestedMatrix>>)
35 #else
36  template<
37  typename StaticDescriptor,
38  typename MeanNestedMatrix,
39  typename CovarianceNestedMatrix,
40  typename random_number_engine>
41 #endif
43  {
44 
45 #ifndef __cpp_concepts
46  static_assert(typed_matrix_nestable<MeanNestedMatrix>);
47  static_assert(covariance_nestable<CovarianceNestedMatrix>);
48  static_assert(index_dimension_of_v<MeanNestedMatrix, 0> == index_dimension_of_v<CovarianceNestedMatrix, 0>);
49  static_assert(index_dimension_of_v<MeanNestedMatrix, 1> == 1);
50  static_assert(std::is_same_v<scalar_type_of_t<MeanNestedMatrix>,
52 #endif
53 
54  protected:
55 
56  static constexpr auto dim = coordinates::dimension_of_v<StaticDescriptor>;
59  using Scalar = scalar_type_of_t<Mean>;
60 
61  private:
62 
63  template<typename Arg>
64  static decltype(auto) cov_adapter(Arg&& arg)
65  {
66  if constexpr (triangular_covariance<Arg>) return square(std::forward<Arg>(arg));
67  else return std::forward<Arg>(arg);
68  }
69 
70  public:
71 
72  // -------------- //
73  // Constructors //
74  // -------------- //
75 
76  /*
77  * \brief Default constructor.
78  */
79 #ifdef __cpp_concepts
80  GaussianDistribution() requires std::default_initializable<Mean> and std::default_initializable<Covariance>
81 #else
82  template<typename T = Mean, typename U = Covariance, std::enable_if_t<
83  std::is_default_constructible_v<T> and std::is_default_constructible_v<U>, int> = 0>
85 #endif
86  : mu {}, sigma {} {}
87 
88 
92 #ifdef __cpp_concepts
93  template<gaussian_distribution Arg> requires (not std::derived_from<std::decay_t<Arg>, GaussianDistribution>) and
94  compares_with<typename DistributionTraits<Arg>::StaticDescriptor, StaticDescriptor>
95 #else
96  template<typename Arg, std::enable_if_t<gaussian_distribution<Arg> and
97  not std::is_base_of_v<GaussianDistribution, std::decay_t<Arg>> and
98  compares_with<typename DistributionTraits<Arg>::StaticDescriptor, StaticDescriptor>, int> = 0>
99 #endif
101  : mu {std::forward<Arg>(arg).mu}, sigma {std::forward<Arg>(arg).sigma} {}
102 
103 
107  GaussianDistribution(Mean&& mean, Covariance&& cov) : mu {std::move(mean)}, sigma {std::move(cov)} {}
108 
109 
113 #ifdef __cpp_concepts
114  template<typed_matrix M> requires vector<M> and has_untyped_index<M, 1> and
115  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor>
116 #else
117  template<typename M, std::enable_if_t<typed_matrix<M> and vector<M> and has_untyped_index<M, 1> and
118  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor>, int> = 0>
119 #endif
120  GaussianDistribution(M&& mean, Covariance&& cov) : mu {std::forward<M>(mean)}, sigma {std::move(cov)} {}
121 
122 
126 #ifdef __cpp_concepts
127  template<typed_matrix_nestable M> requires vector<M> and (index_dimension_of_v<M, 0> == dim)
128 #else
129  template<typename M, std::enable_if_t<typed_matrix_nestable<M> and vector<M> and
130  (index_dimension_of<M, 0>::value == dim), int> = 0>
131 #endif
132  GaussianDistribution(M&& mean, Covariance&& cov) : mu {std::forward<M>(mean)}, sigma {std::move(cov)} {}
133 
134 
139 #ifdef __cpp_concepts
140  template<typename Cov> requires ((covariance<Cov> or (typed_matrix<Cov> and square_shaped<Cov>)) and
141  compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>) or
142  (covariance_nestable<Cov> and index_dimension_of_v<Cov, 0> == dim)
143 #else
144  template<typename Cov, std::enable_if_t<(covariance<Cov> or (typed_matrix<Cov> and square_shaped<Cov>)) and
145  compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>, int> = 0>
146  GaussianDistribution(Mean&& mean, Cov&& cov) : mu {std::move(mean)}, sigma {cov_adapter(std::forward<Cov>(cov))} {}
147 
148  template<typename Cov, std::enable_if_t<
149  covariance_nestable<Cov> and (index_dimension_of<Cov, 0>::value == dim), int> = 0>
150 #endif
151  GaussianDistribution(Mean&& mean, Cov&& cov) : mu {std::move(mean)}, sigma {cov_adapter(std::forward<Cov>(cov))} {}
152 
153 
159 #ifdef __cpp_concepts
160  template<typed_matrix M, typename Cov> requires vector<M> and has_untyped_index<M, 1> and
161  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor> and
162  (covariance<Cov> or typed_matrix<Cov>) and
163  compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>
164 #else
165  template<typename M, typename Cov, std::enable_if_t<typed_matrix<M> and vector<M> and has_untyped_index<M, 1> and
166  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor> and
167  (covariance<Cov> or typed_matrix<Cov>) and
168  compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>, int> = 0>
169 #endif
170  GaussianDistribution(M&& mean, Cov&& cov)
171  : mu {std::forward<M>(mean)}, sigma {cov_adapter(std::forward<Cov>(cov))} {}
172 
173 
179 #ifdef __cpp_concepts
180  template<typed_matrix M, typename Cov> requires vector<M> and has_untyped_index<M, 1> and
181  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor> and
182  covariance_nestable<Cov> and (index_dimension_of_v<Cov, 0> == dim)
183 #else
184  template<typename M, typename Cov, std::enable_if_t<typed_matrix<M> and vector<M> and has_untyped_index<M, 1> and
185  compares_with<vector_space_descriptor_of_t<M, 0>, StaticDescriptor> and
186  covariance_nestable<Cov> and (index_dimension_of<Cov, 0>::value == dim), int> = 0>
187 #endif
188  GaussianDistribution(M&& mean, Cov&& cov) : mu {std::forward<M>(mean)}, sigma {std::forward<Cov>(cov)} {}
189 
190 
196 #ifdef __cpp_concepts
197  template<typed_matrix_nestable M, typename Cov> requires vector<M> and
198  (index_dimension_of_v<M, 0> == dim) and (covariance<Cov> or typed_matrix<Cov>) and
199  coordinates::compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>
200 #else
201  template<typename M, typename Cov, std::enable_if_t<typed_matrix_nestable<M> and vector<M> and
202  (index_dimension_of<M, 0>::value == dim) and (covariance<Cov> or typed_matrix<Cov>) and
203  compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>, int> = 0>
204 #endif
205  GaussianDistribution(M&& mean, Cov&& cov)
206  : mu {std::forward<M>(mean)}, sigma {cov_adapter(std::forward<Cov>(cov))} {}
207 
208 
214 #ifdef __cpp_concepts
215  template<typed_matrix_nestable M, typename Cov> requires vector<M> and
216  (index_dimension_of_v<M, 0> == dim) and covariance_nestable<Cov> and
217  (index_dimension_of_v<Cov, 0> == dim)
218 #else
219  template<typename M, typename Cov, std::enable_if_t<typed_matrix_nestable<M> and vector<M> and
220  (index_dimension_of<M, 0>::value == dim) and covariance_nestable<Cov> and
221  (index_dimension_of<Cov, 0>::value == dim), int> = 0>
222 #endif
223  GaussianDistribution(M&& mean, Cov&& cov) : mu {std::forward<M>(mean)}, sigma {std::forward<Cov>(cov)} {}
224 
225 
227 #ifdef __cpp_concepts
228  template<typename Cov> requires (covariance<Cov> or (typed_matrix<Cov> and square_shaped<Cov>)) and
229  coordinates::compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>
230 #else
231  template<typename Cov, std::enable_if_t<(covariance<Cov> or (typed_matrix<Cov> and square_shaped<Cov>)) and
232  compares_with<vector_space_descriptor_of_t<Cov, 0>, StaticDescriptor>, int> = 0>
233 #endif
234  explicit GaussianDistribution(Cov&& cov) :
235  mu {[]{ make_zero<MeanNestedMatrix>(get_vector_space_descriptor<0>(cov), Dimensions<1>{}); }()},
236  sigma {cov_adapter(std::forward<Cov>(cov))} {}
237 
238 
240 #ifdef __cpp_concepts
241  template<covariance_nestable Cov> requires (index_dimension_of_v<Cov, 0> == dim)
242 #else
243  template<typename Cov, std::enable_if_t<
244  covariance_nestable<Cov> and (index_dimension_of<Cov, 0>::value == dim), int> = 0>
245 #endif
246  explicit GaussianDistribution(Cov&& cov) :
247  mu {[]{ make_zero<MeanNestedMatrix>(get_vector_space_descriptor<0>(cov), Dimensions<1>{}); }()},
248  sigma {cov_adapter(std::forward<Cov>(cov))}{}
249 
250  // ---------------------- //
251  // Assignment Operators //
252  // ---------------------- //
253 
255 #ifdef __cpp_concepts
256  template<gaussian_distribution Arg> requires
257  coordinates::compares_with<typename DistributionTraits<Arg>::StaticDescriptor, StaticDescriptor>
258 #else
259  template<typename Arg, std::enable_if_t<gaussian_distribution<Arg> and
260  compares_with<typename DistributionTraits<Arg>::StaticDescriptor, StaticDescriptor>, int> = 0>
261 #endif
263  {
264  if constexpr (std::is_same_v<std::decay_t<Arg>, GaussianDistribution>) if (this == &arg) return *this;
265  mu = std::forward<Arg>(arg).mu;
266  sigma = std::forward<Arg>(arg).sigma;
267  return *this;
268  }
269 
270 
271  auto& operator+=(const GaussianDistribution& arg)
272  {
273  mu += arg.mu;
274  sigma += arg.sigma;
275  return *this;
276  };
277 
278 
279  auto& operator-=(const GaussianDistribution& arg)
280  {
281  mu -= arg.mu;
282  sigma -= arg.sigma;
283  return *this;
284  };
285 
286 
287  template<typename S, std::enable_if_t<std::is_convertible_v<S, const Scalar>, int> = 0>
288  auto& operator*=(const S scale)
289  {
290  mu *= static_cast<const Scalar>(scale);
291  sigma.scale(static_cast<const Scalar>(scale));
292  return *this;
293  };
294 
295 
296  template<typename S, std::enable_if_t<std::is_convertible_v<S, const Scalar>, int> = 0>
297  auto& operator/=(const S scale)
298  {
299  mu /= static_cast<const Scalar>(scale);
300  sigma.inverse_scale(static_cast<const Scalar>(scale));
301  return *this;
302  };
303 
304  // ------- //
305  // Other //
306  // ------- //
307 
308  private:
309 
310  template<typename M, typename C>
311  static auto
312  make(M&& m, C&& c)
313  {
314  using MB = equivalent_self_contained_t<nested_object_of_t<M>>;
315  using CB = equivalent_self_contained_t<nested_object_of_t<C>>;
316  return GaussianDistribution<StaticDescriptor, MB, CB, random_number_engine>(std::forward<M>(m), std::forward<C>(c));
317  }
318 
319  public:
320 
325  auto operator()() const
326  {
327  auto norm = randomize<Matrix<StaticDescriptor, Axis, MeanNestedMatrix>, random_number_engine>(
328  std::normal_distribution {0.0, 1.0});
329  auto s = square_root(sigma);
330  if constexpr(triangular_matrix<decltype(s), TriangleType::upper>)
331  return sum(Matrix {mu}, contract(transpose(std::move(s)), std::move(norm)));
332  else
333  return sum(Matrix {mu}, contract(std::move(s), std::move(norm)));
334  }
335 
336 
341 #ifdef __cpp_concepts
342  template<typed_matrix...Z> requires (sizeof...(Z) > 0) and
343  ((vector<Z> and compares_with<vector_space_descriptor_of_t<Z, 0>, StaticDescriptor>) and ...)
344 #else
345  template<typename...Z, std::enable_if_t<(sizeof...(Z) > 0) and ((typed_matrix<Z> and vector<Z> and
346  compares_with<vector_space_descriptor_of_t<Z, 0>, StaticDescriptor>) and ...), int> = 0>
347 #endif
348  Scalar log_likelihood(const Z&...z) const
349  {
350  static constexpr auto n = sizeof...(Z);
351  auto sum = (trace(transpose(z - mu) * solve(sigma, z - mu)) + ...);
352  return -0.5 * (n * (dim * values::log(2 * numbers::pi_v<long double>) +
354  }
355 
356 
358  Scalar entropy() const
359  {
360  return 0.5 * (dim * (1 + values::log2(numbers::pi_v<long double>) +
361  Scalar {numbers::log2e_v<long double>}) + values::log2(determinant(sigma)));
362  }
363 
364 
368  Mean mu;
369 
370 
374  Covariance sigma;
375 
376  };
377 
378 
379  // ------------------------------- //
380  // Deduction Guides //
381  // ------------------------------- //
382 
383 #ifdef __cpp_concepts
384  template<typed_matrix M, self_adjoint_covariance C>
385 #else
386  template<typename M, typename C, std::enable_if_t<typed_matrix<M> and self_adjoint_covariance<C>, int> = 0>
387 #endif
392 
393 
394 #ifdef __cpp_concepts
395  template<typed_matrix M, triangular_covariance C>
396 #else
397  template<typename M, typename C, std::enable_if_t<
398  typed_matrix<M> and triangular_covariance<C>, int> = 0>
399 #endif
401  vector_space_descriptor_of_t<M, 0>,
402  nested_object_of_t<passable_t<M>>,
404 
405 
406 #ifdef __cpp_concepts
407  template<typed_matrix M, typed_matrix C> requires
408  coordinates::compares_with<vector_space_descriptor_of_t<C, 0>, vector_space_descriptor_of_t<C, 1>>
409 #else
410  template<typename M, typename C, std::enable_if_t<
411  typed_matrix<M> and typed_matrix<C> and
412  compares_with<vector_space_descriptor_of_t<C, 0>, vector_space_descriptor_of_t<C, 1>>, int> = 0>
413 #endif
417  decltype(to_covariance_nestable(nested_object(std::declval<passable_t<C>>())))>;
418 
419 
420 #ifdef __cpp_concepts
421  template<typed_matrix M, covariance_nestable C>
422 #else
423  template<typename M, typename C, std::enable_if_t<typed_matrix<M> and covariance_nestable<C>, int> = 0>
424 #endif
426  vector_space_descriptor_of_t<M, 0>,
427  nested_object_of_t<passable_t<M>>,
428  passable_t<C>>;
429 
430 
431 #ifdef __cpp_concepts
432  template<typed_matrix_nestable M, self_adjoint_covariance C>
433 #else
434  template<typename M, typename C, std::enable_if_t<typed_matrix_nestable<M> and self_adjoint_covariance<C>, int> = 0>
435 #endif
438  passable_t<M>,
440 
441 
442 #ifdef __cpp_concepts
443  template<typed_matrix_nestable M, triangular_covariance C>
444 #else
445  template<typename M, typename C, std::enable_if_t<
446  typed_matrix_nestable<M> and triangular_covariance<C>, int> = 0>
447 #endif
449  vector_space_descriptor_of_t<C, 0>,
450  passable_t<M>,
452 
453 
454 #ifdef __cpp_concepts
455  template<typed_matrix_nestable M, typed_matrix C> requires
456  coordinates::compares_with<vector_space_descriptor_of_t<C, 0>, vector_space_descriptor_of_t<C, 1>>
457 #else
458  template<typename M, typename C, std::enable_if_t<typed_matrix_nestable<M> and typed_matrix<C> and
459  compares_with<vector_space_descriptor_of_t<C, 0>, vector_space_descriptor_of_t<C, 1>>, int> = 0>
460 #endif
463  passable_t<M>,
464  decltype(to_covariance_nestable(nested_object(std::declval<passable_t<C>>())))>;
465 
466 
467 #ifdef __cpp_concepts
468  template<typed_matrix_nestable M, covariance_nestable C>
469 #else
470  template<typename M, typename C,
471  std::enable_if_t<typed_matrix_nestable<M> and covariance_nestable<C>, int> = 0>
472 #endif
474  Dimensions<index_dimension_of_v<M, 0>>,
475  passable_t<M>,
476  passable_t<C>>;
477 
478 
479  // ----------------------------- //
480  // Make functions //
481  // ----------------------------- //
482 
488 #ifdef __cpp_concepts
489  template<gaussian_distribution D>
490 #else
491  template<typename D, std::enable_if_t<gaussian_distribution<D>, int> = 0>
492 #endif
493  inline auto
495  {
496  return GaussianDistribution {std::forward<D>(dist)};
497  }
498 
499 
507 #ifdef __cpp_concepts
508  template<std::uniform_random_bit_generator re = std::mt19937, typed_matrix M, typename Cov> requires
509  vector<M> and has_untyped_index<M, 1> and square_shaped<Cov> and (covariance<Cov> or typed_matrix<Cov>) and
510  (compares_with<vector_space_descriptor_of_t<M, 0>, vector_space_descriptor_of_t<Cov, 0>>)
511 #else
512  template<typename re = std::mt19937, typename M, typename Cov, std::enable_if_t<(not fixed_pattern<re>) and
513  typed_matrix<M> and vector<M> and has_untyped_index<M, 1> and
514  square_shaped<Cov> and (covariance<Cov> or typed_matrix<Cov>) and
515  (compares_with<vector_space_descriptor_of_t<M, 0>, vector_space_descriptor_of_t<Cov, 0>>), int> = 0>
516 #endif
517  inline auto
519  {
520  using C = vector_space_descriptor_of_t<M, 0>;
521  using Mb = passable_t<nested_object_of_t<M>>;
522  using Covb = passable_t<nested_object_of_t<Cov>>;
523  return GaussianDistribution<C, Mb, Covb, re>(std::forward<M>(mean), std::forward<Cov>(cov));
524  }
525 
526 
534 #ifdef __cpp_concepts
535  template<std::uniform_random_bit_generator re = std::mt19937, typed_matrix M, typename Cov> requires
536  vector<M> and has_untyped_index<M, 1> and
537  square_shaped<Cov> and (covariance_nestable<Cov> or typed_matrix_nestable<Cov>) and
538  (index_dimension_of_v<M, 0> == index_dimension_of_v<Cov, 0>)
539 #else
540  template<typename re = std::mt19937, typename M, typename Cov, std::enable_if_t<
541  (not fixed_pattern<re>) and typed_matrix<M> and vector<M> and has_untyped_index<M, 1> and
542  square_shaped<Cov> and (covariance_nestable<Cov> or typed_matrix_nestable<Cov>) and
544 #endif
545  inline auto
547  {
548  using C = vector_space_descriptor_of_t<M, 0>;
549  using Mb = passable_t<nested_object_of_t<M>>;
550  auto c = nested_object(make_covariance<C>(std::forward<Cov>(cov)));
551  return GaussianDistribution<C, Mb, equivalent_self_contained_t<decltype(c)>, re>(std::forward<M>(mean), std::move(c));
552  }
553 
554 
562 #ifdef __cpp_concepts
563  template<std::uniform_random_bit_generator re = std::mt19937, typed_matrix_nestable M, typename Cov> requires
564  vector<M> and square_shaped<Cov> and
565  (covariance<Cov> or typed_matrix<Cov> or covariance_nestable<Cov> or typed_matrix_nestable<Cov>) and
566  (index_dimension_of_v<M, 0> == index_dimension_of_v<Cov, 0>)
567 #else
568  template<typename re = std::mt19937, typename M, typename Cov, std::enable_if_t<
569  (not fixed_pattern<re>) and typed_matrix_nestable<M> and vector<M> and square_shaped<Cov> and
570  (covariance<Cov> or typed_matrix<Cov> or covariance_nestable<Cov> or typed_matrix_nestable<Cov>) and
572 #endif
573  inline auto
574  make_GaussianDistribution(M&& mean, Cov&& cov)
575  {
576  if constexpr(covariance<Cov>)
577  {
579  using Covb = passable_t<nested_object_of_t<Cov>>;
580  return GaussianDistribution<C, passable_t<M>, Covb, re>(std::forward<M>(mean), std::forward<Cov>(cov));
581  }
582  else if constexpr(typed_matrix<Cov>)
583  {
585  auto sc = nested_object(make_covariance(std::forward<Cov>(cov)));
586  using SC = equivalent_self_contained_t<decltype(sc)>;
587  return GaussianDistribution<C, passable_t<M>, SC, re>(std::forward<M>(mean), std::move(sc));
588  }
589  else
590  {
591  static_assert(covariance_nestable<Cov> or typed_matrix_nestable<Cov>);
592  using C = Dimensions<index_dimension_of_v<M, 0>>;
593  auto c = nested_object(make_covariance<C>(std::forward<Cov>(cov)));
594  return GaussianDistribution<C, passable_t<M>, equivalent_self_contained_t<decltype(c)>, re>(
595  std::forward<M>(mean), std::move(c));
596  }
597  }
598 
599 
608 #ifdef __cpp_concepts
609  template<fixed_pattern StaticDescriptor, std::uniform_random_bit_generator re = std::mt19937,
610  typed_matrix_nestable M, typename Cov> requires vector<M> and (covariance_nestable<Cov> or typed_matrix_nestable<Cov>)
611 #else
612  template<typename StaticDescriptor, typename re = std::mt19937, typename M, typename Cov, std::enable_if_t<
613  fixed_pattern<StaticDescriptor> and typed_matrix_nestable<M> and vector<M> and
614  (covariance_nestable<Cov> or typed_matrix_nestable<Cov>), int> = 0>
615 #endif
616  inline auto
618  {
619  static_assert(index_dimension_of_v<M, 0> == index_dimension_of_v<Cov, 0>);
620  if constexpr(covariance_nestable<Cov>)
621  {
622  return GaussianDistribution<StaticDescriptor, passable_t<M>, passable_t<Cov>, re>(
623  std::forward<M>(mean), std::forward<Cov>(cov));
624  }
625  else
626  {
627  static_assert(typed_matrix_nestable<Cov>);
628  auto c = nested_object(make_covariance<StaticDescriptor>(std::forward<Cov>(cov)));
629  return GaussianDistribution<StaticDescriptor, passable_t<M>, equivalent_self_contained_t<decltype(c)>, re>(
630  std::forward<M>(mean), std::move(c));
631  }
632  }
633 
634 
642 #ifdef __cpp_concepts
643  template<typed_matrix M, covariance Cov, std::uniform_random_bit_generator re = std::mt19937> requires
644  vector<M> and has_untyped_index<M, 1> and
645  coordinates::compares_with<vector_space_descriptor_of_t<M, 0>, vector_space_descriptor_of_t<Cov, 0>>
646 #else
647  template<typename M, typename Cov, typename re = std::mt19937, std::enable_if_t<
648  typed_matrix<M> and vector<M> and has_untyped_index<M, 1> and covariance<Cov> and
649  compares_with<vector_space_descriptor_of_t<M, 0>, vector_space_descriptor_of_t<Cov, 0>>, int> = 0>
650 #endif
651  inline auto
653  {
654  using C = vector_space_descriptor_of_t<M, 0>;
655  return GaussianDistribution<C, passable_t<nested_object_of_t<M>>, passable_t<nested_object_of_t<Cov>>, re>();
656  }
657 
658 
667 #ifdef __cpp_concepts
668  template<vector M, typename Cov, std::uniform_random_bit_generator re = std::mt19937> requires
669  (typed_matrix<M> or typed_matrix_nestable<M>) and has_untyped_index<M, 1> and
670  (covariance<Cov> or covariance_nestable<Cov>) and (not typed_matrix<M> or not covariance<Cov>) and
671  (index_dimension_of_v<M, 0> == index_dimension_of_v<Cov, 0>)
672 #else
673  template<typename M, typename Cov, typename re = std::mt19937, std::enable_if_t<
674  vector<M> and (typed_matrix<M> or typed_matrix_nestable<M>) and has_untyped_index<M, 1> and
675  (covariance<Cov> or covariance_nestable<Cov>) and (not typed_matrix<M> or not covariance<Cov>) and
677 #endif
678  inline auto
680  {
681  if constexpr(typed_matrix<M>)
682  {
683  using C = vector_space_descriptor_of_t<M, 0>;
684  return GaussianDistribution<C, passable_t<nested_object_of_t<M>>, passable_t<Cov>, re>();
685  }
686  else if constexpr(covariance<Cov>)
687  {
688  using C = vector_space_descriptor_of_t<Cov, 0>;
689  return GaussianDistribution<C, passable_t<M>, passable_t<nested_object_of_t<Cov>>, re>();
690  }
691  else
692  {
693  using C = Dimensions<index_dimension_of_v<M, 0>>;
694  return GaussianDistribution<C, passable_t<M>, passable_t<Cov>, re>();
695  }
696  }
697 
698 
707 #ifdef __cpp_concepts
708  template<fixed_pattern StaticDescriptor, typed_matrix_nestable M, covariance_nestable Cov,
709  std::uniform_random_bit_generator re = std::mt19937> requires
710  vector<M> and (index_dimension_of_v<M, 0> == index_dimension_of_v<Cov, 0>)
711 #else
712  template<typename StaticDescriptor, typename M, typename Cov, typename re = std::mt19937, std::enable_if_t<
713  typed_matrix_nestable<M> and vector<M> and covariance_nestable<Cov> and
715 #endif
716  inline auto
718  {
719  return GaussianDistribution<StaticDescriptor, passable_t<M>, passable_t<Cov>, re>();
720  }
721 
722 
723  // --------------------- //
724  // Traits //
725  // --------------------- //
726 
727  namespace interface
728  {
729  template<typename Coeffs, typename NestedMean, typename NestedCovariance, typename re>
730  struct indexible_object_traits<GaussianDistribution<Coeffs, NestedMean, NestedCovariance, re>>
731  {
732  using scalar_type = scalar_type_of_t<NestedMean>;
733 
734  template<typename Arg>
735  static constexpr auto count_indices(const Arg& arg) { return std::integral_constant<std::size_t, 1>{}; }
736 
737  template<typename Arg, typename N>
738  static constexpr auto get_vector_space_descriptor(const Arg& arg, N n)
739  {
740  if constexpr (values::fixed<N>)
741  {
742  static_assert(n == 0_uz);
743  if constexpr (not dynamic_dimension<NestedMean, 0>) return OpenKalman::get_vector_space_descriptor<0>(mean_of(arg));
744  else return OpenKalman::get_vector_space_descriptor<0>(covariance_of(arg));
745  }
746  else
747  {
748  return OpenKalman::get_vector_space_descriptor(mean_of(arg), n);
749  }
750  }
751 
752 
753  template<typename Arg>
754  static decltype(auto) nested_object(Arg&& arg)
755  {
756  return std::forward<Arg>(arg).mu;
757  }
758 
759 
760 #ifdef __cpp_lib_concepts
761  template<typename Arg> requires raw_data_defined_for<Mean<Coeffs, NestedMean>>
762 #else
763  template<typename Arg, std::enable_if_t<raw_data_defined_for<Mean<Coeffs, NestedMean>>, int> = 0>
764 #endif
765  static constexpr auto *
766  raw_data(Arg& arg) { return internal::raw_data(arg.mu()); }
767 
768 
769  static constexpr Layout layout = layout_of_v<NestedMean>;
770 
771  };
772 
773  } // namespace interface
774 
775 
776  template<typename Coeffs, typename NestedMean, typename NestedCovariance, typename re>
777  struct DistributionTraits<GaussianDistribution<Coeffs, NestedMean, NestedCovariance, re>>
778  {
779  using StaticDescriptor = Coeffs;
780  using Mean = Mean<StaticDescriptor, NestedMean>;
781  using Covariance = Covariance<StaticDescriptor, NestedCovariance>;
782  using Scalar = scalar_type_of_t<Mean>;
783  template<typename S> using distribution_type = std::normal_distribution<S>;
784  using random_number_engine = re;
785 
786 #ifdef __cpp_concepts
787  template<fixed_pattern C = StaticDescriptor, typed_matrix_nestable M, covariance_nestable Cov> requires
788  vector<M> and (index_dimension_of_v<M, 0> == index_dimension_of_v<Cov, 0>)
789 #else
790  template<typename C = StaticDescriptor, typename M, typename Cov,
791  std::enable_if_t<fixed_pattern<C> and typed_matrix_nestable<M> and covariance_nestable<Cov> and
793 #endif
794  static auto make(M&& mean, Cov&& covariance)
795  {
796  return make_GaussianDistribution<C, random_number_engine>(std::forward<M>(mean), std::forward<Cov>(covariance));
797  }
798 
799  };
800 
801 
802  // ------------------------ //
803  // Overloads //
804  // ------------------------ //
805 
806  #ifdef __cpp_concepts
807  template<gaussian_distribution Arg>
808 #else
809  template<typename Arg, std::enable_if_t<gaussian_distribution<Arg>, int> = 0>
810 #endif
811  constexpr decltype(auto)
812  mean_of(Arg&& arg)
813  {
814  return (std::forward<Arg>(arg).mu);
815  }
816 
817 
818 #ifdef __cpp_concepts
819  template<gaussian_distribution Arg>
820 #else
821  template<typename Arg, std::enable_if_t<gaussian_distribution<Arg>, int> = 0>
822 #endif
823  constexpr decltype(auto)
824  covariance_of(Arg&& arg)
825  {
826  return (std::forward<Arg>(arg).sigma);
827  }
828 
829 
830 #ifdef __cpp_concepts
831  template<gaussian_distribution T, std::size_t dimension = index_dimension_of_v<T, 0>,
832  typename Scalar = scalar_type_of_t<T>, std::convertible_to<std::size_t>...runtime_dimensions> requires
833  (sizeof...(runtime_dimensions) == (dimension == dynamic_size ? 1 : 0))
834 #else
836  typename Scalar = typename scalar_type_of<T>::type, typename...runtime_dimensions, std::enable_if_t<
837  gaussian_distribution<T> and (sizeof...(runtime_dimensions) == (dimension == dynamic_size ? 1 : 0)) and
838  (std::is_convertible_v<runtime_dimensions, std::size_t> and ...), int> = 0>
839 #endif
840  constexpr auto
841  make_zero_distribution_like(runtime_dimensions...e)
842  {
843  using Coeffs = typename DistributionTraits<T>::StaticDescriptor;
844  using re = DistributionTraits<T>::random_number_engine;
845  auto m = make_zero<DistributionTraits<T>::Mean, Scalar>(Dimensions<dimension>{e...}, Dimension<1>{});
846  auto c = make_zero<DistributionTraits<T>::Covariance, Scalar>(Dimensions<dimension>{e...}, Dimensions<dimension>{e...});
847  return make_gaussian_distribution<re>>(std::move(m), std::move(c));
848  }
849 
850 
851 #ifdef __cpp_concepts
852  template<gaussian_distribution T, std::size_t dimension = index_dimension_of_v<T, 0>,
853  typename Scalar = scalar_type_of_t<T>, std::convertible_to<std::size_t>...runtime_dimensions> requires
854  (sizeof...(runtime_dimensions) == (dimension == dynamic_size ? 1 : 0))
855 #else
856  template<typename T, std::size_t dimension = index_dimension_of<T, 0>::value,
857  typename Scalar = typename scalar_type_of<T>::type, typename...runtime_dimensions, std::enable_if_t<
858  gaussian_distribution<T> and (sizeof...(runtime_dimensions) == (dimension == dynamic_size ? 1 : 0)) and
859  (std::is_convertible_v<runtime_dimensions, std::size_t> and ...), int> = 0>
860 #endif
861  constexpr auto
862  make_normal_distribution_like(runtime_dimensions...e)
863  {
864  using Coeffs = typename DistributionTraits<T>::StaticDescriptor;
865  using re = DistributionTraits<T>::random_number_engine;
866  auto m = make_zero<DistributionTraits<T>::Mean, Scalar>(Dimensions<dimension>{e...}, Dimension<1>{});
867  auto c = make_identity_matrix_like<DistributionTraits<T>::Covariance, Scalar>(Dimensions<dimension>{e...});
868  return make_gaussian_distribution<re>>(std::move(m), std::move(c));
869  }
870 
871 
872 #ifdef __cpp_concepts
873  template<gaussian_distribution D, gaussian_distribution ... Ds>
874 #else
875  template<typename D, typename ... Ds,
876  std::enable_if_t<(gaussian_distribution<D> and ... and gaussian_distribution<Ds>), int> = 0>
877 #endif
878  auto
879  concatenate(D&& d, Ds&& ... ds)
880  {
881  if constexpr(sizeof...(Ds) > 0)
882  {
883  using re = typename DistributionTraits<D>::random_number_engine;
884  auto m = concatenate(mean_of(std::forward<D>(d)), mean_of(std::forward<Ds>(ds))...);
885  auto cov = concatenate(covariance_of(std::forward<D>(d)), covariance_of(std::forward<Ds>(ds))...);
886  return make_GaussianDistribution<re>(std::move(m), std::move(cov));
887  }
888  else
889  {
890  return d;
891  }
892  }
893 
894 
895  namespace detail
896  {
897  template<typename Dist, typename Means, typename Covariances, std::size_t ... ints>
898  inline auto zip_dist(Means&& ms, Covariances&& cs, std::index_sequence<ints...>)
899  {
900  using re = typename DistributionTraits<Dist>::random_number_engine;
901  return std::tuple {make_GaussianDistribution<re>(
902  std::get<ints>(std::forward<Means>(ms)),
903  std::get<ints>(std::forward<Covariances>(cs)))...};
904  };
905  }
906 
907 
909 #ifdef __cpp_concepts
910  template<fixed_pattern ... Cs, gaussian_distribution D> requires
911  coordinates::compares_with<static_concatenate_t<Cs...>, typename DistributionTraits<D>::StaticDescriptor, less_equal<>>
912 #else
913  template<typename ... Cs, typename D, std::enable_if_t<
914  (fixed_pattern<Cs> and ...) and gaussian_distribution<D> and
915  coordinates::compares_with<static_concatenate_t<Cs...>, typename DistributionTraits<D>::StaticDescriptor, less_equal<>>, int> = 0>
916 #endif
917  inline auto
918  split(D&& d)
919  {
920  using Coeffs = typename DistributionTraits<D>::StaticDescriptor;
921  if constexpr(sizeof...(Cs) == 1 and compares_with<static_concatenate_t<Cs...>, Coeffs>)
922  {
923  return std::tuple(std::forward<D>(d));
924  }
925  else
926  {
927  auto means = split_vertical<Cs...>(mean_of(d));
928  auto covariances = split_diagonal<Cs...>(covariance_of(std::forward<D>(d)));
929  return OpenKalman::detail::zip_dist<D>(means, covariances, std::index_sequence_for<Cs...> {});
930  }
931  }
932 
933 
934 #ifdef __cpp_concepts
935  template<gaussian_distribution Dist>
936 #else
937  template<typename Dist, std::enable_if_t<gaussian_distribution<Dist>, int> = 0>
938 #endif
939  inline std::ostream&
940  operator<<(std::ostream& os, const Dist& d)
941  {
942  os << "mean:" << std::endl << mean_of(d) << std::endl <<
943  "covariance:" << std::endl << covariance_of(d) << std::endl;
944  return os;
945  }
946 
947 
948  // ---------------------- //
949  // Arithmetic Operators //
950  // ---------------------- //
951 
952 #ifdef __cpp_concepts
953  template<gaussian_distribution Dist1, gaussian_distribution Dist2> requires
954  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor, typename DistributionTraits<Dist2>::StaticDescriptor>
955 #else
956  template<typename Dist1, typename Dist2, std::enable_if_t<
957  gaussian_distribution<Dist1> and gaussian_distribution<Dist2> and
958  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor,
959  typename DistributionTraits<Dist2>::StaticDescriptor>, int> = 0>
960 #endif
961  inline auto
962  operator+(Dist1&& d1, Dist2&& d2)
963  {
964  using re = typename DistributionTraits<Dist1>::random_number_engine;
965  auto m1 = mean_of(std::forward<Dist1>(d1)) + mean_of(std::forward<Dist2>(d2));
966  auto m2 = covariance_of(std::forward<Dist1>(d1)) + covariance_of(std::forward<Dist2>(d2));
967  return make_GaussianDistribution<re>(std::move(m1), std::move(m2));
968  };
969 
970 
971 #ifdef __cpp_concepts
972  template<gaussian_distribution Dist1, gaussian_distribution Dist2> requires
973  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor, typename DistributionTraits<Dist2>::StaticDescriptor>
974 #else
975  template<typename Dist1, typename Dist2, std::enable_if_t<
976  gaussian_distribution<Dist1> and gaussian_distribution<Dist2> and
977  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor,
978  typename DistributionTraits<Dist2>::StaticDescriptor>, int> = 0>
979 #endif
980  inline auto
981  operator-(Dist1&& d1, Dist2&& d2)
982  {
983  using re = typename DistributionTraits<Dist1>::random_number_engine;
984  auto m1 = mean_of(std::forward<Dist1>(d1)) - mean_of(std::forward<Dist2>(d2));
985  auto m2 = covariance_of(std::forward<Dist1>(d1)) - covariance_of(std::forward<Dist2>(d2));
986  return make_GaussianDistribution<re>(std::move(m1), std::move(m2));
987  };
988 
989 
990 #ifdef __cpp_concepts
991  template<typed_matrix A, gaussian_distribution D> requires gaussian_distribution<D> and
992  (not euclidean_transformed<A>) and
993  (compares_with<vector_space_descriptor_of_t<A, 1>, typename DistributionTraits<D>::StaticDescriptor>)
994 #else
995  template<typename A, typename D, std::enable_if_t<typed_matrix<A> and gaussian_distribution<D> and
996  (not euclidean_transformed<A>) and
997  (compares_with<vector_space_descriptor_of_t<A, 1>, typename DistributionTraits<D>::StaticDescriptor>), int> = 0>
998 #endif
999  inline auto
1000  operator*(A&& a, D&& d)
1001  {
1002  using re = typename DistributionTraits<D>::random_number_engine;
1003  auto m = a * mean_of(std::forward<D>(d));
1004  auto c = scale(covariance_of(std::forward<D>(d)), std::forward<A>(a));
1005  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1006  }
1007 
1008 
1009 #ifdef __cpp_concepts
1010  template<gaussian_distribution Dist, std::convertible_to<const typename DistributionTraits<Dist>::Scalar> S>
1011 #else
1012  template<typename Dist, typename S, std::enable_if_t<
1013  gaussian_distribution<Dist> and std::is_convertible_v<S, const typename DistributionTraits<Dist>::Scalar>, int> = 0>
1014 #endif
1015  inline auto
1016  operator*(Dist&& d, S s)
1017  {
1018  using re = typename DistributionTraits<Dist>::random_number_engine;
1019  auto m = mean_of(std::forward<Dist>(d)) * s;
1020  auto c = scale(covariance_of(std::forward<Dist>(d)), s);
1021  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1022  };
1023 
1024 
1025 #ifdef __cpp_concepts
1026  template<gaussian_distribution Dist, std::convertible_to<const typename DistributionTraits<Dist>::Scalar> S>
1027 #else
1028  template<typename Dist, typename S, std::enable_if_t<
1029  gaussian_distribution<Dist> and std::is_convertible_v<S, const typename DistributionTraits<Dist>::Scalar>, int> = 0>
1030 #endif
1031  inline auto
1032  operator*(S s, Dist&& d)
1033  {
1034  using re = typename DistributionTraits<Dist>::random_number_engine;
1035  auto m = s * mean_of(std::forward<Dist>(d));
1036  auto c = scale(covariance_of(std::forward<Dist>(d)), s);
1037  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1038  };
1039 
1040 
1041 #ifdef __cpp_concepts
1042  template<gaussian_distribution Dist, std::convertible_to<const typename DistributionTraits<Dist>::Scalar> S>
1043 #else
1044  template<typename Dist, typename S, std::enable_if_t<
1045  gaussian_distribution<Dist> and std::is_convertible_v<S, const typename DistributionTraits<Dist>::Scalar>, int> = 0>
1046 #endif
1047  inline auto
1048  operator/(Dist&& d, S s)
1049  {
1050  using re = typename DistributionTraits<Dist>::random_number_engine;
1051  auto m = mean_of(std::forward<Dist>(d)) / s;
1052  auto c = inverse_scale(covariance_of(std::forward<Dist>(d)), s);
1053  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1054  };
1055 
1056 }
1057 
1058 #endif //OPENKALMAN_GAUSSIANDISTRIBUTION_HPP
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
constexpr auto log(const Arg &arg)
Constexpr alternative to the std::log function.
Definition: log.hpp:47
decltype(auto) constexpr contract(A &&a, B &&b)
Matrix multiplication of A * B.
Definition: contract.hpp:54
Definition: indexible_object_traits.hpp:36
GaussianDistribution(Mean &&mean, Cov &&cov)
Construct from an rvalue of a mean and a covariance, typed_matrix, or covariance_nestable.
Definition: GaussianDistribution.hpp:146
typename scalar_type_of< T >::type scalar_type_of_t
helper template for scalar_type_of.
Definition: scalar_type_of.hpp:54
auto make_GaussianDistribution(D &&dist)
Make a Gaussian distribution.
Definition: GaussianDistribution.hpp:494
Definition: tuple_reverse.hpp:103
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
An upper-right triangular matrix.
Covariance(const Args &...) -> Covariance< Dimensions< static_cast< std::size_t >(values::sqrt(sizeof...(Args)))>, HermitianAdapter< Eigen3::eigen_matrix_t< std::common_type_t< Args... >, static_cast< std::size_t >(values::sqrt(sizeof...(Args))), static_cast< std::size_t >(values::sqrt(sizeof...(Args)))>>>
If the arguments are a sequence of scalars, derive a square, self-adjoint matrix. ...
Type scalar type (e.g., std::float, std::double, std::complex<double>) of a tensor.
Definition: scalar_type_of.hpp:32
constexpr bool triangular_matrix
Specifies that a type is a triangular matrix (upper, lower, or diagonal).
Definition: triangular_matrix.hpp:37
decltype(auto) constexpr transpose(Arg &&arg)
Take the transpose of a matrix.
Definition: transpose.hpp:58
Covariance sigma
The Covariance matrix of the distribution.
Definition: GaussianDistribution.hpp:374
A Gaussian distribution, defined in terms of a Mean and a Covariance.
Definition: GaussianDistribution.hpp:42
constexpr bool typed_matrix_nestable
Specifies a type that is nestable in a general typed matrix (e.g., matrix, mean, or euclidean_mean) ...
Definition: object-types.hpp:253
constexpr bool typed_matrix
Specifies that T is a typed matrix (i.e., is a specialization of Matrix, Mean, or EuclideanMean)...
Definition: object-types.hpp:110
The root namespace for OpenKalman.
Definition: basics.hpp:34
auto split_diagonal(M &&m)
Split Covariance or SquareRootCovariance diagonally.
Definition: covariance-overloads.hpp:326
constexpr auto solve(A &&a, B &&b)
Solve the equation AX = B for X, which may or may not be a unique solution.
Definition: solve.hpp:87
constexpr auto determinant(Arg &&arg)
Take the determinant of a matrix.
Definition: determinant.hpp:44
Scalar entropy() const
Entropy of the distribution, in bits.
Definition: GaussianDistribution.hpp:358
GaussianDistribution(M &&mean, Cov &&cov)
Construct from matrices representing a mean and a covariance.
Definition: GaussianDistribution.hpp:170
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
constexpr bool covariance
T is a specialization of either Covariance or SquareRootCovariance.
Definition: object-types.hpp:161
Layout
The layout format of a multidimensional array.
Definition: global-definitions.hpp:47
GaussianDistribution(Arg &&arg)
Construct from related distribution.
Definition: GaussianDistribution.hpp:100
decltype(auto) constexpr sum(Ts &&...ts)
Element-by-element sum of one or more objects.
Definition: sum.hpp:112
Mean mu
The mean of the distribution.
Definition: GaussianDistribution.hpp:368
A generalization of std::less_equal in which the arguments may be of different types.
Definition: less_equal.hpp:29
GaussianDistribution(Mean &&mean, Covariance &&cov)
Construct from an rvalue of a mean and a covariance.
Definition: GaussianDistribution.hpp:107
auto make_covariance(Arg &&arg)
Make a Covariance from a covariance_nestable, specifying the fixed_pattern.
Definition: Covariance.hpp:735
constexpr bool gaussian_distribution
T is a Gaussian distribution.
Definition: object-types.hpp:182
The dimension of an index for a matrix, expression, or array.
Definition: index_dimension_of.hpp:34
Mean(V &&) -> Mean< Dimensions< index_dimension_of_v< V, 0 >>, passable_t< V >>
Deduce template parameters from a typed_matrix_nestable, assuming untyped coordinates::pattern.
GaussianDistribution & operator=(Arg &&arg)
Assign from another compatible distribution.
Definition: GaussianDistribution.hpp:262
constexpr bool fixed_pattern
A coordinates::pattern for which the size is fixed at compile time.
Definition: fixed_pattern.hpp:47
auto operator()() const
Generate a random value from the distribution.
Definition: GaussianDistribution.hpp:325
constexpr std::size_t dynamic_size
A constant indicating that a size or index is dynamic.
Definition: global-definitions.hpp:33
constexpr bool mean
Specifies that T is a mean (i.e., is a specialization of the class Mean).
Definition: object-types.hpp:40
constexpr bool covariance_nestable
T is an acceptable nested matrix for a covariance (including triangular_covariance).
Definition: object-types.hpp:237
auto split_vertical(M &&m)
Split Covariance or SquareRootCovariance vertically. Result is a tuple of typed matrices.
Definition: covariance-overloads.hpp:340
auto inverse_scale(M &&m, const S s)
Scale a covariance by the inverse of a scalar factor.
Definition: covariance-arithmetic.hpp:543
auto scale(M &&m, const S s)
Scale a covariance by a factor.
Definition: covariance-arithmetic.hpp:518
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:34
auto split(D &&d)
Split distribution.
Definition: GaussianDistribution.hpp:918
GaussianDistribution(Cov &&cov)
Construct with only a covariance or square typed_matrix (mean is set to zero).
Definition: GaussianDistribution.hpp:234
GaussianDistribution(M &&mean, Covariance &&cov)
Construct from a typed_matrix and an rvalue of a covariance.
Definition: GaussianDistribution.hpp:120
Scalar log_likelihood(const Z &...z) const
Log-likelihood function for a set of i.i.d.
Definition: GaussianDistribution.hpp:348
decltype(auto) constexpr trace(Arg &&arg)
Take the trace of a matrix.
Definition: trace.hpp:35
A matrix with typed rows and columns.
Definition: forward-class-declarations.hpp:448
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