EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Emrys::upkeep::RepairCovariance< Repair_ > Struct Template Reference

Action that repairs every covariance of the state that is not positive definite, by the Repair Repair_ (roots::Ridge by default), so that its density can be read. More...

#include <EmrysFilter/Distributions/Upkeep.h>

Public Member Functions

template<typename State>
requires requires(State & state, Repair_ const & repair) { std::as_const(state).factorize(); state.factorize(repair); }
std::expected< bool, NumericError > operator() (State &state) const
 Repairs state's covariances that are not positive definite.

Public Attributes

Repair_ repair {}
 the repair, roots::ridge() by default

Detailed Description

template<Repair Repair_ = roots::Ridge<>>
struct Emrys::upkeep::RepairCovariance< Repair_ >

Action that repairs every covariance of the state that is not positive definite, by the Repair Repair_ (roots::Ridge by default), so that its density can be read.

A Kalman filter's covariance can lose positive definiteness by rounding, as the standard update \( P - K \Sigma_{xy}^T \) does when a measurement is far more precise than the prior: a prior variance of \( 10^6 \) and a fix of variance \( 10^{-12} \) leave a variance of exactly zero (decisions.md [covariance-update-forms]). The Joseph form avoids that in the update, at more cost per update; this action repairs the covariance afterward, whatever caused it. Applied to the filter's state() after the updates, it repairs as state.factorize(repair) does (decisions.md [covariance-repair]): it first factorizes without the repair, and if that succeeds it changes nothing and returns false; if it fails with GaussianError::NotPositiveDefinite, it factorizes again with the repair, which replaces each covariance that fails with the repaired matrix, and returns true. A repair changes the distribution, for roots::ridge() by the ridge on the diagonal, so a covariance that is positive definite is never touched. Called at every step, it costs one factorization when nothing fails, which the next read of the density reuses.

The state is anything with a const factorize() and a factorize(repair): a GaussianParams, the state of a KalmanFilter; a MixtureParams of Gaussians, the state of a MixtureFilter; or a HybridGaussianParams, the state of an ImmFilter. A mixture and a hybrid repair every component or none, so an error leaves the state as it was. The square-root form needs no repair, being positive semidefinite by construction, and refuses one at compile time; the information forms have no repair (decisions.md [gaussian-forms]).

Returns
whether a covariance was repaired; the GaussianError of the first factorization if it is not GaussianError::NotPositiveDefinite, as GaussianError::NonFinite is, with the state unchanged; the GaussianError of the repair, as roots::ridge() gives NotPositiveDefinite for a zero covariance, which roots::ridge<1.0, 1e-12>() repairs; or the WeightError of a mixture's or hybrid's weights. A mixture's error for a component comes back as its NumericError, without the index.
See also
Repair, roots::Ridge, GaussianParams::factorize(R const &)

Member Function Documentation

◆ operator()()

template<Repair Repair_ = roots::Ridge<>>
template<typename State>
requires requires(State & state, Repair_ const & repair) { std::as_const(state).factorize(); state.factorize(repair); }
std::expected< bool, NumericError > Emrys::upkeep::RepairCovariance< Repair_ >::operator() ( State & state) const
inlinenodiscard

Repairs state's covariances that are not positive definite.

Returns
whether it repaired one, or the NumericError that stopped it

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