EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Emrys::ParticleHistory< Space_, Scalar_, Allocator_ > Class Template Reference

The record of a particle filter's forward pass that ancestor tracing runs backward over: the particles at each step, how each descends from the step before, and room for the step's smoothed particles. More...

#include <EmrysFilter/Smoothers/ParticleHistory.h>

Classes

class  Step
 One recorded set of particles, its descent from the step before, and its smoothed set, built from the history's allocator. More...

Public Types

using Scalar = Scalar_
 the scalar type
using SpaceType = Space_
 the state space
using ParticleSetType = ParticleSet<Space_, Scalar_, Allocator_>
 what each step records
using allocator_type = Allocator_
 the allocator the steps come from
using Index = Eigen::Index
 Eigen's index type.
using const_iterator = typename ListType::const_iterator
 iterates the steps, oldest first

Public Member Functions

 ParticleHistory ()=default
 An empty history that keeps every step.
 ParticleHistory (Allocator_ const &allocator)
 An empty history that keeps every step, with storage from allocator.
 ParticleHistory (Lag lag, Allocator_ const &allocator={})
 An empty history that keeps the newest lag steps, with storage from allocator.
 ParticleHistory (ParticleHistory const &other)
 Copies the steps into nodes from other's allocator (see Allocation).
 ParticleHistory (ParticleHistory const &other, Allocator_ const &allocator)
 Copies other's steps into storage from allocator.
 ParticleHistory (ParticleHistory &&other)=default
 Takes other's steps.
 ParticleHistory (ParticleHistory &&other, Allocator_ const &allocator)
 Moves other's steps into storage from allocator, taking its storage when the allocators are equal.
ParticleHistory & operator= (ParticleHistory const &other)=default
 Copies other's steps and lag.
ParticleHistory & operator= (ParticleHistory &&other)=default
 Takes other's steps and lag, as std::list's move assignment does.
allocator_type get_allocator () const
std::optional< Index > lag () const
Index size () const
bool empty () const
Step const & front () const
Step const & back () const
const_iterator begin () const
const_iterator end () const
void push (ParticleSetType const &particles)
 Records particles, the filter's state before its next prediction, as the newest step, with their descent from the step before.
void smooth (ParticleSetType const &latest)
 Fills every step's smoothed set by ancestor tracing, from the newest back, given latest, the filter's particles after the newest step.
template<ExecutionPolicy P>
void smooth (P &&policy, ParticleSetType const &latest)
 smooth() under policy: each step's tracing and gather are for-eaches over the latest particles (see Execution policies), so the smoothed sets are Sequential's exactly.
void clear ()
 Drops every step, keeping the lag.

Detailed Description

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
class Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >

The record of a particle filter's forward pass that ancestor tracing runs backward over: the particles at each step, how each descends from the step before, and room for the step's smoothed particles.

The caller keeps it, outside the filter (decisions.md [smoothing]): push() records the filter's particles before each prediction, and smooth() takes its current particles and fills every step's smoothed set by following each current particle's genealogy back through the steps. Prediction and update keep each particle in its place, so the only change of lineage between two records is a resample, whose ancestors() the history takes when the set's resampleCount() says one happened. At most one resample may fall between two records, since ancestors() keeps only the last, and nothing else may renumber the particles there (ParticleSet::removeIf(), a prune, insertion, or erasure): each would break the genealogy without the history knowing.

auto window = ParticleHistory<State>{Lag{10}};
for (auto const & z : measurements)
{
window.push(filter.state());
filter.predict(rng, dt);
static_cast<void>(filter.update(fix(z)));
static_cast<void>(upkeep(filter.state(), rng));
window.smooth(filter.state());
use(window.front().smoothed.moments()); // x_{k-10|k}
}
ParticleHistory()=default
An empty history that keeps every step.
The number of steps a fixed-lag history keeps.
Definition Lag.h:17

Each step's smoothed set holds, as its particle j, the state at that step of the trajectory that ends in the current particle j, with the current particle's weight: a weighted sample of the smoothing distribution \( p(x_k \mid z_{1:N}) \), whose moments(), kernel density, and marginals are those of any ParticleSet. Read across the steps, particle j's states are its trajectory.

Ancestor tracing is the smoother of Kitagawa (1996), who stores each particle's path and resamples the paths with the particles. The departure is storage: this keeps each step's particles once and the indices that join them, and traces the paths when asked, which costs \( O(N L) \) index lookups and copies per smooth() rather than copying paths at every resample. Each resample keeps only some lineages, so going back the traced paths pass through fewer and fewer distinct particles and the smoothed sets lose their spread: it is a fixed-lag smoother, for a lag short enough that the paths have not yet collapsed. Backward simulation, which does not degenerate, needs the transition density and is not yet provided [smoothing].

As with GaussianHistory, a Lag keeps the newest steps and reuses the oldest step's node once full, copying the particles into its storage, so at a steady particle count fixed-lag smoothing allocates nothing once the window is full. Each step's sets and indices come from the history's allocator, by uses-allocator construction. The recorded sets are copies, so they carry no resample record of their own (see ParticleSet::resampleCount()).

Template Parameters
Space_the state space
Scalar_scalar type, double by default
Allocator_allocator for the steps, their particles, and the tracing scratch (see Allocation)
See also
ParticleFilter, ParticleSet::ancestors(), GaussianHistory, Smoothers

Member Function Documentation

◆ back()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Step const & Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::back ( ) const
inlinenodiscard
Returns
the newest step; the history must not be empty

◆ begin()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
const_iterator Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::begin ( ) const
inlinenodiscard
Returns
an iterator to the oldest step

◆ empty()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
bool Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::empty ( ) const
inlinenodiscard
Returns
whether no step is recorded

◆ end()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
const_iterator Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::end ( ) const
inlinenodiscard
Returns
an iterator past the newest step

◆ front()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Step const & Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::front ( ) const
inlinenodiscard
Returns
the oldest step kept; the history must not be empty

◆ get_allocator()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
allocator_type Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::get_allocator ( ) const
inlinenodiscard
Returns
the allocator the steps come from

◆ lag()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::optional< Index > Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::lag ( ) const
inlinenodiscard
Returns
the most steps a fixed-lag history keeps, or nothing if it keeps every step

◆ push()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
void Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::push ( ParticleSetType const & particles)
inline

Records particles, the filter's state before its next prediction, as the newest step, with their descent from the step before.

A full fixed-lag history drops its oldest step and reuses its node.

◆ size()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Index Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::size ( ) const
inlinenodiscard
Returns
the number of steps recorded, at most lag()

◆ smooth()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
void Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >::smooth ( ParticleSetType const & latest)
inline

Fills every step's smoothed set by ancestor tracing, from the newest back, given latest, the filter's particles after the newest step.

The smoothed sets store no bandwidth, so their kernel densities take Silverman's rule (see ParticleSet::kdeBandwidth()).


The documentation for this class was generated from the following file: