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

A set of weighted samples: the empirical distribution. More...

#include <EmrysFilter/Distributions/ParticleSet.h>

Classes

class  MutableParticle
 Writable access to one particle during forEach(). More...

Public Types

using MomentsType = Moments<Space_, Scalar_>
 a mean and covariance together
using Scalar = typename MomentsType::Scalar
 the scalar type
using Index = typename MomentsType::Index
 Eigen's index type.
using VectorType = typename MomentsType::VectorType
 a value, such as a state
using DifferenceVectorType = typename MomentsType::DifferenceVectorType
 a difference
using MatrixType = typename MomentsType::MatrixType
 a matrix over differences, such as a bandwidth
using SampleSetType = SampleSet<Space_, Scalar_>
 A plain matrix of particle states as columns, laid out as states() is.
using StatesType = ConstSampleSetMap<Space_, Scalar_>
 The particle states as columns: a map over the set's storage.
using ConstStateType = Eigen::Block<StatesType const, SampleSetType::RowsAtCompileTime, 1, true>
 One particle's state: a column of states().
using WeightArrayType = Eigen::Array<Scalar, Eigen::Dynamic, 1>
 one entry per particle
using LogWeightsType = Eigen::Map<WeightArrayType const>
 The log-weights: a map over the set's storage.
using SpaceType = Space_
 the states' space
using allocator_type = Allocator_
 the allocator, re-bound per buffer
using DensityType = KernelDensity<Space_, Scalar_, Allocator_>
 the view toDensity() returns
template<bool ReturnRemovedWeight>
using RemovalResult = std::conditional_t<ReturnRemovedWeight, std::expected<Scalar, WeightError>, void>
 Result of removeIf(): the log of the removed fraction of the total weight, or nothing when ReturnRemovedWeight is false.

Public Member Functions

 ParticleSet (Allocator_ const &allocator)
 Constructs an empty set that allocates through allocator.
 ParticleSet (Capacity capacity, Allocator_ const &allocator={})
 Constructs an empty set in a FixedSizeSpace that reserves room for capacity particles.
 ParticleSet (Index valueDimension, Allocator_ const &allocator={})
 Constructs an empty set whose particles will have valueDimension coordinates.
template<typename StatesDerived>
requires internal::SizedByLength<Space_>
 ParticleSet (Eigen::MatrixBase< StatesDerived > const &states, Allocator_ const &allocator={})
 Constructs a set from the columns of states, with equal weights summing to one.
template<typename StatesDerived, typename WeightsDerived>
requires internal::SizedByLength<Space_>
 ParticleSet (Eigen::MatrixBase< StatesDerived > const &states, Eigen::DenseBase< WeightsDerived > const &logWeights, Allocator_ const &allocator={})
 Constructs a set from the columns of states with the log-weights logWeights.
 ParticleSet (Space_ space, Allocator_ const &allocator={})
 Constructs an empty set in space.
 ParticleSet (Space_ space, Capacity capacity, Allocator_ const &allocator={})
 Constructs an empty set in space that reserves room for capacity particles.
 ParticleSet (Space_ space, Index valueDimension, Allocator_ const &allocator={})
 Constructs an empty set in space whose particles will have valueDimension coordinates.
template<typename StatesDerived>
 ParticleSet (Space_ space, Eigen::MatrixBase< StatesDerived > const &states, Allocator_ const &allocator={})
 Constructs a set in space from the columns of states, with equal weights summing to one.
template<typename StatesDerived, typename WeightsDerived>
 ParticleSet (Space_ space, Eigen::MatrixBase< StatesDerived > const &states, Eigen::DenseBase< WeightsDerived > const &logWeights, Allocator_ const &allocator={})
 Constructs a set in space from the columns of states with the log-weights logWeights.
 ParticleSet (ParticleSet const &other)
 Copies the particles and any stored bandwidth into storage from other's allocator, with its capacity (see Allocation).
 ParticleSet (ParticleSet const &other, Allocator_ const &allocator)
 Copies the particles and any stored bandwidth into storage from allocator, with other's capacity and no resample record.
 ParticleSet (ParticleSet &&other) noexcept
 Takes other's particles and storage; a view of other may not be read afterward.
 ParticleSet (ParticleSet &&other, Allocator_ const &allocator)
 Moves other's particles into storage from allocator, taking its storage when the allocators are equal.
ParticleSet & operator= (ParticleSet const &other)
 Copies other's particles, weights, space, and bandwidth into this set's storage, which keeps its allocator and capacity, and clears its resample record, as a copy has none.
ParticleSet & operator= (ParticleSet &&other) noexcept
 Takes other's storage when the allocators are equal or propagate, otherwise copies into this set's storage, which keeps its capacity; either way it takes other's resample record.
allocator_type get_allocator () const
Index size () const
bool empty () const
std::optional< Index > capacity () const
void setCapacity (Index capacity)
 Reserves room for capacity particles, and for the scratch resample() uses, and makes holding more a precondition violation.
Index valueDimension () const
Index differenceDimension () const
Space_ const & space () const
StatesType states () const
LogWeightsType logWeights () const
ConstStateType state (Index i) const
Scalar logWeight (Index i) const
std::optional< MatrixType > const & bandwidth () const
std::expected< MatrixType, WeightError > kdeBandwidth () const
template<ExecutionPolicy P>
std::expected< MatrixType, WeightError > kdeBandwidth (P &&policy) const
 kdeBandwidth() under policy: Silverman's rule's total weight, effective sample size, and covariance are reductions over the particles (see Execution policies).
template<MatrixExpression Bandwidth>
void setBandwidth (Bandwidth &&bandwidth)
 Stores bandwidth as the kernel covariance.
void clearBandwidth ()
 Forgets the stored bandwidth, so kdeBandwidth() returns to Silverman's rule.
void resizeParticles (Index n)
 Resizes every particle state to n coordinates and clears the bandwidth.
template<typename Path, typename Derived>
void insert (Index element, Eigen::MatrixBase< Derived > const &states)
 Inserts the state entries states, one column per particle, into the resizable block named by the tag path Path, before its element element.
template<typename Path>
void erase (Index element, Index count=1)
 Removes count elements of the resizable block named by the tag path Path from every particle, starting at its element element.
void clear ()
 Removes every particle; the space, bandwidth, capacity, and scratch stay.
template<typename StatesDerived>
void assign (Eigen::MatrixBase< StatesDerived > const &states)
 Replaces the particles with the columns of states, with equal weights summing to one.
template<typename StatesDerived, typename WeightsDerived>
void assign (Eigen::MatrixBase< StatesDerived > const &states, Eigen::DenseBase< WeightsDerived > const &logWeights)
 Replaces the particles and weights.
template<typename Derived>
Index add (Scalar logWeight, Eigen::MatrixBase< Derived > const &state)
 Appends a particle.
template<typename OtherAllocator>
void append (ParticleSet< Space_, Scalar_, OtherAllocator > const &other)
 Appends copies of other's particles, which must be in the same space.
void remove (Index i)
 Removes particle i by moving the last particle into its place.
template<typename Derived>
void setState (Index i, Eigen::MatrixBase< Derived > const &state)
 Sets particle i's state, normalized by the space.
template<typename Derived>
void setStates (Eigen::MatrixBase< Derived > const &states)
 Sets every state at once.
void setLogWeight (Index i, Scalar logWeight)
 Sets particle i's log-weight.
template<typename Derived>
void setLogWeights (Eigen::DenseBase< Derived > const &logWeights)
 Sets every log-weight at once; logWeights has one entry per particle.
void scaleWeight (Index i, Scalar logScale)
 Multiplies the weight of particle i by \( e^{\mathrm{logScale}} \).
void scaleWeights (Scalar logScale)
 Multiplies every weight by \( e^{\mathrm{logScale}} \).
template<typename Derived>
void scaleWeights (Eigen::DenseBase< Derived > const &logScales)
 Multiplies weight i by \( e^{\mathrm{logScales}_i} \), e.g.
std::expected< Scalar, WeightError > logTotalWeight () const
template<ExecutionPolicy P>
std::expected< Scalar, WeightError > logTotalWeight (P &&policy) const
 logTotalWeight() under policy: a reduction over the particles (see Execution policies).
std::expected< void, WeightError > normalize ()
 Scales the weights so they sum to one.
template<ExecutionPolicy P>
std::expected< void, WeightError > normalize (P &&policy)
 normalize() under policy: the total is a reduction over the particles, and scaling the weights a whole-array operation (see Execution policies).
std::expected< WeightArrayType, WeightError > normalizedWeights () const
std::expected< Scalar, WeightError > ess () const
template<ExecutionPolicy P>
std::expected< Scalar, WeightError > ess (P &&policy) const
 ess() under policy: two reductions over the particles (see Execution policies).
std::expected< MomentsType, WeightError > moments () const
template<ExecutionPolicy P>
std::expected< MomentsType, WeightError > moments (P &&policy) const
 moments() under policy: reductions over the particles, which match Sequential's to rounding (see Execution policies).
template<typename F>
void forEach (F &&f)
 Calls f on each particle as a MutableParticle&, returning nothing; reweight() takes one that returns a log scale factor.
template<ExecutionPolicy P, typename F>
void forEach (P &&policy, F &&f)
 forEach() under policy, a for-each over the particles (see Execution policies).
template<typename F>
void reweight (F &&f)
 Calls f on each particle as a MutableParticle&, as forEach() does, and adds what it returns, a log scale factor in a floating-point type, to that particle's log-weight.
template<ExecutionPolicy P, typename F>
void reweight (P &&policy, F &&f)
 reweight() under policy, as forEach() under it runs.
template<bool ReturnRemovedWeight = false, typename Pred>
requires (!ReturnRemovedWeight && !ExecutionPolicy<Pred>)
void removeIf (Pred pred)
 Removes every particle for which pred(logWeight, state) is true.
template<bool ReturnRemovedWeight, typename Pred>
requires (ReturnRemovedWeight && !ExecutionPolicy<Pred>)
std::expected< Scalar, WeightError > removeIf (Pred pred)
 As above, returning the log of the removed fraction of the total weight, or the WeightError that left the set unchanged.
template<bool ReturnRemovedWeight = false, ExecutionPolicy P, typename Pred>
requires (!ReturnRemovedWeight)
void removeIf (P &&policy, Pred pred)
 removeIf() under policy: pred runs as a for-each over the particles, and the particles kept are compacted, in order, through the scratch (see Execution policies).
template<bool ReturnRemovedWeight, ExecutionPolicy P, typename Pred>
requires ReturnRemovedWeight
std::expected< Scalar, WeightError > removeIf (P &&policy, Pred pred)
 As above, returning the log of the removed fraction of the total weight, or the WeightError that left the set unchanged.
std::expected< Scalar, WeightError > pruneBelow (Scalar logThreshold)
 Removes every particle whose normalized log-weight is below logThreshold, and normalizes the weights of the rest; the heaviest particle is always kept, the first of them if several are.
std::expected< Scalar, WeightError > pruneTail (Scalar logFraction)
 Removes the lightest particles, as many as can be while their combined normalized weight stays below \( e^{\mathrm{logFraction}} \), and normalizes the weights of the rest.
std::expected< Scalar, WeightError > pruneToSize (Index maxSize)
 Removes the lightest particles until at most maxSize, at least one, remain, and normalizes the weights of the rest.
template<std::uniform_random_bit_generator G, typename R = resamplers::Systematic>
requires Resampler<R, Scalar, G>
std::expected< void, WeightError > resample (G &rng, Index newSize, R const &resampler={})
 Replaces the particles with newSize draws chosen by resampler in proportion to their weights, then sets every weight to \( 1/\mathrm{newSize} \).
template<std::uniform_random_bit_generator G, typename R = resamplers::Systematic>
requires Resampler<R, Scalar, G>
std::expected< void, WeightError > resample (G &rng, R const &resampler={})
 Resamples to the current size().
template<ExecutionPolicy P, std::uniform_random_bit_generator G, typename R = resamplers::Systematic>
requires Resampler<R, Scalar, G>
std::expected< void, WeightError > resample (P &&policy, G &rng, Index newSize, R const &resampler={})
 resample() under policy: the total weight is a reduction, the linear weights a whole-array expression on each chunk, the gather of the ancestors' states a for-each, and resampler runs under policy if it can (see ResamplerUnder), drawing from rng in the order the sequential form does.
template<ExecutionPolicy P, std::uniform_random_bit_generator G, typename R = resamplers::Systematic>
requires Resampler<R, Scalar, G>
std::expected< void, WeightError > resample (P &&policy, G &rng, R const &resampler={})
 resample() to the current size() under policy.
std::span< Index const > ancestors () const
Index resampleCount () const
template<typename Path>
auto marginal () const &
 marginal() of the subspace named by the tag path Path (see idx()), whose space is that subspace with its parameters.
template<typename Path>
void marginal () const &&=delete
 A marginal of a temporary would outlive it.
template<typename Path>
auto marginal (Index element) const &
 marginal() of one repetition of a repeated block; see GaussianParams::marginal(element).
template<typename Path>
void marginal (Index element) const &&=delete
 A marginal of a temporary would outlive it.
template<typename GivenPath, typename Derived>
auto conditional (Eigen::MatrixBase< Derived > const &values) const
std::expected< DensityType, NumericError > toDensity () const &
 Validates the weights and builds a kernel density estimate with kdeBandwidth(): the stored bandwidth if there is one, otherwise Silverman's rule.
void toDensity () const &&=delete
 A density of a temporary would outlive it.
template<MatrixExpression Bandwidth>
std::expected< DensityType, NumericError > toDensity (Bandwidth &&bandwidth) const &
 Validates the weights and builds a kernel density estimate with bandwidth bandwidth, of which only the lower triangle is read.
template<MatrixExpression Bandwidth>
void toDensity (Bandwidth &&bandwidth) const &&=delete
 A density of a temporary would outlive it.

Static Public Attributes

static constexpr int ValueDimensionAtCompileTime = MomentsType::ValueDimensionAtCompileTime
 the length of a state, or Eigen::Dynamic
static constexpr int MaxValueDimensionAtCompileTime = MomentsType::MaxValueDimensionAtCompileTime
 a bound on the length of a state, or Eigen::Dynamic
static constexpr int DifferenceDimensionAtCompileTime = MomentsType::DifferenceDimensionAtCompileTime
 the length of a difference and the rows of a bandwidth, or Eigen::Dynamic
static constexpr int MaxDifferenceDimensionAtCompileTime = MomentsType::MaxDifferenceDimensionAtCompileTime
 a bound on the length of a difference, or Eigen::Dynamic
static constexpr bool IsParams = true
 parameters, which views check

Detailed Description

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

A set of weighted samples: the empirical distribution.

\[ \hat p(x) = \sum_i \hat w_i \, \delta(x - x_i), \qquad \hat w_i = w_i / \textstyle\sum_j w_j. \]

The weighted particle approximation of Arulampalam et al. (2002), §II, kept as a matrix of states and an array of log-weights.

Particle states are the columns of states(), with valueDimension() rows; their log-weights are logWeights(). Both are maps over storage the set keeps through its allocator (see Allocation), valid until the set's particles are added, removed, or resized. Weights need not be normalized; a log-weight of -inf is a zero weight. Particles are addressed by index, and the set has no begin() and end(): loop over the indices, or call forEach(). Removal may reorder the remaining particles. Statistics that need normalized weights, such as moments(), return a WeightError if the weights cannot be normalized (see logTotalWeight()).

A set given a Capacity reserves room for that many particles once, along with the scratch that resample() uses, so that resampling and replacing particles at a steady size allocate nothing. Holding more particles than the capacity is a precondition violation.

A set may carry a kernel bandwidth: the shared covariance \( H \) of the Gaussian kernels in its kernel density estimate, with differenceDimension() rows. kdeBandwidth() is the stored bandwidth if there is one, and Silverman's rule otherwise. Conditionals store their exact bandwidth this way. resample() clears a stored bandwidth, since it describes the cloud before the draw; other changes of the states keep it, so it can go stale; call clearBandwidth() to return to Silverman's rule.

A set of weighted points has no density of its own, so toDensity() returns its kernel density estimate: it validates the weights, factorizes a bandwidth, and returns a KernelDensity, which checks this object for changes: reading it after this object has changed in any way is a programmer error caught by EMRYS_FILTER_ASSERT (decisions.md [view-stamp]). So is changing the set from inside a forEach() or removeIf() callback.

marginal() returns a read-only view of a subset of the state entries, which checks only this object's size and structure: states, weights, and bandwidth may change under it, but reading it after particles are added, removed, resampled, or resized, or this object is assigned to, is a programmer error. Neither view may outlive this object, and neither may be made from a temporary.

The space's size always matches the states'. insert() and erase() grow and shrink one resizable block of the space in place, and resizeParticles() resizes a space with a single resizable block.

Template Parameters
Space_space of the states, which sets their dimensions and storage bounds (see Spaces): states are normalized when stored, and moments are tangent-space moments
Scalar_scalar type, double by default
Allocator_allocator for the states, weights, and scratch (see Allocation)
See also
class KernelDensity, Resamplers

Constructor & Destructor Documentation

◆ ParticleSet() [1/3]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::ParticleSet ( Capacity capacity,
Allocator_ const & allocator = {} )
inlineexplicit

Constructs an empty set in a FixedSizeSpace that reserves room for capacity particles.

A space that holds values is given: ParticleSet(space, capacity, allocator).

◆ ParticleSet() [2/3]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::ParticleSet ( Space_ space,
Index valueDimension,
Allocator_ const & allocator = {} )
inline

Constructs an empty set in space whose particles will have valueDimension coordinates.

A space with one resizable block is resized to valueDimension; any other must already have that many.

◆ ParticleSet() [3/3]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::ParticleSet ( ParticleSet< Space_, Scalar_, Allocator_ > const & other)
inline

Copies the particles and any stored bandwidth into storage from other's allocator, with its capacity (see Allocation).

The copy has no resample record: it is a new set, which views of other do not see, so its resampleCount() is zero and its ancestors() empty.

Member Function Documentation

◆ add()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename Derived>
Index Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::add ( Scalar logWeight,
Eigen::MatrixBase< Derived > const & state )
inline

Appends a particle.

Without a capacity it may grow the storage, which costs O(size()).

Returns
the index of the new particle

◆ ancestors()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::span< Index const > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::ancestors ( ) const
inlinenodiscard
Returns
the ancestor indices chosen by the last successful resample(): particle j became a copy of the particle at ancestors()[j] before it

◆ assign() [1/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename StatesDerived>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::assign ( Eigen::MatrixBase< StatesDerived > const & states)
inline

Replaces the particles with the columns of states, with equal weights summing to one.

Clears the bandwidth if the number of coordinates changes.

◆ assign() [2/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename StatesDerived, typename WeightsDerived>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::assign ( Eigen::MatrixBase< StatesDerived > const & states,
Eigen::DenseBase< WeightsDerived > const & logWeights )
inline

Replaces the particles and weights.

Clears the bandwidth if the number of coordinates changes.

◆ bandwidth()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::optional< MatrixType > const & Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::bandwidth ( ) const
inlinenodiscard
Returns
the stored kernel bandwidth, if any

◆ capacity()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::optional< Index > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::capacity ( ) const
inlinenodiscard
Returns
the most particles the set holds without growing its storage, if it has a capacity

◆ conditional()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename GivenPath, typename Derived>
auto Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::conditional ( Eigen::MatrixBase< Derived > const & values) const
inlinenodiscard
Returns
a copy of the kernel density estimate's distribution of the other coordinates given that the subspace named by the path GivenPath equals values, in the space of the remaining blocks (see GaussianParams::conditional()), with this set's allocator.

Uses kdeBandwidth(). The conditional of a Gaussian KDE is again a Gaussian KDE: each center becomes \( x_{a,i} \boxplus K (v \boxminus x_{b,i}) \), each weight gains \( \mathcal{N}(v; x_{b,i}, H_{bb}) \), and the shared bandwidth becomes \( H_{aa} - K H_{ba} \), with \( K = H_{ab} H_{bb}^{-1} \). The weights are not normalized, and the result stores the exact conditional bandwidth, so a KDE built from it with its stored bandwidth reproduces this conditional; Silverman's rule would re-smooth it.

Returns
the conditional set, or GaussianError::NotPositiveDefinite if \( H_{bb} \) is not positive definite, as Silverman's rule makes it for particles that coincide in the given block (decisions.md [innovation-cholesky]), or GaussianError::NonFinite if no bandwidth is stored and the weights cannot be normalized

◆ differenceDimension()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Index Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::differenceDimension ( ) const
inlinenodiscard
Returns
the number of rows and columns of a bandwidth or covariance (see Spaces)

◆ empty()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
bool Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::empty ( ) const
inlinenodiscard
Returns
whether there are no particles

◆ erase()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename Path>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::erase ( Index element,
Index count = 1 )
inline

Removes count elements of the resizable block named by the tag path Path from every particle, starting at its element element.

A stored bandwidth is marginalized, which keeps the kernel density estimate exact.

◆ ess()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< Scalar, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::ess ( ) const
inlinenodiscard
Returns
the effective sample size \( 1 / \sum_i \hat w_i^2 \), between 1 and size(), or a WeightError if the weights cannot be normalized; see internal::ess() for its source

◆ forEach() [1/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename F>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::forEach ( F && f)
inline

Calls f on each particle as a MutableParticle&, returning nothing; reweight() takes one that returns a log scale factor.

f may modify the particle it is given but not the set, which is a programmer error caught when f returns. Views of the set may not be read afterward.

◆ forEach() [2/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<ExecutionPolicy P, typename F>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::forEach ( P && policy,
F && f )
inline

forEach() under policy, a for-each over the particles (see Execution policies).

Under a parallel policy f runs for several particles at once, so it must read and write nothing but the particle it is given and what no other call writes.

◆ get_allocator()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
allocator_type Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::get_allocator ( ) const
inlinenodiscard
Returns
the allocator the set's storage comes from

◆ insert()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename Path, typename Derived>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::insert ( Index element,
Eigen::MatrixBase< Derived > const & states )
inline

Inserts the state entries states, one column per particle, into the resizable block named by the tag path Path, before its element element.

The space's block grows to match. A stored bandwidth no longer fits and is cleared, so kdeBandwidth() returns to Silverman's rule. See GaussianParams::insert() for what an element is.

◆ kdeBandwidth()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< MatrixType, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::kdeBandwidth ( ) const
inlinenodiscard
Returns
the bandwidth a kernel density estimate uses: the stored bandwidth, or Silverman's rule if none is stored, which fails with a WeightError if the weights cannot be normalized

◆ logTotalWeight()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< Scalar, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::logTotalWeight ( ) const
inlinenodiscard
Returns
the log of the sum of the weights, or a WeightError if the set is empty, the weights sum to zero, or a log-weight is NaN or +inf.

After normalize(), resample(), or a ParticleFilter update, and until the weights next change, it is zero, the total those scaled the weights to, without the rounding that summing them again would add; the operations that need the total, such as ess() and moments(), read that rather than taking a pass over the weights.

◆ logWeight()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Scalar Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::logWeight ( Index i) const
inlinenodiscard
Returns
particle i's log-weight

◆ logWeights()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
LogWeightsType Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::logWeights ( ) const
inlinenodiscard
Returns
the particles' log-weights

◆ moments()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< MomentsType, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::moments ( ) const
inlinenodiscard
Returns
the weighted mean and covariance, \( \mu = \sum_i \hat w_i x_i \) and \( \Sigma = \sum_i \hat w_i (x_i - \mu)(x_i - \mu)^T \), or a WeightError if the weights cannot be normalized.

The covariance is the plain weighted (biased) estimate and is exactly symmetric. It excludes any kernel bandwidth; see KernelDensity::moments() for that. In a non-linear space these are tangent-space moments.

◆ normalize()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< void, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::normalize ( )
inlinenodiscard

Scales the weights so they sum to one.

On failure the weights are unchanged.

See also
logTotalWeight()

◆ normalizedWeights()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< WeightArrayType, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::normalizedWeights ( ) const
inlinenodiscard
Returns
the normalized linear weights \( \hat w_i \), or a WeightError if the weights cannot be normalized

◆ operator=()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
ParticleSet & Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::operator= ( ParticleSet< Space_, Scalar_, Allocator_ > && other)
inlinenoexcept

Takes other's storage when the allocators are equal or propagate, otherwise copies into this set's storage, which keeps its capacity; either way it takes other's resample record.

A view of either object may not be read afterward.

◆ pruneBelow()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< Scalar, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::pruneBelow ( Scalar logThreshold)
inlinenodiscard

Removes every particle whose normalized log-weight is below logThreshold, and normalizes the weights of the rest; the heaviest particle is always kept, the first of them if several are.

The threshold is absolute: a caller who wants it relative to something, such as the heaviest particle, makes it so. The particles keep their order, and a stored bandwidth is kept, as removeIf() keeps it. upkeep::pruneBelow() calls it.

Returns
the log of the removed fraction of the total weight, -inf if nothing was removed, or, with nothing changed, the WeightError of logTotalWeight()
See also
pruneTail(), pruneToSize()

◆ pruneTail()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< Scalar, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::pruneTail ( Scalar logFraction)
inlinenodiscard

Removes the lightest particles, as many as can be while their combined normalized weight stays below \( e^{\mathrm{logFraction}} \), and normalizes the weights of the rest.

The fraction is below one, so a particle is always kept. Of particles equally heavy, those later in order go first. upkeep::pruneTail() calls it.

Returns
the log of the removed fraction of the total weight, -inf if nothing was removed, or, with nothing changed, the WeightError of logTotalWeight()
See also
pruneBelow(), pruneToSize()

◆ pruneToSize()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< Scalar, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::pruneToSize ( Index maxSize)
inlinenodiscard

Removes the lightest particles until at most maxSize, at least one, remain, and normalizes the weights of the rest.

Of particles equally heavy, as after a resample, those later in order go first. upkeep::pruneToSize() calls it.

Returns
the log of the removed fraction of the total weight, -inf if nothing was removed, or, with nothing changed, the WeightError of logTotalWeight()
See also
pruneBelow(), pruneTail()

◆ removeIf() [1/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<bool ReturnRemovedWeight = false, ExecutionPolicy P, typename Pred>
requires (!ReturnRemovedWeight)
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::removeIf ( P && policy,
Pred pred )
inline

removeIf() under policy: pred runs as a for-each over the particles, and the particles kept are compacted, in order, through the scratch (see Execution policies).

The particles left are Sequential's; the removed weight matches it to rounding. Under a parallel policy pred runs for several particles at once, so it must not write shared state.

◆ removeIf() [2/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<bool ReturnRemovedWeight = false, typename Pred>
requires (!ReturnRemovedWeight && !ExecutionPolicy<Pred>)
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::removeIf ( Pred pred)
inline

Removes every particle for which pred(logWeight, state) is true.

Template Parameters
ReturnRemovedWeightif true, returns the log of the removed fraction of the total weight. This requires normalizing the weights; if that fails, nothing is removed and the WeightError is returned.

◆ resample() [1/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<std::uniform_random_bit_generator G, typename R = resamplers::Systematic>
requires Resampler<R, Scalar, G>
std::expected< void, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::resample ( G & rng,
Index newSize,
R const & resampler = {} )
inlinenodiscard

Replaces the particles with newSize draws chosen by resampler in proportion to their weights, then sets every weight to \( 1/\mathrm{newSize} \).

A stored bandwidth is cleared, since it describes the particles before the draw.

rng is used only during this call. Scratch storage is kept between calls, and passed to a resampler that takes it (ResamplerWithScratch), so repeated resampling at a steady size does not allocate.

Returns
nothing on success, or a WeightError (with the set unchanged) if the weights cannot be normalized.
See also
Resamplers

◆ resample() [2/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<ExecutionPolicy P, std::uniform_random_bit_generator G, typename R = resamplers::Systematic>
requires Resampler<R, Scalar, G>
std::expected< void, WeightError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::resample ( P && policy,
G & rng,
Index newSize,
R const & resampler = {} )
inlinenodiscard

resample() under policy: the total weight is a reduction, the linear weights a whole-array expression on each chunk, the gather of the ancestors' states a for-each, and resampler runs under policy if it can (see ResamplerUnder), drawing from rng in the order the sequential form does.

Its ancestors may differ from Sequential's by rounding (see Resamplers).

◆ resampleCount()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Index Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::resampleCount ( ) const
inlinenodiscard
Returns
how many times resample() has succeeded on this set, including on the sets it was moved from (a copy starts at zero). An observer that saw an earlier count can tell from it whether ancestors() is new since then, as ParticleHistory does (decisions.md [smoothing]).

◆ resizeParticles()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::resizeParticles ( Index n)
inline

Resizes every particle state to n coordinates and clears the bandwidth.

States are unspecified afterward. A space with several resizable blocks grows and shrinks through insert() and erase() instead.

◆ scaleWeights()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename Derived>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::scaleWeights ( Eigen::DenseBase< Derived > const & logScales)
inline

Multiplies weight i by \( e^{\mathrm{logScales}_i} \), e.g.

by per-particle likelihoods.

◆ setBandwidth()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<MatrixExpression Bandwidth>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::setBandwidth ( Bandwidth && bandwidth)
inline

Stores bandwidth as the kernel covariance.

Only its lower triangle is read.

◆ setCapacity()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::setCapacity ( Index capacity)
inline

Reserves room for capacity particles, and for the scratch resample() uses, and makes holding more a precondition violation.

It must be at least size().

◆ setStates()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<typename Derived>
void Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::setStates ( Eigen::MatrixBase< Derived > const & states)
inline

Sets every state at once.

states must have the current dimensions.

◆ size()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Index Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::size ( ) const
inlinenodiscard
Returns
the number of particles

◆ space()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Space_ const & Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::space ( ) const
inlinenodiscard
Returns
the states' space, with its sizes

◆ state()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
ConstStateType Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::state ( Index i) const
inlinenodiscard
Returns
particle i's state, a column of states()

◆ states()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
StatesType Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::states ( ) const
inlinenodiscard
Returns
the particle states, one per column

◆ toDensity() [1/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
std::expected< DensityType, NumericError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::toDensity ( ) const &
inlinenodiscard

Validates the weights and builds a kernel density estimate with kdeBandwidth(): the stored bandwidth if there is one, otherwise Silverman's rule.

A conditional stores its exact bandwidth, so its density is exact.

Returns
a KernelDensity that checks this object, or a NumericError if the weights cannot be normalized or the bandwidth is not positive definite (for example, Silverman's rule when every particle has the same state).

◆ toDensity() [2/2]

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
template<MatrixExpression Bandwidth>
std::expected< DensityType, NumericError > Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::toDensity ( Bandwidth && bandwidth) const &
inlinenodiscard

Validates the weights and builds a kernel density estimate with bandwidth bandwidth, of which only the lower triangle is read.

Returns
a KernelDensity that checks this object, or a NumericError if the weights cannot be normalized or bandwidth is not positive definite.

◆ valueDimension()

template<Space Space_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
Index Emrys::ParticleSet< Space_, Scalar_, Allocator_ >::valueDimension ( ) const
inlinenodiscard
Returns
the number of coordinates of every particle state (see Spaces)

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