EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Component.h
Go to the documentation of this file.
1#pragma once
2
11
12#include <concepts>
13#include <type_traits>
14
25
26namespace Emrys
27{
28
29namespace internal
30{
31
35template <typename C, typename F>
36decltype(auto)
37keepingSpace(C & component, F & f)
38{
39 [[maybe_unused]] auto const before = typename C::SpaceType{component.space()};
40 if constexpr (std::is_void_v<std::invoke_result_t<F &, C &>>)
41 {
42 f(component);
43 EMRYS_FILTER_ASSERT(component.space() == before && "the component must keep its space");
44 }
45 else
46 {
47 std::invoke_result_t<F &, C &> result = f(component);
48 EMRYS_FILTER_ASSERT(component.space() == before && "the component must keep its space");
49 return result;
50 }
51}
52
56template <typename Scalar>
57struct CollapseWeights
58{
59 Scalar logTotal;
60 Eigen::Index kept;
61 Eigen::Index only;
62};
63
67template <typename Scalar, typename LogWeightAt>
68[[nodiscard]] CollapseWeights<Scalar>
69collapseWeights(Eigen::Index count, LogWeightAt const & logWeightAt)
70{
71 EMRYS_FILTER_ASSERT(count > 0 && "a collapse needs a component");
72 auto total = LogSumExp<Scalar>{};
73 auto result = CollapseWeights<Scalar>{Scalar(0), 0, 0};
74 for (Eigen::Index i = 0; i < count; ++i)
75 {
76 Scalar const logWeight = logWeightAt(i);
77 total.add(logWeight);
78 if (logWeight > -Eigen::NumTraits<Scalar>::infinity())
79 {
80 ++result.kept;
81 result.only = i;
82 }
83 }
84 result.logTotal = total.value();
85 EMRYS_FILTER_ASSERT(isFinite(result.logTotal) && "the weights must be finite and not all zero");
86 return result;
87}
88
89} // namespace internal
90
103template <typename C>
105
110template <typename C>
111inline constexpr bool isGaussian = false;
112
114template <Space Space_, RealScalar Scalar_>
115inline constexpr bool isGaussian<GaussianParams<Space_, Scalar_>>{true};
116
118
120template <Space Space_, RealScalar Scalar_>
121struct ComponentTraits<GaussianParams<Space_, Scalar_>>
122{
124
128 template <typename Selection, typename SubSpace>
130
134 template <typename Derived>
135 [[nodiscard]] static Scalar_
136 logDensity(Type const & gaussian, Eigen::MatrixBase<Derived> const & x)
137 {
138 return internal::FactorizedGaussian::logDensity(gaussian, x);
139 }
140
150 template <typename ComponentAt, typename LogWeightAt>
151 [[nodiscard]] static Type
152 collapse(Eigen::Index count, ComponentAt componentAt, LogWeightAt logWeightAt)
153 {
154 auto const weights = internal::collapseWeights<Scalar_>(count, logWeightAt);
155 if (weights.kept == 1)
156 {
157 return Type{componentAt(weights.only)};
158 }
159 Type const & first = componentAt(0);
160 return Type{
161 first.space(),
162 mixtureMomentsIn<typename Type::MomentsType>(
163 first.space(),
164 count,
165 [&](Eigen::Index i) -> decltype(auto) {
166 return componentAt(i).mean();
167 },
168 [&](Eigen::Index i) -> decltype(auto) {
169 return componentAt(i).covarianceLower();
170 },
171 logWeightAt,
172 weights.logTotal
173 )
174 };
175 }
176
178 [[nodiscard]] static typename Type::MomentsType const &
179 moments(Type const & gaussian)
180 {
181 return gaussian.moments();
182 }
183};
184
186template <Space Space_, RealScalar Scalar_>
187struct ComponentTraits<SqrtGaussianParams<Space_, Scalar_>>
188{
190
195 template <typename Selection, typename SubSpace>
196 using MarginalType = internal::SqrtComponentMarginal<Type, Selection, SubSpace>;
197
201 template <typename Derived>
202 [[nodiscard]] static Scalar_
203 logDensity(Type const & gaussian, Eigen::MatrixBase<Derived> const & x)
204 {
205 typename Type::DifferenceVectorType residual = Emrys::minus(gaussian.space(), x, gaussian.mean());
206 gaussian.whitenInPlace(residual);
207 Scalar_ const dimension = internal::scalarFromCount<Scalar_>(gaussian.differenceDimension());
208 return Scalar_(-0.5) * (dimension * log2Pi<Scalar_>() + gaussian.m_logDeterminant + residual.squaredNorm());
209 }
210
224 template <typename ComponentAt, typename LogWeightAt>
225 [[nodiscard]] static Type
226 collapse(Eigen::Index count, ComponentAt componentAt, LogWeightAt logWeightAt)
227 {
228 auto const weights = internal::collapseWeights<Scalar_>(count, logWeightAt);
229 if (weights.kept == 1)
230 {
231 return Type{componentAt(weights.only)};
232 }
233 Type const & first = componentAt(0);
234 auto const & space = first.space();
235 typename Type::VectorType mean = pointMomentsIn<typename Type::MomentsType>(
236 space,
237 count,
238 [&](Eigen::Index i) -> decltype(auto) {
239 return componentAt(i).mean();
240 },
241 logWeightAt,
242 weights.logTotal
243 )
244 .mean();
245 constexpr int Rows = Type::DifferenceDimensionAtCompileTime;
246 constexpr int MaxRows = Type::MaxDifferenceDimensionAtCompileTime;
247 using Stack = internal::MatrixOf<
248 Scalar_,
249 Rows,
250 Rows == Eigen::Dynamic ? Eigen::Dynamic : 2 * Rows + 1,
251 MaxRows,
252 MaxRows == Eigen::Dynamic ? Eigen::Dynamic : 2 * MaxRows + 1>;
253 Eigen::Index const n = first.differenceDimension();
254 typename Type::MatrixType factor = Type::MatrixType::Zero(n, n);
255 auto stack = Stack{n, 2 * n + 1};
256 for (Eigen::Index i = 0; i < count; ++i)
257 {
258 Scalar_ const logWeight = logWeightAt(i);
259 if (logWeight == -Eigen::NumTraits<Scalar_>::infinity())
260 {
261 continue;
262 }
263 Type const & component = componentAt(i);
264 Scalar_ const root = Eigen::numext::exp(Scalar_(0.5) * (logWeight - weights.logTotal));
265 stack.leftCols(n) = factor;
266 stack.middleCols(n, n) = root * component.root();
267 stack.col(2 * n) = root * Emrys::minus(space, component.mean(), mean);
268 factor = internal::lowerTriangularRoot(stack);
269 }
270 return Type{space, std::move(mean), std::move(factor)};
271 }
272
274 [[nodiscard]] static typename Type::MomentsType
275 moments(Type const & gaussian)
276 {
277 return gaussian.moments();
278 }
279};
280
298template <typename C>
299concept Component = std::same_as<Density<Params<C>>, C> && requires(Params<C> const & c) {
300 typename Params<C>::SpaceType;
301 typename Params<C>::Scalar;
302 typename Params<C>::MomentsType;
303 { Params<C>::ValueDimensionAtCompileTime } -> std::convertible_to<int>;
304 { Params<C>::MaxValueDimensionAtCompileTime } -> std::convertible_to<int>;
305 { Params<C>::DifferenceDimensionAtCompileTime } -> std::convertible_to<int>;
306 { Params<C>::MaxDifferenceDimensionAtCompileTime } -> std::convertible_to<int>;
307 { c.space() } -> std::same_as<typename Params<C>::SpaceType const &>;
308 { c.valueDimension() } -> std::same_as<Eigen::Index>;
309 { c.differenceDimension() } -> std::same_as<Eigen::Index>;
310 { ComponentTraits<Params<C>>::moments(c) } -> std::convertible_to<typename Params<C>::MomentsType>;
311 { c.factorize() };
312 typename ComponentTraits<Params<C>>::Type;
313};
314
315namespace internal
316{
317
322template <typename C>
323concept InfoFormDensity = GaussianForm<Params<C>> && std::same_as<Density<Params<C>>, C> && isInfoForm<Params<C>>;
324
328template <typename C>
329concept ComponentOrInfoForm = Component<C> || InfoFormDensity<C>;
330
331} // namespace internal
332
333} // namespace Emrys
What the four forms of the Gaussian share (decisions.md [gaussian-forms], [form-densities]): the Gaus...
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
Params and Density: the traits that pair a distribution's parameters with its density,...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
The square-root form of the Gaussian (decisions.md [gaussian-forms]): its parameters SqrtGaussianPara...
Weighted statistics over points, all in internal, which the containers of weighted elements (Gaussian...
Triangularization: the triangular factor of a stacked matrix by Householder reflections,...
Log-weights: the WeightError a normalization can fail with (NumericError.h), and the streaming log-su...
Read-only view of a subset of the entries of a GaussianParams or Gaussian.
Definition Gaussian.h:1324
A Gaussian distribution: a mean and covariance in a space.
Definition Gaussian.h:259
MomentsType const & moments() const
Definition Gaussian.h:526
Space_ const & space() const
Definition Gaussian.h:519
A Gaussian kept as a mean and a lower-triangular root of its covariance.
Definition SqrtGaussian.h:81
typename MomentsType::VectorType VectorType
Definition SqrtGaussian.h:87
Index differenceDimension() const
Definition SqrtGaussian.h:155
MomentsType moments() const
Definition SqrtGaussian.h:185
static constexpr int DifferenceDimensionAtCompileTime
Definition SqrtGaussian.h:100
Space_ const & space() const
Definition SqrtGaussian.h:162
VectorType const & mean() const
Definition SqrtGaussian.h:169
typename MomentsType::DifferenceVectorType DifferenceVectorType
Definition SqrtGaussian.h:88
static constexpr int MaxDifferenceDimensionAtCompileTime
Definition SqrtGaussian.h:103
typename MomentsType::MatrixType MatrixType
Definition SqrtGaussian.h:89
MatrixType const & root() const
Definition SqrtGaussian.h:178
The distribution that a container of several holds one of per element (decisions.md [component-first]...
Definition Component.h:299
A Gaussian in any of its four forms (decisions.md [gaussian-forms]): GaussianParams,...
Definition GaussianForm.h:46
bool isFinite(T const &x)
Definition Math.h:305
Scalar log2Pi()
Definition Math.h:177
constexpr bool isGaussian
Whether C is a Gaussian in covariance form: the component for which a container offers the convenienc...
Definition Component.h:111
constexpr bool isInfoForm
Whether the GaussianForm G holds the precision, as InfoGaussianParams and SqrtInfoGaussianParams do,...
Definition GaussianForm.h:69
typename ParamsOf< D >::type Params
The parameters of the density D: GaussianParams for a Gaussian, and D itself for a distribution whose...
Definition Params.h:42
auto minus(S const &space, Eigen::MatrixBase< ADerived > const &a, Eigen::MatrixBase< BDerived > const &b)
Definition Space.h:715
static Type collapse(Eigen::Index count, ComponentAt componentAt, LogWeightAt logWeightAt)
Definition Component.h:152
static Type::MomentsType const & moments(Type const &gaussian)
Definition Component.h:179
static Scalar_ logDensity(Type const &gaussian, Eigen::MatrixBase< Derived > const &x)
Definition Component.h:136
GaussianParams< Space_, Scalar_ > Type
the component
Definition Component.h:123
GaussianMarginal< Type, Selection, SubSpace > MarginalType
A marginal of one component, which borrows the selection the marginal of its container resolved (an i...
Definition Component.h:129
static Type::MomentsType moments(Type const &gaussian)
Definition Component.h:275
static Scalar_ logDensity(Type const &gaussian, Eigen::MatrixBase< Derived > const &x)
Definition Component.h:203
SqrtGaussianParams< Space_, Scalar_ > Type
the component
Definition Component.h:189
static Type collapse(Eigen::Index count, ComponentAt componentAt, LogWeightAt logWeightAt)
Definition Component.h:226
internal::SqrtComponentMarginal< Type, Selection, SubSpace > MarginalType
A marginal of one component, which borrows the selection the marginal of its container resolved (an i...
Definition Component.h:196
What a container does with a component beyond the component's own members (decisions....
Definition Component.h:104