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>,
51  scalar_type_of_t<CovarianceNestedMatrix>>);
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<bool Enable = true, std::enable_if_t<Enable and
83  stdex::default_initializable<Mean> and stdex::default_initializable<Covariance>, 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_pattern_collection<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_pattern_collection<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<stdex::convertible_to<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<stdex::convertible_to<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), triangle_type::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 * stdex::numbers::pi_v<long double>) +
354  }
355 
356 
358  Scalar entropy() const
359  {
360  return 0.5 * (dim * (1 + values::log2(stdex::numbers::pi_v<long double>) +
361  Scalar {stdex::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
389  vector_space_descriptor_of_t<M, 0>,
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
415  vector_space_descriptor_of_t<M, 0>,
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
437  vector_space_descriptor_of_t<C, 0>,
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
462  vector_space_descriptor_of_t<C, 0>,
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  {
578  using C = vector_space_descriptor_of_t<Cov, 0>;
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  {
584  using C = vector_space_descriptor_of_t<Cov, 0>;
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 object_traits<GaussianDistribution<Coeffs, NestedMean, NestedCovariance, re>>
731  {
732  static const bool is_specialized = true;
733 
734  using scalar_type = scalar_type_of_t<NestedMean>;
735 
736  template<typename Arg>
737  static constexpr auto count_indices(const Arg& arg) { return std::integral_constant<std::size_t, 1>{}; }
738 
739  template<typename Arg, typename N>
740  static constexpr auto get_pattern_collection(const Arg& arg, N n)
741  {
742  if constexpr (values::fixed<N>)
743  {
744  static_assert(n == 0_uz);
745  if constexpr (not dynamic_dimension<NestedMean, 0>) return OpenKalman::get_pattern_collection<0>(mean_of(arg));
746  else return OpenKalman::get_pattern_collection<0>(covariance_of(arg));
747  }
748  else
749  {
750  return OpenKalman::get_pattern_collection(mean_of(arg), n);
751  }
752  }
753 
754 
755  template<typename Arg>
756  static decltype(auto) nested_object(Arg&& arg)
757  {
758  return std::forward<Arg>(arg).mu;
759  }
760 
761 
762 #ifdef __cpp_lib_concepts
763  template<typename Arg> requires raw_data_defined_for<Mean<Coeffs, NestedMean>>
764 #else
765  template<typename Arg, std::enable_if_t<raw_data_defined_for<Mean<Coeffs, NestedMean>>, int> = 0>
766 #endif
767  static constexpr auto *
768  raw_data(Arg& arg) { return internal::raw_data(arg.mu()); }
769 
770 
771  static constexpr data_layout layout = layout_of_v<NestedMean>;
772 
773  };
774 
775  }
776 
777 
778  template<typename Coeffs, typename NestedMean, typename NestedCovariance, typename re>
779  struct DistributionTraits<GaussianDistribution<Coeffs, NestedMean, NestedCovariance, re>>
780  {
781  using StaticDescriptor = Coeffs;
782  using Mean = Mean<StaticDescriptor, NestedMean>;
783  using Covariance = Covariance<StaticDescriptor, NestedCovariance>;
784  using Scalar = scalar_type_of_t<Mean>;
785  template<typename S> using distribution_type = std::normal_distribution<S>;
786  using random_number_engine = re;
787 
788 #ifdef __cpp_concepts
789  template<fixed_pattern C = StaticDescriptor, typed_matrix_nestable M, covariance_nestable Cov> requires
790  vector<M> and (index_dimension_of_v<M, 0> == index_dimension_of_v<Cov, 0>)
791 #else
792  template<typename C = StaticDescriptor, typename M, typename Cov,
793  std::enable_if_t<fixed_pattern<C> and typed_matrix_nestable<M> and covariance_nestable<Cov> and
795 #endif
796  static auto make(M&& mean, Cov&& covariance)
797  {
798  return make_GaussianDistribution<C, random_number_engine>(std::forward<M>(mean), std::forward<Cov>(covariance));
799  }
800 
801  };
802 
803 
804  // ------------------------ //
805  // Overloads //
806  // ------------------------ //
807 
808  #ifdef __cpp_concepts
809  template<gaussian_distribution Arg>
810 #else
811  template<typename Arg, std::enable_if_t<gaussian_distribution<Arg>, int> = 0>
812 #endif
813  constexpr decltype(auto)
814  mean_of(Arg&& arg)
815  {
816  return (std::forward<Arg>(arg).mu);
817  }
818 
819 
820 #ifdef __cpp_concepts
821  template<gaussian_distribution Arg>
822 #else
823  template<typename Arg, std::enable_if_t<gaussian_distribution<Arg>, int> = 0>
824 #endif
825  constexpr decltype(auto)
826  covariance_of(Arg&& arg)
827  {
828  return (std::forward<Arg>(arg).sigma);
829  }
830 
831 
832 #ifdef __cpp_concepts
833  template<gaussian_distribution T, std::size_t dimension = index_dimension_of_v<T, 0>,
834  typename Scalar = scalar_type_of_t<T>, std::convertible_to<std::size_t>...runtime_dimensions> requires
835  (sizeof...(runtime_dimensions) == (dimension == stdex::dynamic_extent ? 1 : 0))
836 #else
838  typename Scalar = typename scalar_type_of<T>::type, typename...runtime_dimensions, std::enable_if_t<
839  gaussian_distribution<T> and (sizeof...(runtime_dimensions) == (dimension == stdex::dynamic_extent ? 1 : 0)) and
840  (stdex::convertible_to<runtime_dimensions, std::size_t> and ...), int> = 0>
841 #endif
842  constexpr auto
843  make_zero_distribution_like(runtime_dimensions...e)
844  {
845  using Coeffs = typename DistributionTraits<T>::StaticDescriptor;
846  using re = DistributionTraits<T>::random_number_engine;
847  auto m = make_zero<DistributionTraits<T>::Mean, Scalar>(Dimensions<dimension>{e...}, Dimension<1>{});
848  auto c = make_zero<DistributionTraits<T>::Covariance, Scalar>(Dimensions<dimension>{e...}, Dimensions<dimension>{e...});
849  return make_gaussian_distribution<re>>(std::move(m), std::move(c));
850  }
851 
852 
853 #ifdef __cpp_concepts
854  template<gaussian_distribution T, std::size_t dimension = index_dimension_of_v<T, 0>,
855  typename Scalar = scalar_type_of_t<T>, std::convertible_to<std::size_t>...runtime_dimensions> requires
856  (sizeof...(runtime_dimensions) == (dimension == stdex::dynamic_extent ? 1 : 0))
857 #else
858  template<typename T, std::size_t dimension = index_dimension_of<T, 0>::value,
859  typename Scalar = typename scalar_type_of<T>::type, typename...runtime_dimensions, std::enable_if_t<
860  gaussian_distribution<T> and (sizeof...(runtime_dimensions) == (dimension == stdex::dynamic_extent ? 1 : 0)) and
861  (stdex::convertible_to<runtime_dimensions, std::size_t> and ...), int> = 0>
862 #endif
863  constexpr auto
864  make_normal_distribution_like(runtime_dimensions...e)
865  {
866  using Coeffs = typename DistributionTraits<T>::StaticDescriptor;
867  using re = DistributionTraits<T>::random_number_engine;
868  auto m = make_zero<DistributionTraits<T>::Mean, Scalar>(Dimensions<dimension>{e...}, Dimension<1>{});
869  auto c = make_identity_matrix_like<DistributionTraits<T>::Covariance, Scalar>(Dimensions<dimension>{e...});
870  return make_gaussian_distribution<re>>(std::move(m), std::move(c));
871  }
872 
873 
874 #ifdef __cpp_concepts
875  template<gaussian_distribution D, gaussian_distribution ... Ds>
876 #else
877  template<typename D, typename ... Ds,
878  std::enable_if_t<(gaussian_distribution<D> and ... and gaussian_distribution<Ds>), int> = 0>
879 #endif
880  auto
881  concatenate(D&& d, Ds&& ... ds)
882  {
883  if constexpr(sizeof...(Ds) > 0)
884  {
885  using re = typename DistributionTraits<D>::random_number_engine;
886  auto m = concatenate(mean_of(std::forward<D>(d)), mean_of(std::forward<Ds>(ds))...);
887  auto cov = concatenate(covariance_of(std::forward<D>(d)), covariance_of(std::forward<Ds>(ds))...);
888  return make_GaussianDistribution<re>(std::move(m), std::move(cov));
889  }
890  else
891  {
892  return d;
893  }
894  }
895 
896 
897  namespace detail
898  {
899  template<typename Dist, typename Means, typename Covariances, std::size_t ... ints>
900  inline auto zip_dist(Means&& ms, Covariances&& cs, std::index_sequence<ints...>)
901  {
902  using re = typename DistributionTraits<Dist>::random_number_engine;
903  return std::tuple {make_GaussianDistribution<re>(
904  std::get<ints>(std::forward<Means>(ms)),
905  std::get<ints>(std::forward<Covariances>(cs)))...};
906  };
907  }
908 
909 
911 #ifdef __cpp_concepts
912  template<fixed_pattern ... Cs, gaussian_distribution D> requires
913  coordinates::compares_with<static_concatenate_t<Cs...>, typename DistributionTraits<D>::StaticDescriptor, less_equal<>>
914 #else
915  template<typename ... Cs, typename D, std::enable_if_t<
916  (fixed_pattern<Cs> and ...) and gaussian_distribution<D> and
917  coordinates::compares_with<static_concatenate_t<Cs...>, typename DistributionTraits<D>::StaticDescriptor, less_equal<>>, int> = 0>
918 #endif
919  inline auto
920  split(D&& d)
921  {
922  using Coeffs = typename DistributionTraits<D>::StaticDescriptor;
923  if constexpr(sizeof...(Cs) == 1 and compares_with<static_concatenate_t<Cs...>, Coeffs>)
924  {
925  return std::tuple(std::forward<D>(d));
926  }
927  else
928  {
929  auto means = split_vertical<Cs...>(mean_of(d));
930  auto covariances = split_diagonal<Cs...>(covariance_of(std::forward<D>(d)));
931  return OpenKalman::detail::zip_dist<D>(means, covariances, std::index_sequence_for<Cs...> {});
932  }
933  }
934 
935 
936 #ifdef __cpp_concepts
937  template<gaussian_distribution Dist>
938 #else
939  template<typename Dist, std::enable_if_t<gaussian_distribution<Dist>, int> = 0>
940 #endif
941  inline std::ostream&
942  operator<<(std::ostream& os, const Dist& d)
943  {
944  os << "mean:" << std::endl << mean_of(d) << std::endl <<
945  "covariance:" << std::endl << covariance_of(d) << std::endl;
946  return os;
947  }
948 
949 
950  // ---------------------- //
951  // Arithmetic Operators //
952  // ---------------------- //
953 
954 #ifdef __cpp_concepts
955  template<gaussian_distribution Dist1, gaussian_distribution Dist2> requires
956  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor, typename DistributionTraits<Dist2>::StaticDescriptor>
957 #else
958  template<typename Dist1, typename Dist2, std::enable_if_t<
959  gaussian_distribution<Dist1> and gaussian_distribution<Dist2> and
960  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor,
961  typename DistributionTraits<Dist2>::StaticDescriptor>, int> = 0>
962 #endif
963  inline auto
964  operator+(Dist1&& d1, Dist2&& d2)
965  {
966  using re = typename DistributionTraits<Dist1>::random_number_engine;
967  auto m1 = mean_of(std::forward<Dist1>(d1)) + mean_of(std::forward<Dist2>(d2));
968  auto m2 = covariance_of(std::forward<Dist1>(d1)) + covariance_of(std::forward<Dist2>(d2));
969  return make_GaussianDistribution<re>(std::move(m1), std::move(m2));
970  };
971 
972 
973 #ifdef __cpp_concepts
974  template<gaussian_distribution Dist1, gaussian_distribution Dist2> requires
975  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor, typename DistributionTraits<Dist2>::StaticDescriptor>
976 #else
977  template<typename Dist1, typename Dist2, std::enable_if_t<
978  gaussian_distribution<Dist1> and gaussian_distribution<Dist2> and
979  coordinates::compares_with<typename DistributionTraits<Dist1>::StaticDescriptor,
980  typename DistributionTraits<Dist2>::StaticDescriptor>, int> = 0>
981 #endif
982  inline auto
983  operator-(Dist1&& d1, Dist2&& d2)
984  {
985  using re = typename DistributionTraits<Dist1>::random_number_engine;
986  auto m1 = mean_of(std::forward<Dist1>(d1)) - mean_of(std::forward<Dist2>(d2));
987  auto m2 = covariance_of(std::forward<Dist1>(d1)) - covariance_of(std::forward<Dist2>(d2));
988  return make_GaussianDistribution<re>(std::move(m1), std::move(m2));
989  };
990 
991 
992 #ifdef __cpp_concepts
993  template<typed_matrix A, gaussian_distribution D> requires gaussian_distribution<D> and
994  (not euclidean_transformed<A>) and
995  (compares_with<vector_space_descriptor_of_t<A, 1>, typename DistributionTraits<D>::StaticDescriptor>)
996 #else
997  template<typename A, typename D, std::enable_if_t<typed_matrix<A> and gaussian_distribution<D> and
998  (not euclidean_transformed<A>) and
999  (compares_with<vector_space_descriptor_of_t<A, 1>, typename DistributionTraits<D>::StaticDescriptor>), int> = 0>
1000 #endif
1001  inline auto
1002  operator*(A&& a, D&& d)
1003  {
1004  using re = typename DistributionTraits<D>::random_number_engine;
1005  auto m = a * mean_of(std::forward<D>(d));
1006  auto c = scale(covariance_of(std::forward<D>(d)), std::forward<A>(a));
1007  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1008  }
1009 
1010 
1011 #ifdef __cpp_concepts
1012  template<gaussian_distribution Dist, std::convertible_to<const typename DistributionTraits<Dist>::Scalar> S>
1013 #else
1014  template<typename Dist, typename S, std::enable_if_t<
1015  gaussian_distribution<Dist> and stdex::convertible_to<S, const typename DistributionTraits<Dist>::Scalar>, int> = 0>
1016 #endif
1017  inline auto
1018  operator*(Dist&& d, S s)
1019  {
1020  using re = typename DistributionTraits<Dist>::random_number_engine;
1021  auto m = mean_of(std::forward<Dist>(d)) * s;
1022  auto c = scale(covariance_of(std::forward<Dist>(d)), s);
1023  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1024  };
1025 
1026 
1027 #ifdef __cpp_concepts
1028  template<gaussian_distribution Dist, std::convertible_to<const typename DistributionTraits<Dist>::Scalar> S>
1029 #else
1030  template<typename Dist, typename S, std::enable_if_t<
1031  gaussian_distribution<Dist> and stdex::convertible_to<S, const typename DistributionTraits<Dist>::Scalar>, int> = 0>
1032 #endif
1033  inline auto
1034  operator*(S s, Dist&& d)
1035  {
1036  using re = typename DistributionTraits<Dist>::random_number_engine;
1037  auto m = s * mean_of(std::forward<Dist>(d));
1038  auto c = scale(covariance_of(std::forward<Dist>(d)), s);
1039  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1040  };
1041 
1042 
1043 #ifdef __cpp_concepts
1044  template<gaussian_distribution Dist, std::convertible_to<const typename DistributionTraits<Dist>::Scalar> S>
1045 #else
1046  template<typename Dist, typename S, std::enable_if_t<
1047  gaussian_distribution<Dist> and std::is_convertible_v<S, const typename DistributionTraits<Dist>::Scalar>, int> = 0>
1048 #endif
1049  inline auto
1050  operator/(Dist&& d, S s)
1051  {
1052  using re = typename DistributionTraits<Dist>::random_number_engine;
1053  auto m = mean_of(std::forward<Dist>(d)) / s;
1054  auto c = inverse_scale(covariance_of(std::forward<Dist>(d)), s);
1055  return make_GaussianDistribution<re>(std::move(m), std::move(c));
1056  };
1057 
1058 }
1059 
1060 #endif
typename nested_object_of< T >::type nested_object_of_t
Helper type for nested_object_of.
Definition: nested_object_of.hpp:58
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
GaussianDistribution(Mean &&mean, Cov &&cov)
Construct from an rvalue of a mean and a covariance, typed_matrix, or covariance_nestable.
Definition: GaussianDistribution.hpp:146
auto make_GaussianDistribution(D &&dist)
Make a Gaussian distribution.
Definition: GaussianDistribution.hpp:494
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 value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
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. ...
constexpr bool triangular_matrix
Specifies that an argument is an indexible object having a given triangle_type (e.g., upper, lower, or diagonal).
Definition: triangular_matrix.hpp:36
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
Definition: object_traits.hpp:38
constexpr bool fixed_pattern
A coordinates::pattern for which the dimension is fixed at compile time.
Definition: fixed_pattern.hpp:46
auto split_diagonal(M &&m)
Split Covariance or SquareRootCovariance diagonally.
Definition: covariance-overloads.hpp:326
decltype(auto) constexpr transpose(Arg &&arg)
Swap any two indices of an indexible_object.
Definition: transpose.hpp:163
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
constexpr bool covariance
T is a specialization of either Covariance or SquareRootCovariance.
Definition: object-types.hpp:161
An upper-right triangular matrix.
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
Definition: trait_backports.hpp:64
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:35
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
auto operator()() const
Generate a random value from the distribution.
Definition: GaussianDistribution.hpp:325
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:35
auto split(D &&d)
Split distribution.
Definition: GaussianDistribution.hpp:920
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
constexpr bool compares_with
Compares two coordinates::pattern objects.
Definition: compares_with.hpp:475
A matrix with typed rows and columns.
Definition: forward-class-declarations.hpp:292