20#include <Eigen/Cholesky>
45 typename T::SpaceType;
48 input.valueDimension();
49 input.differenceDimension();
50} && (
requires(T
const & input) { input.covarianceLower(); } ||
requires(T
const & input) { input.root(); });
59template <UncertainInput Input>
60[[nodiscard]]
decltype(
auto)
61covarianceLowerOf(Input
const & input)
63 if constexpr (
requires { input.covarianceLower(); })
65 return input.covarianceLower();
69 using Matrix = std::remove_cvref_t<
decltype(input.root())>;
70 Matrix result = multiply(asTriangular<Eigen::Lower>(input.root()), input.root().transpose());
79template <UncertainInput Prior>
80[[nodiscard]]
decltype(
auto)
81withCovariance(Prior
const & prior)
83 if constexpr (
requires { prior.covarianceLower(); })
89 using Result = GaussianParams<typename Prior::SpaceType, typename Prior::Scalar>;
92 typename Result::VectorType{prior.mean()},
93 typename Result::MatrixType{covarianceLowerOf(prior)}
126inline constexpr bool isLinearizationForm = std::is_same_v<T, JacobianForm> || std::is_same_v<T, RootForm>;
131template <
typename InputSpace,
typename OutputSpace,
typename Scalar>
132using CrossMatrixOf = MatrixOf<
142template <
typename Derived>
144isInvertibleLowerTriangular(Eigen::MatrixBase<Derived>
const & root)
146 using Scalar =
typename Derived::Scalar;
147 for (Eigen::Index j = 0; j < root.cols(); ++j)
149 if (!(root(j, j) > Scalar(0)))
153 for (Eigen::Index i = 0; i < j; ++i)
155 if (root(i, j) != Scalar(0))
175template <
typename Result,
typename Root,
typename Whitened>
177solveWithRoot(Eigen::MatrixBase<Root>
const & root, Eigen::MatrixBase<Whitened>
const & whitened)
179 using RootMatrix =
typename Root::PlainObject;
180 Result result = whitened;
182 if constexpr (Root::RowsAtCompileTime != 0)
184 if (isInvertibleLowerTriangular(root))
186 root.template triangularView<Eigen::Lower>().transpose().solveInPlace(result);
190 auto const ldlt = Eigen::LDLT<RootMatrix>{
RootMatrix{multiply(root, root.transpose())}};
191 result.noalias() = multiply(root, whitened);
192 solveInPlace(ldlt, result);
235template <
typename InputSpace,
typename OutputSpace,
typename Form,
typename Scalar =
double>
238 static_assert(internal::isLinearizationForm<Form>);
241 static constexpr bool IsRoot = std::is_same_v<Form, RootForm>;
258 using CrossMatrix = internal::CrossMatrixOf<InputSpace, OutputSpace, Scalar>;
279 using FactorMatrix = std::conditional_t<IsRoot, RootMatrix, JacobianMatrix>;
299 Explained && explained,
301 Unexplained && unexplained
303 : m_explained{std::forward<Explained>(explained)}
304 , m_inputs{std::forward<Inputs>(inputs)}
305 , m_unexplained{std::forward<Unexplained>(unexplained)}
306 , m_output{std::move(space), std::forward<Mean>(mean),
OutputMatrix{m_explained + m_inputs + m_unexplained}}
307 , m_factor{std::forward<Factor>(factor)}
308 , m_cross{std::forward<Cross>(cross)}
311 m_cross.cols() == m_output.differenceDimension() && m_factor.cols() == m_cross.rows()
312 &&
"the linearization must have a row per input coordinate and a column per output coordinate"
327 return std::move(m_output);
352 return m_unexplained;
372 return internal::multiply(m_factor, m_cross);
390 return internal::solveWithRoot<CrossMatrix>(m_factor, m_cross).transpose();
423template <
typename Scalar>
424struct InnovationStatistics
427 Scalar logDeterminant;
443template <
typename R,
typename Matrix>
444[[nodiscard]] std::expected<Eigen::LLT<std::remove_const_t<Matrix>>,
GaussianError>
445innovationCholesky(Matrix & cov)
447 auto llt = Eigen::LLT<std::remove_const_t<Matrix>>{cov};
448 if (llt.info() == Eigen::Success)
452 if constexpr (!std::is_same_v<R, NoRepair>)
454 static_assert(!std::is_const_v<Matrix>,
"a repaired innovation covariance replaces the one given");
455 auto repaired = R{}.repaired(cov);
458 return std::unexpected{repaired.error()};
460 llt.compute(*repaired);
461 if (llt.info() != Eigen::Success)
465 cov = std::move(*repaired);
478template <
typename Matrix,
typename Res
idual>
479[[nodiscard]] InnovationStatistics<typename Matrix::Scalar>
480innovationStatistics(Eigen::LLT<Matrix>
const & llt, Eigen::MatrixBase<Residual>
const & residual)
482 using Scalar =
typename Matrix::Scalar;
483 typename Residual::PlainObject whitened =
residual;
484 llt.matrixL().solveInPlace(whitened);
485 return {whitened.squaredNorm(), Scalar(2) * llt.matrixLLT().diagonal().array().log().sum()};
491struct InnovationInPlace
502 template <
typename Scalar>
503 [[nodiscard]]
constexpr bool
504 operator()(Scalar , Eigen::Index )
const
511template <
typename Accept>
512inline constexpr bool acceptsByNis = !std::is_same_v<Accept, AcceptEvery>;
534template <
typename Space,
typename Scalar =
double>
548 template <MatrixExpression Res
idual, MatrixExpression Cov>
552 std::optional<internal::InnovationStatistics<Scalar>> statistics = std::nullopt
554 : m_residual{std::forward<Residual>(
residual)}
555 , m_cov{std::forward<Cov>(cov)}
556 , m_statistics{statistics}
559 m_cov.rows() == m_residual.size() && m_cov.cols() == m_residual.size()
560 &&
"the covariance must have a row per residual coordinate"
571 template <MatrixExpression Res
idual,
typename MakeCov,
typename Condition>
573 : m_residual{std::forward<Residual>(
residual)}
575 , m_statistics{
condition(std::as_const(m_residual), m_cov)}
578 m_cov.rows() == m_residual.size() && m_cov.cols() == m_residual.size()
579 &&
"the covariance must have a row per residual coordinate"
598 [[nodiscard]] Eigen::Index
601 return m_residual.size();
610 return statistics().nis;
617 internal::InnovationStatistics<Scalar>
const & known = statistics();
624 [[nodiscard]] internal::InnovationStatistics<Scalar>
const &
629 auto const llt = Eigen::LLT<MatrixType>{m_cov};
630 EMRYS_FILTER_ASSERT(llt.info() == Eigen::Success &&
"the innovation covariance must be positive definite");
631 m_statistics = internal::innovationStatistics(llt, m_residual);
633 return *m_statistics;
640 mutable std::optional<internal::InnovationStatistics<Scalar>> m_statistics;
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
Products of fixed-size matrices by Eigen's fixed-size product at every size: multiply() is by Eigen'...
Solving by a factorization of a small matrix: transposedSolve() gives , the shape of a Kalman gain an...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
A Gaussian distribution: a mean and covariance in a space.
Definition Gaussian.h:259
typename MomentsType::MatrixType MatrixType
Definition Gaussian.h:267
typename MomentsType::VectorType VectorType
Definition Gaussian.h:265
typename MomentsType::DifferenceVectorType DifferenceVectorType
a difference, such as a residual
Definition Gaussian.h:266
VectorType const & residual() const
Definition Linearization.h:585
Eigen::Index differenceDimension() const
Definition Linearization.h:599
typename GaussianParams< Space, Scalar >::MatrixType MatrixType
the covariance's type
Definition Linearization.h:543
MatrixType const & covarianceLower() const
Definition Linearization.h:592
Innovation(Residual &&residual, Cov &&cov, std::optional< internal::InnovationStatistics< Scalar > > statistics=std::nullopt)
The innovation with residual residual and covariance cov, moving either one passed as an rvalue of th...
Definition Linearization.h:549
Innovation(internal::InnovationInPlace, Residual &&residual, MakeCov const &makeCov, Condition const &condition)
The innovation with residual residual and the covariance makeCov returns, made where the innovation k...
Definition Linearization.h:572
Scalar nis() const
Definition Linearization.h:608
typename GaussianParams< Space, Scalar >::DifferenceVectorType VectorType
the residual's type
Definition Linearization.h:540
Scalar logLikelihood() const
Definition Linearization.h:615
JacobianMatrix const & jacobian() const
Definition Linearization.h:377
std::conditional_t< IsRoot, RootMatrix, JacobianMatrix > FactorMatrix
What the form holds beside its cross-covariance: in the Jacobian form, in the root form.
Definition Linearization.h:279
OutputMatrix const & unexplainedCovariance() const
Definition Linearization.h:350
CrossMatrix crossCovariance() const
Definition Linearization.h:369
internal::CrossMatrixOf< InputSpace, OutputSpace, Scalar > CrossMatrix
The cross-covariance's type, and 's: input differences by output differences.
Definition Linearization.h:258
CrossMatrix const & whitenedCross() const
Definition Linearization.h:403
internal::MatrixOf< Scalar, valueDimensionAtCompileTime< DifferenceSpace< InputSpace > >, valueDimensionAtCompileTime< DifferenceSpace< InputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< InputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< InputSpace > > > RootMatrix
The root's type: over the input's differences.
Definition Linearization.h:269
OutputMatrix const & explainedCovariance() const
Definition Linearization.h:332
OutputType output() &&
Definition Linearization.h:325
JacobianMatrix jacobian() const
Definition Linearization.h:387
OutputMatrix const & inputsCovariance() const
Definition Linearization.h:339
GaussianParams< OutputSpace, Scalar > OutputType
The output's distribution.
Definition Linearization.h:249
internal::MatrixOf< Scalar, valueDimensionAtCompileTime< DifferenceSpace< OutputSpace > >, valueDimensionAtCompileTime< DifferenceSpace< InputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< OutputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< InputSpace > > > JacobianMatrix
The Jacobian's type: output differences by input differences.
Definition Linearization.h:261
OutputWithCross(OutputSpace space, Mean &&mean, Factor &&factor, Cross &&cross, Explained &&explained, Inputs &&inputs, Unexplained &&unexplained)
The prediction in space with mean mean, normalized, and the parts of its linearization: factor,...
Definition Linearization.h:294
typename OutputType::MatrixType OutputMatrix
A covariance over the output's differences.
Definition Linearization.h:255
OutputType const & output() const &
Definition Linearization.h:318
Form FormType
JacobianForm or RootForm.
Definition Linearization.h:246
CrossMatrix const & crossCovariance() const
Definition Linearization.h:359
typename OutputType::VectorType OutputVector
An output value.
Definition Linearization.h:252
RootMatrix const & root() const
Definition Linearization.h:395
A dense matrix or matrix expression, possibly cv- or reference-qualified: what a const Eigen::MatrixB...
Definition Forwarding.h:39
Scalar log2Pi()
Definition Math.h:177
@ NotPositiveDefinite
the covariance is not positive definite, so it has no Cholesky factor or inverse
Definition NumericError.h:31
NumericError GaussianError
Reasons a Gaussian, in any of its forms (decisions.md [gaussian-forms]), can fail to give a density,...
Definition NumericError.h:45
internal::SquareMatrixOf< Derived > RootMatrix
The type of a root of the covariance or factor Derived: square, with a row and a column per row of it...
Definition Roots.h:350
constexpr Residual< Inner > residual(Inner inner={})
Definition Resampling.h:544
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
A model's output space given by its instance, or computed from the state's space, as outputSpace() de...
Definition Policies.h:681