EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Spaces

The second layer (decisions.md [layered-headers]): where values live. More...

Topics

 Discrete spaces
 A discrete space is a finite set of values, such as a maneuver regime, a sensor's inlier/outlier state, or the cells of a grid.

Concepts

concept  Emrys::Space
 A type usable as the space of a distribution.
concept  Emrys::FixedSizeSpace
 A space whose instance holds nothing, so that S{} is the only one there is: a space of fixed size, continuous or discrete, which is an empty type (decisions.md [space-storage]).
concept  Emrys::PathValue
 A path given as a value: a TagPath, such as path<Ownship, Position>, or a tag's own value, such as Position{}, which is a path of one tag.

Classes

class  Emrys::Composite< Blocks >
 The concatenation of Blocks, any number of them resizable. More...
class  Emrys::Repeated< Block, MaxCount_ >
 A fixed-size Block repeated count() times, up to MaxCount_, such as one block per vehicle. More...
struct  Emrys::Linear< Dimension_, MaxDimension_ >
 Dimension_ plain coordinates, or a resizable run of at most MaxDimension_ of them if Dimension_ is Eigen::Dynamic. More...
struct  Emrys::PeriodicInterval
 Where a Periodic coordinate's values lie: the half-open interval [lower, upper), whose width is the period. More...
class  Emrys::Periodic< Interval, Dimension_, MaxDimension_ >
 Dimension_ coordinates that wrap with a common period, such as angles or DFT bins. More...
struct  Emrys::TagPath< Tags >
 A path of tags, each naming a block inside the one before: TagPath<Ownship, Position> is the Position block of Ownship. More...
struct  Emrys::TagPaths< Paths >
 A list of tag paths, each a tag or a TagPath, such as the blocks a measurement reads (TagPaths<Position, TagPath<Sensor, Bias>>). More...
struct  Emrys::BlockRows
 Rows of a contiguous block of a space. More...
struct  Emrys::UnitQuaternion
 An attitude: a unit quaternion of four coordinates whose differences are three-coordinate rotation vectors in the body frame. More...

Typedefs

template<int Dimension = 1, int MaxDimension = Dimension>
using Emrys::RadiansPi
 Dimension angles in radians, in [-π, π).
template<int Dimension = 1, int MaxDimension = Dimension>
using Emrys::Radians2Pi = Periodic<PeriodicInterval{.lower = 0.0, .upper = 2 * std::numbers::pi}, Dimension, MaxDimension>
 Dimension angles in radians, in [0, 2π).
template<int Dimension = 1, int MaxDimension = Dimension>
using Emrys::Degrees180 = Periodic<PeriodicInterval{.lower = -180.0, .upper = 180.0}, Dimension, MaxDimension>
 Dimension angles in degrees, in [-180, 180).
template<int Dimension = 1, int MaxDimension = Dimension>
using Emrys::Degrees360 = Periodic<PeriodicInterval{.lower = 0.0, .upper = 360.0}, Dimension, MaxDimension>
 Dimension angles in degrees, in [0, 360), such as a compass heading.
template<Space S>
using Emrys::DifferenceSpace = typename internal::DifferenceSpaceOf<S>::type
 The space that differences of values in S live in: the type of its difference(), or S itself if it has none, as a space written from scratch may not.
template<Space S, typename Scalar = double>
using Emrys::ValueVector
 A value in S as an Eigen column vector of Scalar: a mean, a sample, or a true state.
template<Space S, typename Scalar = double>
using Emrys::DifferenceVector = ValueVector<DifferenceSpace<S>, Scalar>
 A difference in S as an Eigen column vector of Scalar, the type of minus() and of the offset plus() takes: a residual, an estimation error, a step, or the variances on a covariance's diagonal.
template<Space Rows, Space Cols = Rows, typename Scalar = double>
using Emrys::DifferenceMatrix
 An Eigen matrix of Scalar over the differences of Rows and Cols: a covariance, with one space for both (DifferenceMatrix<State>), or a Jacobian, a gain, or a linear model's matrix, from Cols's differences to Rows's (DifferenceMatrix<Fix, State>).

Functions

template<Space S, typename XDerived, typename DDerived>
auto Emrys::resetJacobian (S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
template<Space S, typename XDerived, typename DDerived, typename CovDerived>
void Emrys::resetCovariance (S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d, Eigen::MatrixBase< CovDerived > const &cov)
 Carries the covariance cov from the tangent space at x to the one at \( x \boxplus d \), in place: \( P \leftarrow G P G^T \), with \( G \) the reset Jacobian of resetJacobian() (decisions.md [covariance-reset]).
template<Space S>
DifferenceSpace< S > Emrys::differenceSpace (S const &space)
template<Space S>
Eigen::Index Emrys::valueDimension (S const &space)
template<Space S>
Eigen::Index Emrys::differenceDimension (S const &space)
template<Space S, typename Derived>
void Emrys::normalizeValues (S const &space, Eigen::MatrixBase< Derived > const &block)
 Brings the values in block (rows are space's coordinates, columns samples) into canonical form, writing through the const reference as the space's normalize() does: for values that come from outside, such as a user's mean or a model's output.
template<Space S, typename Derived>
void Emrys::normalizeDifferences (S const &space, Eigen::MatrixBase< Derived > const &block)
 Brings the differences in block into canonical form: normalizeValues() in the difference space of space, for differences that come from outside.
template<FixedSizeSpace S, typename Derived>
requires Space<S>
void Emrys::normalizeValues (Eigen::MatrixBase< Derived > const &block)
 normalizeValues() in the fixed-size space S, given as a template argument: normalizeValues<State>(block).
template<FixedSizeSpace S, typename Derived>
requires Space<S>
void Emrys::normalizeDifferences (Eigen::MatrixBase< Derived > const &block)
 normalizeDifferences() in the fixed-size space S, given as a template argument: normalizeDifferences<State>(block).
template<typename Derived>
Eigen::MatrixBase< Derived > & Emrys::writable (Eigen::MatrixBase< Derived > const &block)
 block, writable: Eigen's idiom for a function that writes through an expression passed as const&.
template<Space S, typename XDerived, typename DDerived>
auto Emrys::plus (S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
template<Space S, typename ADerived, typename BDerived>
auto Emrys::minus (S const &space, Eigen::MatrixBase< ADerived > const &a, Eigen::MatrixBase< BDerived > const &b)
template<Space S, typename XDerived, typename DDerived>
auto Emrys::less (S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
template<FixedSizeSpace S, typename XDerived, typename DDerived>
requires Space<S>
auto Emrys::plus (Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
template<FixedSizeSpace S, typename ADerived, typename BDerived>
requires Space<S>
auto Emrys::minus (Eigen::MatrixBase< ADerived > const &a, Eigen::MatrixBase< BDerived > const &b)
template<FixedSizeSpace S, typename XDerived, typename DDerived>
requires Space<S>
auto Emrys::less (Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
template<typename Space>
constexpr bool Emrys::allowsValueDimension (Eigen::Index n)
template<typename Path, typename X>
requires (!internal::PlacesModel<X>)
internal::OnPath< typename internal::HeldOf< X >::type, Path > Emrys::on (X x)
template<typename Path = internal::WholeSpace, typename X>
requires (!internal::PlacesModel<X>)
internal::OnEach< typename internal::HeldOf< X >::type, Path > Emrys::onEach (X x)
template<Space S, typename Path>
constexpr auto Emrys::idx ()
template<Space S, typename Path>
constexpr auto Emrys::diffIdx ()
 idx<S, Path>() of the differences of the subspace named by Path: its rows of a covariance.
template<typename Path>
auto Emrys::idx (Space auto const &space)
template<typename Path>
auto Emrys::diffIdx (Space auto const &space)
 idx<Path>(space) of the differences of the subspace named by Path: its rows of a covariance.
template<typename Path>
auto Emrys::idx (Space auto const &space, Eigen::Index element)
template<typename Path>
auto Emrys::diffIdx (Space auto const &space, Eigen::Index element)
 idx<Path>(space, element) of the differences of one repetition: its rows of a covariance.
template<Space S, typename Path>
auto Emrys::idx (Eigen::Index element)
 idx<Path>(space, element) for the space type S, without a space object.
template<Space S, typename Path>
auto Emrys::diffIdx (Eigen::Index element)
 idx<S, Path>(element) of the differences of one repetition.
template<typename Path, MatrixExpression X>
auto Emrys::block (Space auto const &space, X &&x)
template<typename Path, MatrixExpression X>
auto Emrys::block (Space auto const &space, X &&x, Eigen::Index element)
template<FixedSizeSpace S, typename Path, MatrixExpression X>
requires Space<S>
auto Emrys::block (X &&x)
template<typename Path, MatrixExpression D>
auto Emrys::diffBlock (Space auto const &space, D &&d)
template<typename Path, MatrixExpression D>
auto Emrys::diffBlock (Space auto const &space, D &&d, Eigen::Index element)
template<FixedSizeSpace S, typename Path, MatrixExpression D>
requires Space<S>
auto Emrys::diffBlock (D &&d)
template<typename Row, typename Column, MatrixExpression M>
auto Emrys::diffBlock (Space auto const &rowSpace, Space auto const &columnSpace, M &&m)
template<typename Row, typename Column, MatrixExpression M>
auto Emrys::diffBlock (Space auto const &space, M &&m)
template<FixedSizeSpace S, typename Row, typename Column, MatrixExpression M>
requires Space<S>
auto Emrys::diffBlock (M &&m)
template<typename Scalar, Space S>
ValueVector< S, Scalar > Emrys::zeros (S const &space)

Variables

template<typename S>
constexpr bool Emrys::hasIdentityReset = internal::identityResetOf<S>()
 Whether the reset Jacobian of S is the identity, so that a covariance needs no change when its mean moves (decisions.md [covariance-reset]).
template<typename Space>
constexpr int Emrys::valueDimensionAtCompileTime
 The value dimension of Space at compile time, or Eigen::Dynamic if it is resizable.
template<typename Space>
constexpr int Emrys::maxValueDimensionAtCompileTime
 The largest valid value dimension of Space, or Eigen::Dynamic if it is unbounded.
template<Space S>
constexpr bool Emrys::hasPlainValues = !internal::HasNormalize<S> && !internal::HasPlus<S>
 Whether the values of S are plain: it has neither normalize() nor plus(), so \( x \boxplus \delta \) is x + δ.
template<Space S>
constexpr bool Emrys::hasPlainDifferences
 Whether the differences of S are plain: its difference space has no normalize(), and it has neither plus() nor minus(), so \( a \boxminus b \) is a - b and \( x \boxplus \delta \) is x + δ up to normalize().
template<Space S>
constexpr bool Emrys::isLinear = hasPlainValues<S> && hasPlainDifferences<S>
 Whether S is linear: its values and its differences are both plain vectors.
template<typename... Tags>
constexpr TagPath< Tags... > Emrys::path {}
 The path TagPath<Tags...> as a value, for a call that takes its paths as arguments rather than as template arguments: reads(path<Position>, path<Ownship, Velocity>).

Detailed Description

The second layer (decisions.md [layered-headers]): where values live.

A continuous space says how long its values and differences are and how to add and subtract them (Space.h, [sizes-and-dimensions]). Its coordinate types are Linear and Periodic (Coordinates.h, [no-bounded-coordinates]), Composite and Repeated build spaces from spaces (Composite.h, [several-resizable-blocks]), tag paths name their blocks and idx() and block() index them (TagPath.h, [index-names]), and Subspace.h builds the space a path names and grows and shrinks blocks; a discrete space is a finite set of named values (Discrete.h, [discrete-spaces]); Reset.h carries a covariance to the tangent space at a moved mean [covariance-reset]; UnitQuaternion.h is an attitude stored as Eigen stores a quaternion [unit-quaternion]; and Indexing.h holds what marginals and conditionals by path are built from. Read Space.h first.

A space describes how the coordinates of a vector behave: whether they wrap or are plain linear values, and how many there are. Every distribution type, and Moments and SampleSet, is parameterized by a space and then a scalar, which defaults to double (GaussianParams<State>), and takes its size and storage bound from the space. A fixed-size space is an empty type and costs nothing. A plain vector of dimension N is Linear<N>, so GaussianParams<Linear<3>> is a Gaussian on a 3-vector.

Values and differences each live in a space. A space whose values need bringing into canonical form has a normalize() member, applied to blocks whose rows are its coordinates and whose columns are samples. Its differences live in its difference space, from difference(), which is another space: an angle in [0, 360) has differences in [-180, 180), and a Linear coordinate's differences are plain vectors. The library works with them through four free functions, which do nothing where there is nothing to do:

  • plus() applies an update, \( x \boxplus \delta \), by default normalizeValues(space, x + δ);
  • minus() takes a residual, \( a \boxminus b \), by default normalizeDifferences(space, a - b);
  • normalizeValues() and normalizeDifferences() bring a value or a difference that came from outside, such as a user's mean or a model's output, into canonical form. A space whose updates and residuals aren't addition and subtraction, such as latitude and longitude with differences in meters, defines its own plus() and minus() members. A space is linear when none of this does anything (isLinear<>).

The coordinate types are Linear and Periodic. Their parameters are template arguments, so a fixed-size coordinate type is always an empty type, and the common periods are named: RadiansPi, Radians2Pi, Degrees180, and Degrees360. There is no bounded coordinate type [no-bounded-coordinates]: a quantity that can't be negative is estimated as the vector it is the length of, or as a log, and a distribution that has a bounded support, such as Gamma, states it itself.

Spaces compose: Composite concatenates them, and Repeated repeats a fixed-size block a runtime number of times. Named subspaces are tag types derived from a space (struct Heading : Degrees360<> {};).

A space's valueDimension() is the number of coordinates of a value. Its differences may have fewer, as a unit quaternion's four coordinates have three-coordinate rotation vectors as differences, so a distribution has two dimensions: valueDimension(), the length of a mean or a sample, and differenceDimension(), the rows of a covariance and the degrees of freedom. Generic code calls the free functions valueDimension(space) and differenceDimension(space); a space implements only the member valueDimension(), and its difference dimension is its difference space's [sizes-and-dimensions]. A fixed-size space is an empty type whose value dimension is a compile-time constant. A resizable space (a Repeated block, a coordinate type with Eigen::Dynamic dimension, or a Composite with one) stores its value dimension. Any number of a Composite's blocks may be resizable, at any depth of nested composites, such as a set of tracks and a set of landmarks. Distributions keep their space's value dimension in step with their data, and grow or shrink each resizable block in place with insert() and erase().

A space with at most one resizable block can take its sizes from a length alone, so it has resize(n), and a distribution can be built in it from a mean without a space. A space with several can't: the same length splits among the blocks in more than one way. A distribution in one is built from a space that carries its counts, and the space is grown block by block.

idx<Path>(space) turns a path (a tag or a TagPath) into an Eigen index set from the space's sizes. idx<S, Path>() gives the same index as a compile-time constant. Model code reads and writes the block a path names with block<Path>(space, x) on a vector of values, or a matrix whose columns are values, and diffBlock<Path>(space, d) on one of differences, each Eigen's block with the rows the space's type fixes, and the sizes checked against the space; diffBlock<Row, Column>(rows, columns, m) is a block of a covariance or a Jacobian, and zeros() the vector such code fills block by block. Where a call takes paths as arguments, a path is the value path<Ownship, Position> (decisions.md [tag-addressing]).

Every space exposes FixedValueDimension (the coordinates of its fixed part), ValueDimensionStep (nonzero if it is resizable: the coordinates of one element of its resizable part), and MaxValueDimension (the largest valid value dimension, or Eigen::Dynamic if unbounded). Like Eigen's matrices, the coordinate types take a dimension and a maximum dimension, and Repeated takes a maximum number of repetitions. Distributions use the space's MaxValueDimension as their storage bound, so a capped space gets fixed-capacity storage.

The \( \boxplus \) and \( \boxminus \) operators, and the idea of writing an estimator once over any state space that provides them, are those of Hertzberg, Wagner, Frese, and Schröder (2013); a Periodic coordinate is the circle \( S^1 \) of their examples. See also directional statistics for why a mean of angles is not the mean of their values.

Read Distributions next.

Typedef Documentation

◆ DifferenceMatrix

template<Space Rows, Space Cols = Rows, typename Scalar = double>
using Emrys::DifferenceMatrix
Initial value:
internal::MatrixOf<
Scalar,
constexpr int valueDimensionAtCompileTime
The value dimension of Space at compile time, or Eigen::Dynamic if it is resizable.
Definition Space.h:251
constexpr int maxValueDimensionAtCompileTime
The largest valid value dimension of Space, or Eigen::Dynamic if it is unbounded.
Definition Space.h:258

An Eigen matrix of Scalar over the differences of Rows and Cols: a covariance, with one space for both (DifferenceMatrix<State>), or a Jacobian, a gain, or a linear model's matrix, from Cols's differences to Rows's (DifferenceMatrix<Fix, State>).

A single row is stored row-major, as Eigen requires.

◆ DifferenceSpace

template<Space S>
using Emrys::DifferenceSpace = typename internal::DifferenceSpaceOf<S>::type

The space that differences of values in S live in: the type of its difference(), or S itself if it has none, as a space written from scratch may not.

The library's spaces all have one, and it carries no tag: DifferenceSpace<Gyro> is Linear<1> for a tag struct Gyro : Linear<1> {};, so a block that is a difference of another quantity, such as a sensor's bias, is declared in it: struct Bias : DifferenceSpace<Gyro> {};.

◆ DifferenceVector

template<Space S, typename Scalar = double>
using Emrys::DifferenceVector = ValueVector<DifferenceSpace<S>, Scalar>

A difference in S as an Eigen column vector of Scalar, the type of minus() and of the offset plus() takes: a residual, an estimation error, a step, or the variances on a covariance's diagonal.

It is a value in DifferenceSpace<S>, so it has fewer rows than a ValueVector where the space's differences are smaller, as a unit quaternion's 3 are than its 4 coordinates.

◆ RadiansPi

template<int Dimension = 1, int MaxDimension = Dimension>
using Emrys::RadiansPi
Initial value:
Periodic<PeriodicInterval{.lower = -std::numbers::pi, .upper = std::numbers::pi}, Dimension, MaxDimension>
Dimension_ coordinates that wrap with a common period, such as angles or DFT bins.
Definition Coordinates.h:144
Where a Periodic coordinate's values lie: the half-open interval [lower, upper), whose width is the p...
Definition Coordinates.h:123

Dimension angles in radians, in [-π, π).

◆ ValueVector

template<Space S, typename Scalar = double>
using Emrys::ValueVector
Initial value:
Eigen::Matrix<Scalar, valueDimensionAtCompileTime<S>, 1, Eigen::ColMajor, maxValueDimensionAtCompileTime<S>, 1>

A value in S as an Eigen column vector of Scalar: a mean, a sample, or a true state.

It has valueDimensionAtCompileTime<S> rows, and a resizable space's bound as its maximum, so a bounded space's vector never allocates. A block's own space gives a block's value (ValueVector<Position>), and Scalar may be an automatic-differentiation scalar, as a model's function written generically in its scalar uses.

Function Documentation

◆ allowsValueDimension()

template<typename Space>
bool Emrys::allowsValueDimension ( Eigen::Index n)
nodiscardconstexpr
Returns
whether some instance of Space has value dimension n: at least its FixedValueDimension, a whole number of ValueDimensionStep beyond it, and at most its MaxValueDimension. An instance's own is its valueDimension().

The test is exact for a space with at most one resizable block. For one with several it is necessary but not sufficient: a Composite of blocks with strides 2 and 3 has stride 1, and no instance has 1 coordinate.

◆ block() [1/3]

template<typename Path, MatrixExpression X>
auto Emrys::block ( Space auto const & space,
X && x )
nodiscard
Returns
the block named by the path Path (a tag or a TagPath) of x, an Eigen vector of values in space, or a matrix whose columns are such values: Eigen's block of its rows, with as many rows at compile time as the block's type fixes, so that it indexes as a hand-written segment does, and writable where x is (block<Position>(out, y) = ...). The rows of x are checked against space, at compile time where both are fixed: which space a vector is in is never inferred from its size (decisions.md [tag-addressing]). The path must not continue inside a Repeated block, whose repetitions block(space, x, element) reaches one at a time; a temporary plain matrix is refused, since its block would dangle. For an operand of differences, such as a covariance's rows, see diffBlock(); for a fixed-size space named by type, block<S, Path>(x).

◆ block() [2/3]

template<typename Path, MatrixExpression X>
auto Emrys::block ( Space auto const & space,
X && x,
Eigen::Index element )
nodiscard
Returns
block<Path>(space, x) for repetition element of the Repeated block that Path starts at, or of the block the rest of the path names within it: block<Fleet>(space, x, k) is vehicle k, and block<TagPath<Fleet, Heading>>(space, x, k) its heading. element must be one of its repetitions.

◆ block() [3/3]

template<FixedSizeSpace S, typename Path, MatrixExpression X>
requires Space<S>
auto Emrys::block ( X && x)
nodiscard
Returns
block<Path>(space, x) in the fixed-size space S, named as a template argument: block<State, Position>(x) (decisions.md [space-storage]).

◆ diffBlock() [1/6]

template<FixedSizeSpace S, typename Path, MatrixExpression D>
requires Space<S>
auto Emrys::diffBlock ( D && d)
nodiscard
Returns
diffBlock<Path>(space, d) in the fixed-size space S, named as a template argument: diffBlock<State, Attitude>(d).

◆ diffBlock() [2/6]

template<FixedSizeSpace S, typename Row, typename Column, MatrixExpression M>
requires Space<S>
auto Emrys::diffBlock ( M && m)
nodiscard
Returns
diffBlock<Row, Column>(space, m) in the fixed-size space S, named as a template argument: diffBlock<State, Position, Velocity>(cov).

◆ diffBlock() [3/6]

template<typename Row, typename Column, MatrixExpression M>
auto Emrys::diffBlock ( Space auto const & rowSpace,
Space auto const & columnSpace,
M && m )
nodiscard
Returns
the block of m, a matrix over differences with its rows in rowSpace and its columns in columnSpace, such as a Jacobian or a cross-covariance, at the rows of the path Row and the columns of the path Column: Eigen's block with as many rows and columns at compile time as the two blocks' types fix, writable where m is. Both sizes of m are checked against the spaces, at compile time where they are fixed.

◆ diffBlock() [4/6]

template<typename Path, MatrixExpression D>
auto Emrys::diffBlock ( Space auto const & space,
D && d )
nodiscard
Returns
the block named by the path Path of d, an Eigen vector of differences in space, or a matrix whose columns are such differences, as block() does for values: its rows are the block's rows of a covariance, which differ from its value rows where the block's differences have another size than its values, as a unit quaternion's do.

◆ diffBlock() [5/6]

template<typename Path, MatrixExpression D>
auto Emrys::diffBlock ( Space auto const & space,
D && d,
Eigen::Index element )
nodiscard
Returns
diffBlock<Path>(space, d) for repetition element of the Repeated block that Path starts at, as block(space, x, element) does for values.

◆ diffBlock() [6/6]

template<typename Row, typename Column, MatrixExpression M>
auto Emrys::diffBlock ( Space auto const & space,
M && m )
nodiscard
Returns
diffBlock<Row, Column>(space, space, m): the block of a matrix over the differences of one space on both axes, such as a covariance.

◆ differenceDimension()

template<Space S>
Eigen::Index Emrys::differenceDimension ( S const & space)
nodiscard
Returns
the number of coordinates of a difference in space, the rows of a covariance, the \( d \) in a density's normalizer, and the degrees of freedom of a NIS: the value dimension of its difference space.

◆ differenceSpace()

template<Space S>
DifferenceSpace< S > Emrys::differenceSpace ( S const & space)
nodiscard
Returns
the difference space of space, with its sizes: its difference(), or a copy of space if it has none. A fixed-size one is an empty type.

◆ diffIdx()

template<Space S, typename Path>
auto Emrys::diffIdx ( )
nodiscardconstexpr

idx<S, Path>() of the differences of the subspace named by Path: its rows of a covariance.

It differs from idx() where a block's differences have other sizes than its values.

◆ idx() [1/4]

template<Space S, typename Path>
auto Emrys::idx ( )
nodiscardconstexpr
Returns
the index of the subspace named by the path Path (a tag or a TagPath) within the space type S, from the type alone, for direct use in Eigen indexing:
  • a single fixed coordinate: an Eigen::Index, as a constant expression (static_assert(idx<State, Heading>() == 3));
  • a fixed block: seqN(fix<offset>, fix<size>);
  • a resizable block at the end of the space: seq(fix<offset>, last);
  • a path through a repeated block at the end of the space to one of its coordinates, such as idx<World, TagPath<Vehicles, Altitude>>(): that coordinate of every repetition, seq(fix<offset>, last, fix<stride>).

Only available when no resizable block precedes the path's block, and a resizable or repeated block ends the space; otherwise idx<Path>(space), which works for every path. A tag that appears more than once must be qualified by an enclosing tag; one inside a repeated block is reached only through it, and is not counted against the same tag outside (see TagPath).

The overloads of idx() are told apart by their arguments: idx<S, Path>() from the type, idx<Path>(space) from a space's sizes, and idx<Path>(space, element) and idx<S, Path>(element) for one repetition. Each indexes values, such as a mean; diffIdx(), with the same overloads, indexes differences, such as the rows of a covariance.

◆ idx() [2/4]

template<Space S, typename Path>
auto Emrys::idx ( Eigen::Index element)
nodiscard

idx<Path>(space, element) for the space type S, without a space object.

Only available when no resizable block precedes the repeated block, and element is not range-checked, since the repetition count is unknown; otherwise use idx<Path>(space, element).

◆ idx() [3/4]

template<typename Path>
auto Emrys::idx ( Space auto const & space)
nodiscard
Returns
the index of the subspace named by the path Path (a tag or a TagPath) within space, from its runtime sizes: an Eigen::Index for a single fixed coordinate; seqN(offset, fix<size>) for a fixed block; seqN(offset, size) for a resizable one; and for a path through a repeated block to one of its coordinates, seqN(offset, count, fix<stride>). It works for every path, where idx<S, Path>() needs every offset fixed by the type.

◆ idx() [4/4]

template<typename Path>
auto Emrys::idx ( Space auto const & space,
Eigen::Index element )
nodiscard
Returns
the index of repetition element of a repeated block within space, from the space's runtime sizes. Path starts at the repeated block: idx<Fleet>(space, k) is vehicle k, and idx<TagPath<Fleet, Heading>>(space, k) its heading. The result is an Eigen::Index for one coordinate, otherwise seqN(start, fix<size>). element must be one of its repetitions.

◆ less() [1/2]

template<FixedSizeSpace S, typename XDerived, typename DDerived>
requires Space<S>
auto Emrys::less ( Eigen::MatrixBase< XDerived > const & x,
Eigen::MatrixBase< DDerived > const & d )
nodiscard
Returns
less() in the fixed-size space S, given as a template argument: less<Gyro>(reading, bias).

◆ less() [2/2]

template<Space S, typename XDerived, typename DDerived>
auto Emrys::less ( S const & space,
Eigen::MatrixBase< XDerived > const & x,
Eigen::MatrixBase< DDerived > const & d )
nodiscard
Returns
\( x \boxplus (-\delta) \): the values x moved back by the differences d, in canonical form, as plus(space, x, -d). It takes a difference away from a value, as minus() takes one value from another: a reading less its bias is less<Gyro>(reading, bias) for a bias in DifferenceSpace<Gyro>. Columns pair as in plus().

It undoes plus() exactly, less(space, plus(space, x, d), d) == x up to rounding, on a space whose plus() is a group's, as on Linear, Periodic, and UnitQuaternion; on a space whose plus() is some other retraction, it undoes it only to first order in d.

A model need not use it: on a Linear space it is x - d, and the filter normalizes the values a model returns, so bare arithmetic is a choice for plainness that is right wherever the space's plus() is addition (docs/usage.md, Conventions).

◆ minus() [1/2]

template<FixedSizeSpace S, typename ADerived, typename BDerived>
requires Space<S>
auto Emrys::minus ( Eigen::MatrixBase< ADerived > const & a,
Eigen::MatrixBase< BDerived > const & b )
nodiscard
Returns
minus() in the fixed-size space S, given as a template argument: minus<State>(a, b).

◆ minus() [2/2]

template<Space S, typename ADerived, typename BDerived>
auto Emrys::minus ( S const & space,
Eigen::MatrixBase< ADerived > const & a,
Eigen::MatrixBase< BDerived > const & b )
nodiscard
Returns
\( a \boxminus b \): the differences from b to a, in canonical form. Rows are coordinates and columns samples; an operand with one column at compile time is used for every column of the other, so minus(space, samples, mean) gives each sample's deviation. For most spaces this is normalizeDifferences(space, a - b), and for a linear one just a - b.

◆ normalizeDifferences()

template<Space S, typename Derived>
void Emrys::normalizeDifferences ( S const & space,
Eigen::MatrixBase< Derived > const & block )

Brings the differences in block into canonical form: normalizeValues() in the difference space of space, for differences that come from outside.

Does nothing where that space has no normalize(). A residual goes through minus() instead.

◆ normalizeValues()

template<Space S, typename Derived>
void Emrys::normalizeValues ( S const & space,
Eigen::MatrixBase< Derived > const & block )

Brings the values in block (rows are space's coordinates, columns samples) into canonical form, writing through the const reference as the space's normalize() does: for values that come from outside, such as a user's mean or a model's output.

Does nothing for a space without normalize(). An update goes through plus() instead.

◆ on()

template<typename Path, typename X>
requires (!internal::PlacesModel<X>)
internal::OnPath< typename internal::HeldOf< X >::type, Path > Emrys::on ( X x)
nodiscard
Returns
x placed on the block that the path Path (a tag or a TagPath) names, in a space that is given later: a factor of a Product or of Factors, such as on<Heading>(uniform), or a sensor's matrix columns for the block's coordinates, in Columns (decisions.md [product-factors]). A matrix expression is evaluated here. Given a path value, it names that path by the tag Path where a list of paths takes each under a name: on<SensorPosition>(path<Ownship, Position>) is the ownship's position under the name SensorPosition (decisions.md [tag-addressing]).

◆ onEach()

template<typename Path = internal::WholeSpace, typename X>
requires (!internal::PlacesModel<X>)
internal::OnEach< typename internal::HeldOf< X >::type, Path > Emrys::onEach ( X x)
nodiscard
Returns
x, given for one repetition, placed on every repetition of the repeated block that the path Path names, as many as the space given later has: a factor of Factors, such as onEach<Landmarks>(GaussianParams<Landmark>{zero, P}), which is \( I \otimes P \), or a sensor's matrix in Columns, which reads each repetition into a repetition of the measurement. Without a path, onEach<>(x), it is placed on every repetition of the whole space, which is then repeated, such as a measurement space inferred by a sensor (decisions.md [product-factors]).

◆ plus() [1/2]

template<FixedSizeSpace S, typename XDerived, typename DDerived>
requires Space<S>
auto Emrys::plus ( Eigen::MatrixBase< XDerived > const & x,
Eigen::MatrixBase< DDerived > const & d )
nodiscard
Returns
plus() in the fixed-size space S, given as a template argument: plus<State>(x, d).

◆ plus() [2/2]

template<Space S, typename XDerived, typename DDerived>
auto Emrys::plus ( S const & space,
Eigen::MatrixBase< XDerived > const & x,
Eigen::MatrixBase< DDerived > const & d )
nodiscard
Returns
\( x \boxplus \delta \): the values x moved by the differences d, in canonical form. Rows are coordinates and columns samples; an operand with one column at compile time is used for every column of the other, so plus(space, mean, L * z) draws samples. For most spaces this is normalizeValues(space, x + d), and for a linear one just x + d.

◆ resetCovariance()

template<Space S, typename XDerived, typename DDerived, typename CovDerived>
void Emrys::resetCovariance ( S const & space,
Eigen::MatrixBase< XDerived > const & x,
Eigen::MatrixBase< DDerived > const & d,
Eigen::MatrixBase< CovDerived > const & cov )

Carries the covariance cov from the tangent space at x to the one at \( x \boxplus d \), in place: \( P \leftarrow G P G^T \), with \( G \) the reset Jacobian of resetJacobian() (decisions.md [covariance-reset]).

An update that moves a mean by a step and keeps the covariance computed at the old mean calls it, as the Kalman update and the Gaussian conditional do.

cov is read and written whole, and must be symmetric; it may be a block of a larger matrix. Where space has an identity reset (hasIdentityReset), this does nothing and compiles to nothing. Otherwise only the blocks that need it are touched: for a block of \( k \) rows at offset \( o \) in an \( n \)-row covariance, the strip \( G P_{o,:} \) is formed once and written into those rows and, transposed, into those columns, and the diagonal block \( G P_{oo} G^T \) is made exactly symmetric, about \( 4 k^2 n \) flops. A symmetric cov stays exactly symmetric, and as a congruence it keeps a positive semidefinite one so. Allocates nothing for a bounded space.

See resetJacobian() for the sources.

◆ resetJacobian()

template<Space S, typename XDerived, typename DDerived>
auto Emrys::resetJacobian ( S const & space,
Eigen::MatrixBase< XDerived > const & x,
Eigen::MatrixBase< DDerived > const & d )
nodiscard
Returns
the reset Jacobian of space at the value x and the step d, dense: the identity but for the blocks without an identity reset, where

\[ G = \frac{\partial}{\partial \epsilon} \Big[ \big(x \boxplus (d + \epsilon)\big) \boxminus (x \boxplus d) \Big]_{\epsilon = 0}, \]

which takes an error at x to the same error seen from \( x \boxplus d \) (decisions.md [covariance-reset]). A block gives its own in closed form with a member resetJacobian(x, d, out), declares it the identity with static constexpr bool identityReset = true;, or has it computed by forward-mode automatic differentiation of its plus() and minus(). For tests and for callers who want \( G \) itself; resetCovariance() applies it without forming it.

For a unit quaternion with \( q \boxplus \delta = q \otimes \mathrm{Exp}(\delta) \) it is the right Jacobian of SO(3), \( J_r(d) \), in the closed form of Solà, Deray, and Atchuthan (2018), eq. (143). The reset is that of the error-state Kalman filter of Solà (2017), §6.3, eqs. (284) to (288), which keeps only the first-order \( I - \tfrac12 [d]_\times \) (eq. 294), and of Mueller, Hehn, and D'Andrea (2017), who derive it for a filter with an attitude and show it is missing from the multiplicative extended Kalman filter of Markley (2003), whose reset moves the attitude and leaves the covariance unchanged. The departure from all three is generality: the Jacobian comes from the space, block by block, by differentiating its own \( \boxplus \) and \( \boxminus \) unless it gives a closed form, rather than being written for an attitude.

◆ valueDimension()

template<Space S>
Eigen::Index Emrys::valueDimension ( S const & space)
nodiscard
Returns
the number of coordinates of a value in space, the length of a mean or a sample: the space's own valueDimension().

It is for run time and is not constexpr, even for a fixed space, as Eigen has rows() beside RowsAtCompileTime: a resizable space's dimension is never a constant, and a user's space would need every member constexpr. At compile time use valueDimensionAtCompileTime, which works for every space, and valueDimensionAtCompileTime<DifferenceSpace<S>> for the differences.

◆ writable()

template<typename Derived>
Eigen::MatrixBase< Derived > & Emrys::writable ( Eigen::MatrixBase< Derived > const & block)
nodiscard

block, writable: Eigen's idiom for a function that writes through an expression passed as const&.

A space's normalize(), plus(), and minus() take their output as a const Eigen::MatrixBase<Derived>&, so that a temporary block such as x.segment(i, n) can be passed, and write through it with this: writable(block) = block.unaryExpr(f).

◆ zeros()

template<typename Scalar, Space S>
ValueVector< S, Scalar > Emrys::zeros ( S const & space)
nodiscard
Returns
a zero Eigen vector of Scalar with the value dimension of space: the vector a function fills block by block, auto y = zeros<T>(out); block<Position>(out, y) = ...;, with T the scalar the function is called in (decisions.md [function-scalars]), so that a function differentiated automatically builds its result in dual numbers. It is zero rather than uninitialized, so that a coordinate the function leaves unwritten reads as zero and no compiler warns of a read before a write. In a fixed-size space it is ValueVector<S, T>::Zero().

Variable Documentation

◆ hasIdentityReset

template<typename S>
bool Emrys::hasIdentityReset = internal::identityResetOf<S>()
inlineconstexpr

Whether the reset Jacobian of S is the identity, so that a covariance needs no change when its mean moves (decisions.md [covariance-reset]).

True for a space with no plus() of its own, such as Linear and Periodic; for one that declares static constexpr bool identityReset = true;; and for a Composite or Repeated whose blocks all have it. Where it holds, resetCovariance() does nothing at all.

◆ hasPlainDifferences

template<Space S>
bool Emrys::hasPlainDifferences
inlineconstexpr
Initial value:
=
!internal::HasNormalize<DifferenceSpace<S>> && !internal::HasPlus<S> && !internal::HasMinus<S>

Whether the differences of S are plain: its difference space has no normalize(), and it has neither plus() nor minus(), so \( a \boxminus b \) is a - b and \( x \boxplus \delta \) is x + δ up to normalize().

Linear has plain differences, so a weighted mean in it is the plain one; Periodic does not.

◆ hasPlainValues

template<Space S>
bool Emrys::hasPlainValues = !internal::HasNormalize<S> && !internal::HasPlus<S>
inlineconstexpr

Whether the values of S are plain: it has neither normalize() nor plus(), so \( x \boxplus \delta \) is x + δ.

Periodic's are not; a space that wraps only its differences has plain values.

◆ isLinear

template<Space S>
bool Emrys::isLinear = hasPlainValues<S> && hasPlainDifferences<S>
inlineconstexpr

Whether S is linear: its values and its differences are both plain vectors.

Linear, and a Composite or Repeated of linear blocks, are linear; Periodic is not. Like hasPlainValues and hasPlainDifferences, it takes only a Space, so a type that is not one does not compile rather than counting as linear.

◆ maxValueDimensionAtCompileTime

template<typename Space>
int Emrys::maxValueDimensionAtCompileTime
inlineconstexpr
Initial value:
=
Space::ValueDimensionStep == 0 ? Space::FixedValueDimension : Space::MaxValueDimension

The largest valid value dimension of Space, or Eigen::Dynamic if it is unbounded.

◆ path

template<typename... Tags>
TagPath<Tags...> Emrys::path {}
inlineconstexpr

The path TagPath<Tags...> as a value, for a call that takes its paths as arguments rather than as template arguments: reads(path<Position>, path<Ownship, Velocity>).

A bare tag's own value, Position{}, is a path of one tag wherever a path value is taken (PathValue), since a tag is an empty type.

◆ valueDimensionAtCompileTime

template<typename Space>
int Emrys::valueDimensionAtCompileTime
inlineconstexpr
Initial value:
=
Space::ValueDimensionStep == 0 ? Space::FixedValueDimension : Eigen::Dynamic

The value dimension of Space at compile time, or Eigen::Dynamic if it is resizable.