EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
GaussianForm.h
Go to the documentation of this file.
1#pragma once
2
11
12#include <concepts>
13#include <expected>
14#include <random>
15#include <utility>
16
27
28namespace Emrys
29{
30
45template <typename G>
46concept GaussianForm = requires(G const & g) {
47 typename G::SpaceType;
48 typename G::Scalar;
49 typename G::VectorType;
50 typename G::MatrixType;
51 { G::IsInfoForm } -> std::convertible_to<bool>;
52 { G::IsSqrtForm } -> std::convertible_to<bool>;
53 { g.space() } -> std::same_as<typename G::SpaceType const &>;
54 { g.valueDimension() } -> std::same_as<Eigen::Index>;
55 { g.differenceDimension() } -> std::same_as<Eigen::Index>;
56 { g.mean() } -> std::convertible_to<std::expected<typename G::VectorType, GaussianError>>;
57 { g.covariance() } -> std::same_as<std::expected<typename G::MatrixType, GaussianError>>;
58 { g.precision() } -> std::same_as<std::expected<typename G::MatrixType, GaussianError>>;
59 { g.covarianceRoot() } -> std::same_as<std::expected<typename G::MatrixType, GaussianError>>;
60 { g.precisionRoot() } -> std::same_as<std::expected<typename G::MatrixType, GaussianError>>;
61};
62
68template <GaussianForm G>
69inline constexpr bool isInfoForm = G::IsInfoForm;
70
75template <GaussianForm G>
76inline constexpr bool isSqrtForm = G::IsSqrtForm;
77
89template <GaussianForm G>
90[[nodiscard]] std::expected<GaussianParams<typename G::SpaceType, typename G::Scalar>, GaussianError>
91toGaussian(G const & form)
92{
93 std::expected<typename G::VectorType, GaussianError> mean = form.mean();
94 if (!mean)
95 {
96 return std::unexpected{mean.error()};
97 }
98 auto covariance = form.covariance();
99 if (!covariance)
100 {
101 return std::unexpected{covariance.error()};
102 }
104 {
105 auto const step = Emrys::minus(form.space(), *mean, form.reference());
106 resetCovariance(form.space(), form.reference(), step, *covariance);
107 }
109 form.space(),
110 std::move(*mean),
111 std::move(*covariance)
112 };
113}
114
137template <typename Params_>
138class FormGaussian
139{
140public:
141
142 using ParamsType = Params_;
143 using SpaceType = typename Params_::SpaceType;
144 using Scalar = typename Params_::Scalar;
145 using Index = Eigen::Index;
146 using VectorType = typename Params_::VectorType;
147 using DifferenceVectorType = typename Params_::DifferenceVectorType;
148 using MatrixType = typename Params_::MatrixType;
149 using MomentsType = typename Params_::MomentsType;
150
152 static constexpr int ValueDimensionAtCompileTime = Params_::ValueDimensionAtCompileTime;
153
155 static constexpr int MaxValueDimensionAtCompileTime = Params_::MaxValueDimensionAtCompileTime;
156
158 static constexpr int DifferenceDimensionAtCompileTime = Params_::DifferenceDimensionAtCompileTime;
159
161 static constexpr int MaxDifferenceDimensionAtCompileTime = Params_::MaxDifferenceDimensionAtCompileTime;
162
163 static constexpr bool IsParams = false;
164
166 [[nodiscard]] Index
168 {
169 return params().valueDimension();
170 }
171
173 [[nodiscard]] Index
175 {
176 return params().differenceDimension();
177 }
178
180 [[nodiscard]] SpaceType const &
181 space() const
182 {
183 return params().space();
184 }
185
187 [[nodiscard]] VectorType const &
188 mean() const
189 {
190 return params().densityMean();
191 }
192
197 [[nodiscard]] MomentsType
198 moments() const
199 {
200 return params().densityMoments();
201 }
202
210 template <typename Path>
211 [[nodiscard]] auto
212 marginal() const
213 {
214 return internal::marginalOverPath<Path>(space(), [&](auto const & kept, auto const & keptSpace) {
215 return params().densityMarginalAt(kept, keptSpace);
216 });
217 }
218
222 template <typename Path>
223 [[nodiscard]] auto
224 marginal(Index element) const
225 {
226 return internal::marginalOverElement<Path>(space(), element, [&](auto const & kept, auto const & keptSpace) {
227 return params().densityMarginalAt(kept, keptSpace);
228 });
229 }
230
232 [[nodiscard]] Scalar
234 {
235 return params().m_logDeterminant;
236 }
237
241 [[nodiscard]] MatrixType const &
242 root() const
243 requires(Params_::IsSqrtForm && !Params_::IsInfoForm)
244 {
245 return params().root();
246 }
247
251 [[nodiscard]] Scalar
252 logPeak() const
253 {
255 return Scalar(-0.5) * (internal::scalarFromCount<Scalar>(differenceDimension()) * log2Pi + logDeterminant());
256 }
257
262 template <typename Derived>
263 [[nodiscard]] Scalar
264 squaredMahalanobisDistance(Eigen::MatrixBase<Derived> const & x) const
265 {
266 static_assert(Derived::IsVectorAtCompileTime, "squaredMahalanobisDistance() expects a vector");
267 EMRYS_FILTER_ASSERT(x.size() == valueDimension());
268 DifferenceVectorType residual = Emrys::minus(space(), x, mean());
269 params().whitenInPlace(residual);
270 return residual.squaredNorm();
271 }
272
276 template <typename Derived>
277 [[nodiscard]] Scalar
278 confidence(Eigen::MatrixBase<Derived> const & x) const
279 {
280 if (differenceDimension() == 0)
281 {
282 return Scalar(0);
283 }
286 internal::scalarFromCount<Scalar>(differenceDimension())
287 );
288 }
289
293 template <typename Derived>
294 [[nodiscard]] bool
295 contains(Eigen::MatrixBase<Derived> const & x, Scalar probability) const
296 {
297 EMRYS_FILTER_ASSERT(probability > 0 && probability < 1 && "the probability must be in (0, 1)");
298 if (differenceDimension() == 0)
299 {
300 return true;
301 }
303 <= chiSquaredQuantile<Scalar>(probability, internal::scalarFromCount<Scalar>(differenceDimension()));
304 }
305
307 template <typename Derived>
308 [[nodiscard]] Scalar
309 logDensity(Eigen::MatrixBase<Derived> const & x) const
310 {
311 return logPeak() - Scalar(0.5) * squaredMahalanobisDistance(x);
312 }
313
318 template <typename Derived>
319 [[nodiscard]] Scalar
320 density(Eigen::MatrixBase<Derived> const & x) const
321 {
322 return Eigen::numext::exp(logDensity(x));
323 }
324
330 template <typename Derived>
331 [[nodiscard]] typename Derived::PlainObject
332 colorNormals(Eigen::MatrixBase<Derived> const & z) const
333 {
334 EMRYS_FILTER_ASSERT(z.rows() == differenceDimension());
335 auto result = typename Derived::PlainObject{};
336 result.resize(z.rows(), z.cols());
337 params().colorInto(result, z);
338 return result;
339 }
340
341private:
342
343 friend Params_;
344
346 explicit FormGaussian(Params_ const & params)
347 : m_check{params}
348 {}
349
351 [[nodiscard]] Params_ const &
352 params() const
353 {
354 return m_check.get();
355 }
356
357 internal::ValuesCheck<Params_> m_check;
358};
359
366template <typename Params_, std::uniform_random_bit_generator G>
368drawSamples(FormGaussian<Params_> const & gaussian, Eigen::Index n, G & rng)
369{
370 EMRYS_FILTER_ASSERT(n >= 0);
371 using Space = typename Params_::SpaceType;
372 using Scalar = typename Params_::Scalar;
373 using Normals = SampleSet<DifferenceSpace<Space>, Scalar>;
374 Normals const z = internal::standardNormal<Normals>(gaussian.differenceDimension(), n, rng);
375 return SampleSet<Space, Scalar>{Emrys::plus(gaussian.space(), gaussian.mean(), gaussian.colorNormals(z))};
376}
377
382template <typename Params_, std::uniform_random_bit_generator G>
384drawSample(FormGaussian<Params_> const & gaussian, G & rng)
385{
388 Normals const z = internal::standardNormalVector<Normals>(gaussian.differenceDimension(), rng);
389 return typename MomentsType::VectorType{Emrys::plus(gaussian.space(), gaussian.mean(), gaussian.colorNormals(z))};
390}
391
401template <typename Params_, std::uniform_random_bit_generator G>
402[[nodiscard]] SamplesWithLogDensity<typename Params_::SpaceType, typename Params_::Scalar>
403drawSamplesWithLogDensity(FormGaussian<Params_> const & gaussian, Eigen::Index n, G & rng)
404{
405 EMRYS_FILTER_ASSERT(n >= 0);
406 using Space = typename Params_::SpaceType;
407 using Scalar = typename Params_::Scalar;
408 using Normals = SampleSet<DifferenceSpace<Space>, Scalar>;
409 Normals const z = internal::standardNormal<Normals>(gaussian.differenceDimension(), n, rng);
411 Emrys::plus(gaussian.space(), gaussian.mean(), gaussian.colorNormals(z)),
412 {}
413 };
414 if constexpr (isLinear<Space>)
415 {
416 result.logDensity = gaussian.logPeak() - Scalar(0.5) * z.colwise().squaredNorm().transpose().array();
417 }
418 else
419 {
420 result.logDensity.resize(n);
421 for (Eigen::Index j = 0; j < n; ++j)
422 {
423 result.logDensity(j) = gaussian.logDensity(result.samples.col(j));
424 }
425 }
426 return result;
427}
428
435template <typename Params_, std::uniform_random_bit_generator G>
436[[nodiscard]] SampleWithLogDensity<typename Params_::SpaceType, typename Params_::Scalar>
438{
439 using Space = typename Params_::SpaceType;
440 using Scalar = typename Params_::Scalar;
441 using MomentsType = Moments<Space, Scalar>;
442 using Normals = DifferenceVector<Space, Scalar>;
443 Normals const z = internal::standardNormalVector<Normals>(gaussian.differenceDimension(), rng);
445 typename MomentsType::VectorType{Emrys::plus(gaussian.space(), gaussian.mean(), gaussian.colorNormals(z))},
446 0
447 };
448 if constexpr (isLinear<Space>)
449 {
450 result.logDensity = gaussian.logPeak() - Scalar(0.5) * z.squaredNorm();
451 }
452 else
453 {
454 result.logDensity = gaussian.logDensity(result.sample);
455 }
456 return result;
457}
458
459} // namespace Emrys
The chi-squared distribution's CDF and quantile, with no dependency outside Eigen,...
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
What marginals and conditionals are built from: resolving Eigen index sets against a space; the share...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
The covariance reset (decisions.md [covariance-reset]): hasIdentityReset<>, resetJacobian(),...
SampleSet: a matrix whose columns are samples in a space, which the samplers return and the unscented...
Drawing samples: SamplesWithLogDensity and SampleWithLogDensity, the Gaussian draws drawSamples(),...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
What parameters and their views share (decisions.md [view-stamp], [params-and-density]): Stamp,...
The density of a Gaussian in a square-root or information form: a read-only view.
Definition GaussianForm.h:139
static constexpr int MaxValueDimensionAtCompileTime
Definition GaussianForm.h:155
SpaceType const & space() const
Definition GaussianForm.h:181
typename Params_::MatrixType MatrixType
a matrix over differences
Definition GaussianForm.h:148
typename Params_::DifferenceVectorType DifferenceVectorType
a difference, such as a residual
Definition GaussianForm.h:147
static constexpr int DifferenceDimensionAtCompileTime
Definition GaussianForm.h:158
typename Params_::Scalar Scalar
the scalar type
Definition GaussianForm.h:144
static constexpr int MaxDifferenceDimensionAtCompileTime
Definition GaussianForm.h:161
MomentsType moments() const
Definition GaussianForm.h:198
auto marginal(Index element) const
marginal<Path>() of repetition element of the repeated block Path starts at (see GaussianParams::marg...
Definition GaussianForm.h:224
static constexpr bool IsParams
Definition GaussianForm.h:163
bool contains(Eigen::MatrixBase< Derived > const &x, Scalar probability) const
Definition GaussianForm.h:295
auto marginal() const
Definition GaussianForm.h:212
Index differenceDimension() const
Definition GaussianForm.h:174
typename Params_::SpaceType SpaceType
the space the values live in
Definition GaussianForm.h:143
Scalar logPeak() const
Definition GaussianForm.h:252
VectorType const & mean() const
Definition GaussianForm.h:188
Scalar confidence(Eigen::MatrixBase< Derived > const &x) const
Definition GaussianForm.h:278
static constexpr int ValueDimensionAtCompileTime
Definition GaussianForm.h:152
Scalar logDeterminant() const
Definition GaussianForm.h:233
typename Params_::VectorType VectorType
a value, such as the mean
Definition GaussianForm.h:146
Scalar logDensity(Eigen::MatrixBase< Derived > const &x) const
Definition GaussianForm.h:309
Scalar density(Eigen::MatrixBase< Derived > const &x) const
Definition GaussianForm.h:320
Scalar squaredMahalanobisDistance(Eigen::MatrixBase< Derived > const &x) const
Definition GaussianForm.h:264
typename Params_::MomentsType MomentsType
the mean and covariance together
Definition GaussianForm.h:149
Derived::PlainObject colorNormals(Eigen::MatrixBase< Derived > const &z) const
Definition GaussianForm.h:332
Params_ ParamsType
the parameters it reads
Definition GaussianForm.h:142
MatrixType const & root() const
Definition GaussianForm.h:242
Eigen::Index Index
Eigen's index type.
Definition GaussianForm.h:145
Index valueDimension() const
Definition GaussianForm.h:167
A Gaussian distribution: a mean and covariance in a space.
Definition Gaussian.h:259
First and second moments (mean and covariance) of a distribution.
Definition Moments.h:55
ValueVector< Space_, Scalar > VectorType
a value, such as the mean
Definition Moments.h:74
A Gaussian in any of its four forms (decisions.md [gaussian-forms]): GaussianParams,...
Definition GaussianForm.h:46
A type usable as the space of a distribution.
Definition Space.h:186
Scalar chiSquaredQuantile(std::type_identity_t< Scalar > const &probability, std::type_identity_t< Scalar > const &dof)
Definition ChiSquared.h:148
Scalar chiSquaredCdf(std::type_identity_t< Scalar > const &x, std::type_identity_t< Scalar > const &dof)
Definition ChiSquared.h:123
Scalar log2Pi()
Definition Math.h:177
SampleWithLogDensity< Space, Scalar > drawSampleWithLogDensity(Gamma< Space, Scalar > const &gamma, G &rng)
Definition Gamma.h:546
Eigen::Matrix< Scalar, valueDimensionAtCompileTime< Space >, Eigen::Dynamic,(maxValueDimensionAtCompileTime< Space >==1 ? Eigen::RowMajor :Eigen::ColMajor), maxValueDimensionAtCompileTime< Space >, Eigen::Dynamic > SampleSet
A matrix whose columns are samples in Space (see Spaces), with the space's size and storage bound.
Definition SampleSet.h:33
NumericError GaussianError
Reasons a Gaussian, in any of its forms (decisions.md [gaussian-forms]), can fail to give a density,...
Definition NumericError.h:45
Eigen::Index drawSample(Categorical< Space, Scalar > const &distribution, G &rng)
Definition Categorical.h:1111
constexpr bool isInfoForm
Whether the GaussianForm G holds the precision, as InfoGaussianParams and SqrtInfoGaussianParams do,...
Definition GaussianForm.h:69
constexpr bool isSqrtForm
Whether the GaussianForm G holds a triangular root, as SqrtGaussianParams and SqrtInfoGaussianParams ...
Definition GaussianForm.h:76
std::expected< GaussianParams< typename G::SpaceType, typename G::Scalar >, GaussianError > toGaussian(G const &form)
Definition GaussianForm.h:91
std::vector< Eigen::Index > drawSamples(Categorical< Space, Scalar > const &distribution, Eigen::Index n, G &rng)
Definition Categorical.h:1087
SamplesWithLogDensity< Space, Scalar > drawSamplesWithLogDensity(Gamma< Space, Scalar > const &gamma, Eigen::Index n, G &rng)
Definition Gamma.h:529
auto plus(S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
Definition Space.h:675
auto minus(S const &space, Eigen::MatrixBase< ADerived > const &a, Eigen::MatrixBase< BDerived > const &b)
Definition Space.h:715
ValueVector< DifferenceSpace< S >, Scalar > DifferenceVector
A difference in S as an Eigen column vector of Scalar, the type of minus() and of the offset plus() t...
Definition Space.h:650
constexpr bool hasIdentityReset
Whether the reset Jacobian of S is the identity, so that a covariance needs no change when its mean m...
Definition Reset.h:100
void resetCovariance(S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d, Eigen::MatrixBase< CovDerived > const &cov)
Carries the covariance cov from the tangent space at x to the one at , in place: ,...
Definition Reset.h:426
constexpr bool isLinear
Whether S is linear: its values and its differences are both plain vectors.
Definition Space.h:321
One sample in Space, in a vector sized by the space, together with the log of the density it was draw...
Definition Sampling.h:50
Samples in Space together with the log of the density they were drawn from, evaluated at each.
Definition Sampling.h:36