38template <
typename GaussianType,
typename Allocator>
39struct MixtureSmoothingScratch
41 using Scalar =
typename GaussianType::Scalar;
43 Buffer<GaussianType, Allocator> pairs;
44 Buffer<Scalar, Allocator> pairLogWeights;
45 Buffer<Eigen::Index, Allocator> offsets;
46 Buffer<Scalar, Allocator> logWeights;
49 explicit MixtureSmoothingScratch(Allocator
const & allocator = {})
50 : pairs(ReBound<Allocator, GaussianType>(allocator))
51 , pairLogWeights(ReBound<Allocator, Scalar>(allocator))
52 , offsets(ReBound<Allocator, Eigen::Index>(allocator))
53 , logWeights(ReBound<Allocator, Scalar>(allocator))
77 NextLineage
const & nextLineage,
82 using Scalar =
typename Joint::Scalar;
83 using GaussianType =
typename Joint::JointType::GaussianType;
84 using Index = Eigen::Index;
85 Scalar
const minusInfinity = -Eigen::NumTraits<Scalar>::infinity();
86 Index
const parents = Index(joint.joints.size());
87 Index
const children = next.size();
88 EMRYS_FILTER_ASSERT(smoothed.size() == parents &&
"the smoothed mixture must have a component per parent");
89 EMRYS_FILTER_ASSERT(Index(gains.size()) == parents &&
"the gains must have one per parent");
91 nextLineage.parentCount() == parents && nextLineage.size() == children
92 &&
"the lineage must have a row per component at the step's end and a share per component at its start"
94 auto const logTotal = next.logTotalWeight();
95 EMRYS_FILTER_ASSERT(logTotal &&
"the smoothed mixture at the step's end must have valid weights");
96 auto const logChildWeight = [&](Index p) {
97 return next[p].logWeight - *logTotal;
99 auto const paired = [&](Index p, Index n) {
100 return logChildWeight(p) > minusInfinity && nextLineage.logShare(p, n) > minusInfinity;
104 scratch.offsets.assign(std::size_t(parents + 1), 0);
105 for (Index n = 0; n < parents; ++n)
108 for (Index p = 0; p < children; ++p)
110 count += paired(p, n) ? 1 : 0;
112 scratch.offsets[std::size_t(n + 1)] = scratch.offsets[std::size_t(n)] + count;
114 std::size_t
const total = std::size_t(scratch.offsets.back());
115 scratch.pairs.resize(total);
116 scratch.pairLogWeights.resize(total);
117 scratch.logWeights.resize(std::size_t(parents));
119 internal::forEachIndex(policy, parents, [&](Index n) {
120 auto const & parentJoint = joint.joints[std::size_t(n)];
121 Index
const first = scratch.offsets[std::size_t(n)];
123 for (Index p = 0; p < children; ++p)
128 scratch.pairs[std::size_t(slot)] =
smoothStep(parentJoint, gains[std::size_t(n)], next[p].component);
129 scratch.pairLogWeights[std::size_t(slot)] = logChildWeight(p) + nextLineage.logShare(p, n);
133 auto weight = LogSumExp<Scalar>{};
134 for (Index i = first; i < slot; ++i)
136 weight.add(scratch.pairLogWeights[std::size_t(i)]);
138 scratch.logWeights[std::size_t(n)] = weight.value();
140 smoothed.forEach(policy, [&](
auto & entry) {
141 Index
const n = entry.index();
142 Index
const first = scratch.offsets[std::size_t(n)];
143 Index
const count = scratch.offsets[std::size_t(n + 1)] - first;
147 entry.setComponent(joint.joints[std::size_t(n)].filtered);
152 ComponentTraits<GaussianType>::collapse(
154 [&](Index i) -> GaussianType
const & {
155 return scratch.pairs[std::size_t(first + i)];
158 return scratch.pairLogWeights[std::size_t(first + i)];
163 for (Index n = 0; n < parents; ++n)
165 smoothed.setLogWeight(n, scratch.logWeights[std::size_t(n)]);
168 [[maybe_unused]]
auto const normalized = smoothed.normalize();
169 EMRYS_FILTER_ASSERT(normalized &&
"nothing at the step's end descends from a component at its start");
246template <Space Space_, RealScalar Scalar_ =
double,
typename Allocator_ = DefaultAllocator>
274 explicit Step(
JointType const & recorded, Allocator_
const & allocator = {})
275 :
joint{copyJoint(recorded, allocator)}
288 :
joint{moveJoint(std::move(recorded), allocator)}
298 Step(
Step const & other, Allocator_
const & allocator)
308 :
joint{moveJoint(std::move(other.
joint), allocator)}
333 for (std::size_t n = 0; n <
joint.joints.size(); ++n)
344 for (std::size_t n = 0; n <
gains.size(); ++n)
346 gains[n] = internal::rtsGain(
joint.joints[n]);
358 internal::Buffer<GainType, Allocator_>
gains;
364 copyJoint(
JointType const & recorded, Allocator_
const & allocator)
375 moveJoint(
JointType && recorded, Allocator_
const & allocator)
387 using StepAllocator = internal::ReBound<Allocator_, Step>;
388 using ListType = std::list<Step, StepAllocator>;
391 using ScratchType = internal::MixtureSmoothingScratch<GaussianParams<Space_, Scalar_>, Allocator_>;
402 : m_steps(StepAllocator(allocator))
403 , m_scratch{allocator}
408 : m_steps(StepAllocator(allocator))
409 , m_scratch{allocator}
412 EMRYS_FILTER_ASSERT(
lag.steps > 0 &&
"a fixed-lag history keeps at least one step");
422 : m_steps(other.m_steps, StepAllocator(allocator))
423 , m_scratch{allocator}
434 : m_steps(std::move(other.m_steps), StepAllocator(allocator))
435 , m_scratch{allocator}
457 [[nodiscard]] std::optional<Index>
460 return m_lag > 0 ? std::optional<Index>{m_lag} : std::nullopt;
467 return Index(m_steps.size());
474 return m_steps.empty();
478 [[nodiscard]] Step
const &
481 EMRYS_FILTER_ASSERT(!
empty() &&
"the history is empty");
482 return m_steps.front();
486 [[nodiscard]] Step
const &
489 EMRYS_FILTER_ASSERT(!
empty() &&
"the history is empty");
490 return m_steps.back();
497 return m_steps.begin();
504 return m_steps.end();
523 record(std::move(joint));
531 template <
typename LatestAllocator>
541 template <ExecutionPolicy P,
typename LatestAllocator>
545 auto step = m_steps.rbegin();
546 if (step == m_steps.rend())
550 assertFollows(latest.
lineage(), *step);
551 internal::smoothMixtureStep(
560 for (
auto next = step++; step != m_steps.rend(); next = step++)
562 internal::smoothMixtureStep(
584 template <
typename Jo
int>
586 record(Joint && joint)
595 if (m_lag > 0 &&
size() == m_lag)
597 m_steps.splice(m_steps.end(), m_steps, m_steps.begin());
598 Step & step = m_steps.back();
600 step.joint.joints.assign(joint.
joints.begin(), joint.
joints.end());
601 step.joint.lineage = joint.
lineage;
602 step.resetSmoothed();
607 m_steps.emplace_back(std::forward<Joint>(joint));
615 template <
typename Lineage>
617 assertFollows([[maybe_unused]] Lineage
const & lineage, [[maybe_unused]]
Step const & step)
620 lineage.count() == step.joint.lineage.count() + 1
621 && lineage.parentCount() ==
Index(step.joint.joints.size())
622 &&
"the lineage must start at the newest record's predictJoint(): one predictJoint() apart, and no copy of "
628 ScratchType m_scratch;
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
Execution policies (decisions.md [execution-policies]): execution::sequential, the ExecutionPolicy co...
Smoothing the Kalman family (decisions.md [smoothing]): smoothStep(), the Rauch-Tung-Striebel backwar...
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
Lag, the number of steps a fixed-lag history keeps, which every history of the Smoothers layer takes ...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
MixtureFilter (decisions.md [mixture-filter], [filters-and-recursions]): a Mixture state whose compon...
The mixture: the parameters MixtureParams of weighted components of one type (decisions....
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
Log-weights: the WeightError a normalization can fail with (NumericError.h), and the streaming log-su...
One recorded prediction and its smoothed mixture, built from the history's allocator.
Definition GaussianMixtureHistory.h:260
SmoothedType smoothed
, a component per component of the joint, as of the last smooth(); the filtered mixture until then
Definition GaussianMixtureHistory.h:355
Step(Step const &)=default
copies the joint and the smoothed mixture
internal::Buffer< GainType, Allocator_ > gains
Each component's Rauch-Tung-Striebel gain, made once when the joint is recorded.
Definition GaussianMixtureHistory.h:358
typename GaussianParams< Space_, Scalar_ >::MatrixType GainType
One component's Rauch-Tung-Striebel gain.
Definition GaussianMixtureHistory.h:266
Step(Step &&other, Allocator_ const &allocator)
Moves other into storage from allocator, taking its storage when the allocators are equal.
Definition GaussianMixtureHistory.h:307
Step(JointType const &recorded, Allocator_ const &allocator={})
A copy of recorded in storage from allocator, with the filtered mixture as its smoothed one until smo...
Definition GaussianMixtureHistory.h:274
Step & operator=(Step const &)=default
Copies into this step's storage.
internal::ReBound< Allocator_, GainType > GainAllocator
The allocator of the gains.
Definition GaussianMixtureHistory.h:269
Step(Step &&)=default
moves the joint and the smoothed mixture
Step(JointType &&recorded, Allocator_ const &allocator={})
recorded moved into storage from allocator, with the filtered mixture as its smoothed one until smoot...
Definition GaussianMixtureHistory.h:287
Step(Step const &other, Allocator_ const &allocator)
Copies other into storage from allocator.
Definition GaussianMixtureHistory.h:298
void resetSmoothed()
Replaces the smoothed mixture with the filtered one: the joint's weights and each component's filtere...
Definition GaussianMixtureHistory.h:330
void computeGains()
Computes each component's gain from its joint (internal::rtsGain()), once per recording.
Definition GaussianMixtureHistory.h:341
Allocator_ allocator_type
the allocator its joint and mixture come from
Definition GaussianMixtureHistory.h:263
Step & operator=(Step &&)=default
Takes the other step's storage, as the members' do.
JointType joint
the prediction as predictJoint() recorded it
Definition GaussianMixtureHistory.h:350
The record of a Gaussian mixture filter's forward pass that its smoother runs backward over: one Gaus...
Definition GaussianMixtureHistory.h:248
GaussianMixtureHistory(Allocator_ const &allocator)
An empty history that keeps every step, with storage from allocator.
Definition GaussianMixtureHistory.h:401
GaussianMixtureHistory(GaussianMixtureHistory const &other, Allocator_ const &allocator)
Copies other's steps into storage from allocator.
Definition GaussianMixtureHistory.h:421
GaussianMixtureHistory & operator=(GaussianMixtureHistory const &other)=default
Copies other's steps and lag.
void smooth(P &&policy, GaussianMixtureParams< Space_, Scalar_, LatestAllocator > const &latest)
smooth() under policy: each backward step's pairs and merges are a for-each over the step's component...
Definition GaussianMixtureHistory.h:543
void push(JointType &&joint)
Records joint as the newest step, taking its storage unless the history is a full fixed-lag one,...
Definition GaussianMixtureHistory.h:521
Space_ SpaceType
the state space
Definition GaussianMixtureHistory.h:252
Eigen::Index Index
Eigen's index type.
Definition GaussianMixtureHistory.h:256
typename ListType::const_iterator const_iterator
iterates the steps, oldest first
Definition GaussianMixtureHistory.h:395
void push(JointType const &joint)
Records a copy of joint as the newest step; it must come from the predictJoint() after the newest ste...
Definition GaussianMixtureHistory.h:512
GaussianMixturePredictedJoint< Space_, Scalar_, Allocator_ > JointType
what each step records
Definition GaussianMixtureHistory.h:253
const_iterator begin() const
Definition GaussianMixtureHistory.h:495
Scalar_ Scalar
the scalar type
Definition GaussianMixtureHistory.h:251
std::optional< Index > lag() const
Definition GaussianMixtureHistory.h:458
GaussianMixtureHistory()=default
An empty history that keeps every step.
GaussianMixtureParams< Space_, Scalar_, Allocator_ > SmoothedType
the smoothed mixture's type
Definition GaussianMixtureHistory.h:254
GaussianMixtureHistory(GaussianMixtureHistory &&other, Allocator_ const &allocator)
Moves other's steps into storage from allocator, taking its storage when the allocators are equal.
Definition GaussianMixtureHistory.h:433
GaussianMixtureHistory & operator=(GaussianMixtureHistory &&other)=default
Takes other's steps and lag, as std::list's move assignment does.
Step const & back() const
Definition GaussianMixtureHistory.h:487
Index size() const
Definition GaussianMixtureHistory.h:465
Allocator_ allocator_type
the allocator the steps come from
Definition GaussianMixtureHistory.h:255
void clear()
Drops every step, keeping the lag.
Definition GaussianMixtureHistory.h:576
const_iterator end() const
Definition GaussianMixtureHistory.h:502
Step const & front() const
Definition GaussianMixtureHistory.h:479
GaussianMixtureHistory(GaussianMixtureHistory const &other)
Copies the steps into nodes from other's allocator (see Allocation).
Definition GaussianMixtureHistory.h:416
allocator_type get_allocator() const
Definition GaussianMixtureHistory.h:451
bool empty() const
Definition GaussianMixtureHistory.h:472
void smooth(GaussianMixtureParams< Space_, Scalar_, LatestAllocator > const &latest)
Fills every step's smoothed mixture by the backward step above, from the newest back,...
Definition GaussianMixtureHistory.h:533
GaussianMixtureHistory(GaussianMixtureHistory &&other)=default
Takes other's steps.
GaussianMixtureHistory(Lag lag, Allocator_ const &allocator={})
An empty history that keeps the newest lag steps, with storage from allocator.
Definition GaussianMixtureHistory.h:407
typename MomentsType::MatrixType MatrixType
a matrix over differences
Definition Gaussian.h:267
LineageType const & lineage() const
Definition Mixture.h:1119
void reserve(Index n)
Reserves room for n components without setting a capacity.
Definition Mixture.h:1080
MixtureParams< Gaussian< Space_, Scalar_ >, Allocator_ > GaussianMixtureParams
A Mixture of Gaussians in covariance form, the spelling for the common case (decisions....
Definition Mixture.h:2072
constexpr Sequential sequential
The default execution policy: plain loops on the calling thread, in index order (Sequential).
Definition Execution.h:128
CategoricalParams< Space, Scalar > smoothStep(CategoricalPredictedJoint< Space, Scalar > const &joint, CategoricalParams< Space, Scalar > const &smoothedNext)
Definition CategoricalHistory.h:114
One prediction of a mixture of Gaussians as its smoother needs it: the weights the step started from,...
Definition MixtureFilter.h:146
internal::Buffer< Scalar_, Allocator_ > LogWeightsType
Definition MixtureFilter.h:151
LineageType lineage
how the components descend from those of the previous record
Definition MixtureFilter.h:156
LogWeightsType logWeights
each component's log-weight before the step, as the state had it
Definition MixtureFilter.h:154
internal::Buffer< JointType, Allocator_ > JointsType
Definition MixtureFilter.h:150
MixtureLineage< Scalar_, Allocator_ > LineageType
Definition MixtureFilter.h:152
JointsType joints
one per component, in the state's order
Definition MixtureFilter.h:155
The number of steps a fixed-lag history keeps.
Definition Lag.h:17