EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Sampling.h
Go to the documentation of this file.
1#pragma once
2
12
13#include <algorithm>
14#include <concepts>
15#include <random>
16
17#include <Eigen/Cholesky>
18
24
25namespace Emrys
26{
27
34template <typename Space, typename Scalar = double>
36{
38 Eigen::Array<Scalar, Eigen::Dynamic, 1> logDensity;
39};
40
48template <typename Space, typename Scalar = double>
54
55namespace internal
56{
57
61template <typename Matrix, std::uniform_random_bit_generator G>
62[[nodiscard]] Matrix
63standardNormal(Eigen::Index rows, Eigen::Index cols, G & rng)
64{
65 using Scalar = typename Matrix::Scalar;
66 static_assert(std::floating_point<Scalar>, "sampling requires a standard floating-point scalar");
67 auto z = Matrix{rows, cols};
68 auto normal = std::normal_distribution<Scalar>{};
69 std::generate(z.data(), z.data() + z.size(), [&] {
70 return normal(rng);
71 });
72 return z;
73}
74
79template <typename Vector, std::uniform_random_bit_generator G>
80[[nodiscard]] Vector
81standardNormalVector(Eigen::Index rows, G & rng)
82{
83 static_assert(std::floating_point<typename Vector::Scalar>, "sampling requires a standard floating-point scalar");
84 auto z = Vector{};
85 z.resize(rows);
86 auto normal = std::normal_distribution<typename Vector::Scalar>{};
87 std::generate(z.data(), z.data() + z.size(), [&] {
88 return normal(rng);
89 });
90 return z;
91}
92
98template <typename Derived, std::uniform_random_bit_generator G, typename Scalar>
99void
100fillStandardNormal(Derived && z, G & rng, std::normal_distribution<Scalar> & normal)
101{
102 static_assert(std::same_as<typename std::remove_cvref_t<Derived>::Scalar, Scalar>);
103 std::generate(z.data(), z.data() + z.size(), [&] {
104 return normal(rng);
105 });
106}
107
111template <typename Derived, std::uniform_random_bit_generator G>
112void
113fillStandardNormal(Derived && z, G & rng)
114{
115 using Scalar = typename std::remove_cvref_t<Derived>::Scalar;
116 static_assert(std::floating_point<Scalar>, "sampling requires a standard floating-point scalar");
117 auto normal = std::normal_distribution<Scalar>{};
118 fillStandardNormal(std::forward<Derived>(z), rng, normal);
119}
120
124template <typename Matrix, std::uniform_random_bit_generator G>
125[[nodiscard]] Matrix
126standardUniform(Eigen::Index rows, Eigen::Index cols, G & rng)
127{
128 using Scalar = typename Matrix::Scalar;
129 static_assert(std::floating_point<Scalar>, "sampling requires a standard floating-point scalar");
130 auto u = Matrix{rows, cols};
131 auto uniform = std::uniform_real_distribution<Scalar>{};
132 std::generate(u.data(), u.data() + u.size(), [&] {
133 return uniform(rng);
134 });
135 return u;
136}
137
138} // namespace internal
139
151template <typename Scalar, typename Space, std::uniform_random_bit_generator G>
152[[nodiscard]] SampleSet<Space, Scalar>
153drawSamples(Gaussian<Space, Scalar> const & gaussian, Eigen::Index n, G & rng)
154{
155 EMRYS_FILTER_ASSERT(n >= 0);
156 using Normals = SampleSet<DifferenceSpace<Space>, Scalar>;
157 Normals const z = internal::standardNormal<Normals>(gaussian.differenceDimension(), n, rng);
159 gaussian.space(),
160 gaussian.mean(),
161 internal::multiply(internal::asTriangular<Eigen::Lower>(gaussian.llt().matrixLLT()), z)
162 )};
163}
164
175template <typename Scalar, typename Space, std::uniform_random_bit_generator G>
176[[nodiscard]] typename Moments<Space, Scalar>::VectorType
177drawSample(Gaussian<Space, Scalar> const & gaussian, G & rng)
178{
179 using Difference = DifferenceVector<Space, Scalar>;
180 Difference const z = internal::standardNormalVector<Difference>(gaussian.differenceDimension(), rng);
182 gaussian.space(),
183 gaussian.mean(),
184 Difference{internal::multiply(internal::asTriangular<Eigen::Lower>(gaussian.llt().matrixLLT()), z)}
185 )};
186}
187
199template <typename Scalar, typename Space, std::uniform_random_bit_generator G>
200[[nodiscard]] SamplesWithLogDensity<Space, Scalar>
201drawSamplesWithLogDensity(Gaussian<Space, Scalar> const & gaussian, Eigen::Index n, G & rng)
202{
203 EMRYS_FILTER_ASSERT(n >= 0);
204 using Normals = SampleSet<DifferenceSpace<Space>, Scalar>;
205 Normals const z = internal::standardNormal<Normals>(gaussian.differenceDimension(), n, rng);
208 gaussian.space(),
209 gaussian.mean(),
210 internal::multiply(internal::asTriangular<Eigen::Lower>(gaussian.llt().matrixLLT()), z)
211 ),
212 {}
213 };
214 if constexpr (isLinear<Space>)
215 {
216 result.logDensity = gaussian.logPeak() - Scalar(0.5) * z.colwise().squaredNorm().transpose().array();
217 }
218 else
219 {
220 result.logDensity.resize(n);
221 for (Eigen::Index j = 0; j < n; ++j)
222 {
223 result.logDensity(j) = gaussian.logDensity(result.samples.col(j));
224 }
225 }
226 return result;
227}
228
240template <typename Scalar, typename Space, std::uniform_random_bit_generator G>
241[[nodiscard]] SampleWithLogDensity<Space, Scalar>
243{
244 using Difference = DifferenceVector<Space, Scalar>;
245 Difference const z = internal::standardNormalVector<Difference>(gaussian.differenceDimension(), rng);
248 gaussian.space(),
249 gaussian.mean(),
250 Difference{internal::multiply(internal::asTriangular<Eigen::Lower>(gaussian.llt().matrixLLT()), z)}
251 )},
252 0
253 };
254 if constexpr (isLinear<Space>)
255 {
256 result.logDensity = gaussian.logPeak() - Scalar(0.5) * z.squaredNorm();
257 }
258 else
259 {
260 result.logDensity = gaussian.logDensity(result.sample);
261 }
262 return result;
263}
264
265} // namespace Emrys
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
The macros every header includes first.
Products of fixed-size matrices by Eigen's fixed-size product at every size: multiply() is by Eigen'...
SampleSet: a matrix whose columns are samples in a space, which the samplers return and the unscented...
Solving by a factorization of a small matrix: transposedSolve() gives , the shape of a Kalman gain an...
The density of a Gaussian whose covariance has been factorized: a read-only view.
Definition Gaussian.h:1011
Index differenceDimension() const
Definition Gaussian.h:1047
VectorType const & mean() const
Definition Gaussian.h:1068
LltType const & llt() const
Definition Gaussian.h:1122
Space_ const & space() const
Definition Gaussian.h:1054
Scalar logDensity(Eigen::MatrixBase< Derived > const &x) const
Definition Gaussian.h:1223
Scalar logPeak() const
Definition Gaussian.h:1141
ValueVector< Space_, Scalar > VectorType
a value, such as the mean
Definition Moments.h:74
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
Eigen::Index drawSample(Categorical< Space, Scalar > const &distribution, G &rng)
Definition Categorical.h:1111
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
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 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
Scalar logDensity
the log-density at sample
Definition Sampling.h:52
Moments< Space, Scalar >::VectorType sample
the sample
Definition Sampling.h:51
Samples in Space together with the log of the density they were drawn from, evaluated at each.
Definition Sampling.h:36
SampleSet< Space, Scalar > samples
one sample per column
Definition Sampling.h:37
Eigen::Array< Scalar, Eigen::Dynamic, 1 > logDensity
logDensity(i) is the log-density at samples.col(i)
Definition Sampling.h:38