21#include <Eigen/Cholesky>
56inline constexpr bool isOtherGaussianForm = GaussianForm<C> && !
isGaussian<C>;
63template <Space Space_, RealScalar Scalar_>
68 using Scalar = Scalar_;
69 using SpaceType = Space_;
70 using MomentsType = Moments<Space_, Scalar_>;
89 RootInput(Space_ space, VectorType mean, MatrixType root)
90 : m_space{std::move(space)}
91 , m_mean{std::move(mean)}
92 , m_root{std::move(root)}
96 [[nodiscard]] Space_
const &
103 [[nodiscard]] VectorType
const &
110 [[nodiscard]] MatrixType
const &
117 [[nodiscard]] MatrixType
118 covarianceLower()
const
120 MatrixType result = multiply(asTriangular<Eigen::Lower>(m_root), m_root.transpose());
125 [[nodiscard]] Eigen::Index
126 valueDimension()
const
132 [[nodiscard]] Eigen::Index
133 differenceDimension()
const
156template <
typename Space,
typename MeasurementSpace,
typename Scalar>
157struct MeasurementLinearization
159 using SpaceType = Space;
160 using MeasurementSpaceType = MeasurementSpace;
163 using Linearization = StatisticalLinearization<Space, MeasurementSpace, Scalar>;
170 using InnovationVector =
173 MeasurementSpace space;
174 MeasurementVector predicted;
175 InnovationVector residual;
176 JacobianMatrix jacobian;
184template <
typename Scalar,
typename R,
typename Linearization>
186observeLinearization(R
const & resolved, Linearization & linearization)
188 if constexpr (R::HasObservation)
190 linearization.residual = observedResidual<Scalar>(resolved, linearization.space, linearization.predicted);
206 typename MeasurementSpace,
208 typename ReadJacobian,
210[[nodiscard]] MeasurementLinearization<Space, MeasurementSpace, Scalar>
211assembleLinearization(
215 MeasurementSpace
const & measurementSpace,
216 Predicted
const & predicted,
217 ReadJacobian
const & readJacobian,
221 using Result = MeasurementLinearization<Space, MeasurementSpace, Scalar>;
222 using MeasurementVector =
typename Result::MeasurementVector;
223 using InnovationVector =
typename Result::InnovationVector;
224 using NoiseMatrix =
typename Result::NoiseMatrix;
227 auto result = Result{
231 Result::JacobianMatrix::Zero(m, n),
234 result.jacobian(Eigen::placeholders::all, reads.differenceIndices()) = readJacobian;
235 if constexpr (!R::HasAdditiveNoise)
237 result.predicted = predicted;
238 result.noise = omega;
244 "a square-root or information form takes measurement noise of one component; mixture noise, whose "
245 "branches are collapsed by moment matching, is the covariance form's (decisions.md [gaussian-forms])"
247 auto const & noise = resolved.noise().distribution();
248 result.predicted =
Emrys::plus(measurementSpace, predicted, noise.mean());
249 result.noise = omega + symmetricFromLower<NoiseMatrix>(noise.covarianceLower());
251 result.noise = (Scalar(0.5) * (result.noise + result.noise.transpose())).eval();
252 observeLinearization<Scalar>(resolved, result);
262template <
typename Scalar,
typename Space,
typename R,
typename Method>
264linearizeMeasurementAtPoint(
268 Method
const & method
271 using Reads =
typename R::Reads;
272 using ReadPoint = PointInput<typename Reads::JointSpace, Scalar>;
273 auto const & reads = resolved.reads();
274 auto const read = ReadPoint{reads.space(),
typename ReadPoint::VectorType{point(reads.indices())}};
275 auto const f = ResolvedFunction{resolved};
277 isLinearMethod<Method>,
278 "a linearization at a point is for a method that linearizes once at the means"
280 return linearizeMeasurement(resolved, method, f, read, [&](
auto const & problem,
auto const & linearized) {
281 using Problem = std::remove_cvref_t<
decltype(problem)>;
282 using Omega =
typename Problem::OutputMatrix;
283 Eigen::Index
const k = reads.differenceIndices().size();
284 auto const readJacobian =
285 linearized.jacobian.template middleCols<Reads::DifferenceSize>(problem.differenceOffset(0), k);
286 Omega
const omega = inputsCovariance<Omega>(resolved, problem,
linearized.jacobian);
287 return assembleLinearization<Scalar>(
291 problem.outputSpace(),
302template <
typename Scalar,
typename Space,
typename R>
304linearizeMeasurementAtPoint(
310 return linearizeMeasurementAtPoint<Scalar>(space, point, resolved, resolved.method());
316template <
typename Linearization>
317struct IteratedLinearization
319 Linearization linearization;
320 std::size_t iterations;
328template <
typename Root,
unsigned int Mode>
335template <
typename Cov>
337spreadScale(Eigen::MatrixBase<Cov>
const & cov,
typename Cov::Scalar tolerance)
339 return iterationScale(cov, tolerance);
345template <
typename Root,
unsigned int Mode>
347spreadScale(TriangularRoot<Root, Mode>
const & spread,
typename Root::Scalar tolerance)
349 using Scalar =
typename Root::Scalar;
350 EMRYS_FILTER_ASSERT(tolerance >= Scalar(0) &&
"an iteration's tolerance must not be negative");
351 using Result = Eigen::Matrix<Scalar, Root::RowsAtCompileTime, 1, Eigen::ColMajor, Root::MaxRowsAtCompileTime, 1>;
352 Result result =
spread.root.rowwise().norm() * tolerance;
357template <
typename Cov,
typename Indices>
359readBlockCovariance(Eigen::MatrixBase<Cov>
const & cov, Indices
const & indices)
361 using Result = MatrixOf<
362 typename Cov::Scalar,
363 Indices::SizeAtCompileTime,
364 Indices::SizeAtCompileTime,
365 Indices::MaxRowsAtCompileTime,
366 Indices::MaxRowsAtCompileTime>;
367 Result result = lowerSymmetricBlock(cov, indices, indices);
374template <
typename Root,
unsigned int Mode,
typename Indices>
376readBlockCovariance(TriangularRoot<Root, Mode>
const & spread, Indices
const & indices)
378 using Result = MatrixOf<
379 typename Root::Scalar,
380 Indices::SizeAtCompileTime,
381 Indices::SizeAtCompileTime,
382 Indices::MaxRowsAtCompileTime,
383 Indices::MaxRowsAtCompileTime>;
384 auto const rows =
spread.root(indices, Eigen::placeholders::all);
385 auto result = Result{};
386 result.resize(indices.size(), indices.size());
387 result.noalias() = multiply(rows, rows.transpose());
394template <
typename Cov,
typename Jacobian,
typename Crossed,
typename InnovationCov>
397 Eigen::MatrixBase<Cov>
const & cov,
398 Jacobian
const & jacobian,
400 InnovationCov & innovationCov
403 crossed.noalias() = multiply(cov, jacobian.transpose());
404 innovationCov.noalias() += multiply(jacobian, crossed);
411template <
typename Root,
unsigned int Mode,
typename Jacobian,
typename Crossed,
typename InnovationCov>
414 TriangularRoot<Root, Mode>
const & spread,
415 Jacobian
const & jacobian,
417 InnovationCov & innovationCov
420 using Scaled = std::remove_cvref_t<
decltype(jacobian.eval())>;
421 auto scaled = Scaled{};
422 scaled.resize(jacobian.rows(), jacobian.cols());
423 scaled.noalias() = multiply(jacobian, asTriangular<Mode>(
spread.root));
424 crossed.noalias() = multiply(asTriangular<Mode>(
spread.root), scaled.transpose());
425 innovationCov.noalias() += multiply(scaled, scaled.transpose());
435template <
typename Scalar,
typename Reads,
typename R,
typename ReadBase,
typename Step,
typename Linearization>
440 ReadBase
const & readBase,
442 Linearization & linearization
446 using ReadJacobian = MatrixOf<
448 Linearization::JacobianMatrix::RowsAtCompileTime,
449 Reads::DifferenceSize,
450 Linearization::JacobianMatrix::MaxRowsAtCompileTime,
451 Reads::DifferenceMaxSize>;
452 ReadDifference
const readStep = step(reads.differenceIndices());
453 ReadJacobian readJacobian = linearization.jacobian(Eigen::placeholders::all, reads.differenceIndices());
454 toPriorChart(reads, readJacobian, readBase, readStep);
455 linearization.jacobian(Eigen::placeholders::all, reads.differenceIndices()) = readJacobian;
456 auto back =
typename Linearization::InnovationVector{};
457 back.resize(linearization.jacobian.rows());
458 back.noalias() = -multiply(linearization.jacobian, step);
459 linearization.predicted =
Emrys::plus(linearization.space, linearization.predicted, back);
460 observeLinearization<Scalar>(resolved, linearization);
471template <
typename Scalar,
typename Space,
typename R,
typename Reference>
473linearizeMeasurementAbout(
476 LinearizedAbout<Reference>
const & about,
480 using About = LinearizedAbout<Reference>;
481 using Method =
typename R::Method;
482 using Reads =
typename R::Reads;
485 static_assert(checkReference<Method, About, Space>());
486 auto const & reads = resolved.reads();
487 Vector
const point = about.mean();
489 point.size() ==
valueDimension(space) &&
"a point to linearize about must have the prior's value dimension"
491 auto linearization = [&] {
492 if constexpr (isLinearMethod<Method>)
494 return linearizeMeasurementAtPoint<Scalar>(space, point, resolved);
496 else if constexpr (About::IsDistribution)
498 using Input = RootInput<typename Reads::JointSpace, Scalar>;
499 auto const cov = readBlockCovariance(about.reference.covarianceLower(), reads.differenceIndices());
500 auto const input = Input{
502 typename Input::VectorType{point(reads.indices())},
503 lowerTriangularRoot(defaultRoot(cov))
505 return linearizeMeasurementAtRoot<Scalar>(space, reads, input, resolved);
509 Difference
const step =
Emrys::minus(space, point, base);
510 ReadVector
const readBase = base(reads.indices());
511 toBaseChart<Scalar>(reads, resolved, readBase, step, linearization);
512 return linearization;
528template <
typename Scalar,
typename Space,
typename Spread,
typename R>
530iterateMeasurementLinearization(
533 std::optional<Spread>
const & spread,
537 using Reads =
typename R::Reads;
542 auto const & method = resolved.method();
543 auto const & reads = resolved.reads();
544 ReadVector
const readMean = mean(reads.indices());
546 std::size_t iteration = 0;
547 bool converged =
false;
552 using Inner = std::remove_cvref_t<
decltype(method.method)>;
553 constexpr bool Spreads = !isLinearMethod<Inner>;
554 using ReadMatrix = MatrixOf<
556 Reads::DifferenceSize,
557 Reads::DifferenceSize,
558 Reads::DifferenceMaxSize,
559 Reads::DifferenceMaxSize>;
560 using SpreadMatrix = std::conditional_t<Spreads, ReadMatrix, std::monostate>;
561 auto priorReadCov = SpreadMatrix{};
562 auto spreadRoot = SpreadMatrix{};
563 if constexpr (Spreads)
565 EMRYS_FILTER_ASSERT(spread &&
"a sigma-point method needs the prior's covariance to spread its points");
566 priorReadCov = readBlockCovariance(*spread, reads.differenceIndices());
567 spreadRoot = lowerTriangularRoot(defaultRoot(priorReadCov));
573 auto const linearizeAtIterate = [&] {
574 if constexpr (Spreads)
576 auto const input = RootInput<typename Reads::JointSpace, Scalar>{
578 iteration == 0 ? readMean
579 : ReadVector{
Emrys::plus(reads.space(), readMean, delta(reads.differenceIndices()))},
582 return linearizeMeasurementAtRoot<Scalar>(space, reads, input, resolved, method.method);
586 return linearizeMeasurementAtPoint<Scalar>(
588 iteration == 0 ? mean : Vector{
Emrys::plus(space, mean, delta)},
596 auto const atIterate = [&] {
597 auto result = linearizeAtIterate();
600 toBaseChart<Scalar>(reads, resolved, readMean, delta, result);
605 using Linearization =
decltype(atIterate());
606 using Result = std::expected<IteratedLinearization<Linearization>,
GaussianError>;
609 return Result{IteratedLinearization<Linearization>{atIterate(), 1,
false}};
611 using Gain = MatrixOf<
613 Linearization::JacobianMatrix::ColsAtCompileTime,
614 Linearization::JacobianMatrix::RowsAtCompileTime,
615 Linearization::JacobianMatrix::MaxColsAtCompileTime,
616 Linearization::JacobianMatrix::MaxRowsAtCompileTime>;
617 using NoiseMatrix =
typename Linearization::NoiseMatrix;
618 auto const scale = spreadScale(*spread, Scalar(method.tolerance));
620 for (; iteration + 1 < method.maxIterations && !converged; ++iteration)
622 Linearization
const linearization = atIterate();
623 Gain crossed(delta.size(), linearization.residual.size());
624 NoiseMatrix innovationCov = linearization.noise;
625 addSpread(*spread, linearization.jacobian, crossed, innovationCov);
626 auto const llt = Eigen::LLT<NoiseMatrix>{innovationCov};
627 if (llt.info() != Eigen::Success)
631 auto next = Difference{};
632 next.resize(delta.size());
633 next.noalias() = multiply(crossed, llt.solve(linearization.residual));
634 if constexpr (Spreads)
638 auto const readCross = std::as_const(crossed)(reads.differenceIndices(), Eigen::placeholders::all);
639 using ReadCross = MatrixOf<
641 Reads::DifferenceSize,
642 Gain::ColsAtCompileTime,
643 Reads::DifferenceMaxSize,
644 Gain::MaxColsAtCompileTime>;
645 ReadMatrix posterior = priorReadCov;
646 posterior.noalias() -=
647 multiply(transposedSolve<ReadCross>(llt, readCross.transpose()), readCross.transpose());
650 ReadDifference
const nextReadStep = next(reads.differenceIndices());
651 auto const reset =
resetJacobian(reads.space(), readMean, nextReadStep);
652 posterior = multiply(multiply(reset, posterior), reset.transpose()).eval();
654 spreadRoot = lowerTriangularRoot(defaultRoot(posterior));
656 converged = withinScale(next, delta, scale);
659 return Result{IteratedLinearization<Linearization>{atIterate(), iteration + 1, converged}};
665template <
typename Update,
typename Iterated>
667withIterations(Update
update, Iterated
const & iterated)
669 auto const report = [&](
auto & filterUpdate) {
670 for (
auto & branch : filterUpdate.branches)
672 branch.iterations =
iterated.iterations;
673 branch.converged =
iterated.converged;
676 if constexpr (
requires {
update.has_value(); })
699template <
typename Scalar,
typename Space,
typename Reads,
typename Read,
typename R,
typename Method>
701linearizeMeasurementAtRoot(
706 Method
const & method
709 auto const f = ResolvedFunction{resolved};
710 auto const predicted = transformMeasurement(resolved, method, f, read);
714 return assembleLinearization<Scalar>(
718 predicted.output().space(),
719 predicted.output().mean(),
726template <
typename Scalar,
typename Space,
typename Reads,
typename Read,
typename R>
728linearizeMeasurementAtRoot(Space
const & space, Reads
const & reads, Read
const & read, R
const & resolved)
730 return linearizeMeasurementAtRoot<Scalar>(space, reads, read, resolved, resolved.method());
736template <
typename Scalar,
typename Space,
typename M>
737using LinearizationOf = MeasurementLinearization<Space, typename ResolvedMeasurement<M, Space>::Out, Scalar>;
742template <
typename Matrix>
744infiniteCovariance(Eigen::Index m)
746 Matrix result = Matrix::Zero(m, m);
747 result.diagonal().setConstant(std::numeric_limits<typename Matrix::Scalar>::infinity());
754template <
typename MeasurementSpace,
typename Scalar>
755[[nodiscard]] FilterUpdate<MeasurementSpace, 1, Scalar>
756oneBranch(Innovation<MeasurementSpace, Scalar> innovation,
bool accepted =
true)
758 return FilterUpdate<MeasurementSpace, 1, Scalar>{
759 {FilterBranch<MeasurementSpace, Scalar>{Scalar(0), std::move(innovation), 0, 0}},
787template <
typename Space,
typename Scalar,
typename MeasurementSpace,
typename Accept = AcceptEvery>
788[[nodiscard]] std::expected<FilterUpdate<MeasurementSpace, 1, Scalar>,
GaussianError>
790 SqrtGaussianParams<Space, Scalar> & state,
791 MeasurementLinearization<Space, MeasurementSpace, Scalar>
const & linearization,
792 Accept
const & accept = {}
795 using Form = SqrtGaussianParams<Space, Scalar>;
796 using InnovationGaussian = GaussianParams<MeasurementSpace, Scalar>;
797 constexpr int N = Form::DifferenceDimensionAtCompileTime;
798 constexpr int NMax = Form::MaxDifferenceDimensionAtCompileTime;
799 constexpr int M = InnovationGaussian::DifferenceDimensionAtCompileTime;
800 constexpr int MMax = InnovationGaussian::MaxDifferenceDimensionAtCompileTime;
801 using Joint = MatrixOf<Scalar, sizeSum<M, N>, sizeSum<M, N>, sizeSum<MMax, NMax>, sizeSum<MMax, NMax>>;
802 using GainFactor = MatrixOf<Scalar, N, M, NMax, MMax>;
803 auto const & space = state.space();
804 Eigen::Index
const n = state.differenceDimension();
805 Eigen::Index
const m = linearization.residual.size();
806 auto const & factor = state.root();
808 Joint array(m + n, m + n);
809 array.topLeftCorner(m, n).noalias() = multiply(linearization.jacobian, asTriangular<Eigen::Lower>(factor));
810 array.topRightCorner(m, m) = defaultRoot(linearization.noise);
811 array.bottomLeftCorner(n, n) = factor;
812 array.bottomRightCorner(n, m).setZero();
813 Joint
const lower = lowerTriangularRoot(array);
814 auto const innovationFactor = blockOf<M, M>(lower, 0, 0, m, m);
815 if ((innovationFactor.diagonal().array() == Scalar(0)).any())
819 GainFactor
const gainFactor = lower.block(m, 0, n, m);
821 typename InnovationGaussian::DifferenceVectorType whitened = linearization.residual;
822 innovationFactor.template triangularView<Eigen::Lower>().solveInPlace(whitened);
823 auto const statistics = InnovationStatistics<Scalar>{
824 whitened.squaredNorm(),
825 Scalar(2) * innovationFactor.diagonal().array().abs().log().sum()
827 typename InnovationGaussian::MatrixType innovationCov = multiply(innovationFactor, innovationFactor.transpose());
828 if constexpr (acceptsByNis<Accept>)
830 if (!accept(statistics.nis, m))
833 Innovation<MeasurementSpace, Scalar>{linearization.residual, std::move(innovationCov), statistics},
839 typename Form::DifferenceVectorType
const step = multiply(gainFactor, whitened);
840 typename Form::VectorType
const start = state.mean();
841 typename Form::MatrixType posterior = lower.bottomRightCorner(n, n);
845 posterior = lowerTriangularRoot(
typename Form::MatrixType{multiply(g, posterior)});
848 state.setRoot(std::move(posterior));
850 Innovation<MeasurementSpace, Scalar>{linearization.residual, std::move(innovationCov), statistics}
858template <
typename Reads,
typename Space,
typename Scalar>
859[[nodiscard]] RootInput<typename Reads::JointSpace, Scalar>
860readRoot(Reads
const & reads, SqrtGaussianParams<Space, Scalar>
const & state)
862 using Result = RootInput<typename Reads::JointSpace, Scalar>;
863 using Rows = MatrixOf<
865 Reads::DifferenceSize,
867 Reads::DifferenceMaxSize,
869 Rows
const rows = state.root()(reads.differenceIndices(), Eigen::placeholders::all);
870 return Result{reads.space(),
typename Result::VectorType{state.mean()(reads.indices())}, lowerTriangularRoot(rows)};
878template <
typename Reads,
typename Po
int,
typename Root>
879[[nodiscard]] RootInput<typename Reads::JointSpace, typename Root::Scalar>
880readRootOf(Reads
const & reads, Point
const & point, Root
const & covarianceRoot)
882 using Scalar =
typename Root::Scalar;
883 using Result = RootInput<typename Reads::JointSpace, Scalar>;
884 using Rows = MatrixOf<
886 Reads::DifferenceSize,
887 Root::ColsAtCompileTime,
888 Reads::DifferenceMaxSize,
889 Root::MaxColsAtCompileTime>;
890 Rows
const rows = covarianceRoot(reads.differenceIndices(), Eigen::placeholders::all);
891 return Result{reads.space(),
typename Result::VectorType{point(reads.indices())}, lowerTriangularRoot(rows)};
911 typename Reference = NoReference,
912 typename Accept = AcceptEvery>
915 SqrtGaussianParams<Space, Scalar> & state,
916 M
const & measurement,
917 Reference
const & reference = {},
918 Accept
const & accept = {}
922 !hasInnovationRepair<M>,
923 "repairing the innovation covariance is the covariance form's (decisions.md [gaussian-forms])"
927 "a consider() update is the covariance form's: the square-root and information forms keep no block's "
928 "covariance as it was (decisions.md [consider-states]); filter in a Gaussian"
932 "a Kalman update pushes the prior through the model by a method: observe(method, model, z)"
934 using Method =
typename M::MethodType;
935 auto const & space = state.space();
936 auto const resolved = resolveMeasurement(measurement, space);
937 if constexpr (isLinearizedAbout<Reference>)
939 return foldIntoSqrt(state, linearizeMeasurementAbout<Scalar>(space, state.mean(), reference, resolved), accept);
941 else if constexpr (isIterated<Method>)
945 auto const spread = std::optional<TriangularRoot<Matrix, Eigen::Lower>>{std::in_place, state.root()};
946 auto const iterated = iterateMeasurementLinearization<Scalar>(space, state.mean(), spread, resolved);
947 using Result =
decltype(foldIntoSqrt(state,
iterated->linearization, accept));
950 return Result{std::unexpected{
iterated.error()}};
952 return withIterations(foldIntoSqrt(state,
iterated->linearization, accept), *iterated);
954 else if constexpr (isLinearMethod<Method>)
956 return foldIntoSqrt(state, linearizeMeasurementAtPoint<Scalar>(space, state.mean(), resolved), accept);
960 auto const & reads = resolved.reads();
963 linearizeMeasurementAtRoot<Scalar>(space, reads, readRoot(reads, state), resolved),
983template <
typename Space,
typename Scalar,
typename MeasurementSpace,
typename Accept = AcceptEvery>
984[[nodiscard]] std::expected<FilterUpdate<MeasurementSpace, 1, Scalar>,
GaussianError>
986 InfoGaussianParams<Space, Scalar> & state,
987 MeasurementLinearization<Space, MeasurementSpace, Scalar>
const & linearization,
989 Accept
const & accept = {}
993 using Lin = MeasurementLinearization<Space, MeasurementSpace, Scalar>;
994 Eigen::Index
const m = linearization.residual.size();
995 auto const llt = Eigen::LLT<InnovationMatrix>{linearization.noise};
996 if (llt.info() != Eigen::Success)
1000 typename Lin::JacobianMatrix whitened = linearization.jacobian;
1001 solveInPlace(llt, whitened);
1003 added.noalias() = multiply(linearization.jacobian.transpose(), whitened);
1005 vector.noalias() = multiply(linearization.jacobian.transpose(), llt.solve(linearization.residual));
1007 auto innovation = [&] {
1011 return Innovation<MeasurementSpace, Scalar>{
1012 linearization.residual,
1013 infiniteCovariance<InnovationMatrix>(m),
1014 InnovationStatistics<Scalar>{Scalar(0), std::numeric_limits<Scalar>::infinity()}
1017 InnovationMatrix innovationCov = linearization.noise;
1018 innovationCov.noalias() +=
1019 multiply(multiply(linearization.jacobian, *covariance), linearization.jacobian.transpose());
1020 return Innovation<MeasurementSpace, Scalar>{linearization.residual, std::move(innovationCov)};
1022 if constexpr (acceptsByNis<Accept>)
1024 if (!accept(innovation.nis(), m))
1026 return oneBranch(std::move(innovation),
false);
1029 state.addInfo(added, vector);
1030 return oneBranch(std::move(innovation));
1053 typename Reference = NoReference,
1054 typename Accept = AcceptEvery>
1057 InfoGaussianParams<Space, Scalar> & state,
1058 M
const & measurement,
1059 Reference
const & reference = {},
1060 Accept
const & accept = {}
1064 !hasInnovationRepair<M>,
1065 "repairing the innovation covariance is the covariance form's (decisions.md [gaussian-forms])"
1069 "a consider() update is the covariance form's: the square-root and information forms keep no block's "
1070 "covariance as it was (decisions.md [consider-states]); filter in a Gaussian"
1074 "a Kalman update pushes the prior through the model by a method: observe(method, model, z)"
1076 using Form = InfoGaussianParams<Space, Scalar>;
1077 using Method =
typename M::MethodType;
1078 using Lin = LinearizationOf<Scalar, Space, M>;
1079 using Result = std::expected<FilterUpdate<typename Lin::MeasurementSpaceType, 1, Scalar>,
GaussianError>;
1080 auto const & space = state.space();
1081 auto const resolved = resolveMeasurement(measurement, space);
1083 auto const mean = state.mean();
1086 return Result{std::unexpected{mean.error()}};
1088 auto covariance = std::optional<typename Form::MatrixType>{};
1089 auto root = std::optional<typename Form::MatrixType>{};
1092 state.setReference(*mean);
1093 auto factor = state.covarianceRoot();
1096 return Result{std::unexpected{factor.error()}};
1098 root = std::move(*factor);
1099 covariance = multiply(*root, root->transpose());
1101 if constexpr (isLinearizedAbout<Reference>)
1103 return foldIntoInfo(
1105 linearizeMeasurementAbout<Scalar>(space, state.reference(), reference, resolved),
1110 else if constexpr (isIterated<Method>)
1112 if constexpr (!isLinearMethod<std::remove_cvref_t<
decltype(measurement.method().method)>>)
1119 auto const iterated = iterateMeasurementLinearization<Scalar>(space, state.reference(), covariance, resolved);
1122 return Result{std::unexpected{
iterated.error()}};
1124 return withIterations(foldIntoInfo(state,
iterated->linearization, covariance, accept), *iterated);
1126 else if constexpr (isLinearMethod<Method>)
1128 return foldIntoInfo(
1130 linearizeMeasurementAtPoint<Scalar>(space, state.reference(), resolved),
1141 auto const & reads = resolved.reads();
1142 return foldIntoInfo(
1144 linearizeMeasurementAtRoot<Scalar>(space, reads, readRootOf(reads, state.reference(), *root), resolved),
1170template <
typename Space,
typename Scalar,
typename MeasurementSpace,
typename Accept = AcceptEvery>
1171[[nodiscard]] std::expected<FilterUpdate<MeasurementSpace, 1, Scalar>,
GaussianError>
1173 SqrtInfoGaussianParams<Space, Scalar> & state,
1174 MeasurementLinearization<Space, MeasurementSpace, Scalar>
const & linearization,
1176 Accept
const & accept = {}
1179 using Form = SqrtInfoGaussianParams<Space, Scalar>;
1180 using InnovationGaussian = GaussianParams<MeasurementSpace, Scalar>;
1181 using InnovationMatrix =
typename InnovationGaussian::MatrixType;
1182 constexpr int N = Form::DifferenceDimensionAtCompileTime;
1183 constexpr int NMax = Form::MaxDifferenceDimensionAtCompileTime;
1184 constexpr int M = InnovationGaussian::DifferenceDimensionAtCompileTime;
1185 constexpr int MMax = InnovationGaussian::MaxDifferenceDimensionAtCompileTime;
1186 using Stacked = MatrixOf<Scalar, sizeSum<N, M>, sizeSum<N, 1>, sizeSum<NMax, MMax>, sizeSum<NMax, 1>>;
1187 Eigen::Index
const n = state.differenceDimension();
1188 Eigen::Index
const m = linearization.residual.size();
1190 auto const llt = Eigen::LLT<InnovationMatrix>{linearization.noise};
1191 if (llt.info() != Eigen::Success)
1195 Stacked stacked(n + m, n + 1);
1196 stacked.topLeftCorner(n, n) = state.infoRoot();
1197 stacked.col(n).head(n) = state.whitenedOffset();
1198 typename MeasurementLinearization<Space, MeasurementSpace, Scalar>::JacobianMatrix whitened =
1199 linearization.jacobian;
1200 solveInPlace(llt.matrixL(), whitened);
1201 stacked.bottomLeftCorner(m, n) = whitened;
1202 stacked.col(n).tail(m) = llt.matrixL().solve(linearization.residual);
1203 Scalar
const priorLogDet = Scalar(2) * state.infoRoot().diagonal().array().abs().log().sum();
1206 Scalar
const nis = stacked.col(n).tail(m).squaredNorm();
1207 Scalar logDeterminant = std::numeric_limits<Scalar>::infinity();
1208 InnovationMatrix innovationCov = infiniteCovariance<InnovationMatrix>(m);
1211 Scalar
const posteriorLogDet = Scalar(2) * stacked.diagonal().head(n).array().abs().log().sum();
1212 logDeterminant = Scalar(2) * llt.matrixLLT().diagonal().array().log().sum() + posteriorLogDet - priorLogDet;
1213 typename MeasurementLinearization<Space, MeasurementSpace, Scalar>::JacobianMatrix
const scaled =
1214 multiply(linearization.jacobian, *covarianceRoot);
1215 innovationCov = linearization.noise;
1216 innovationCov.noalias() += multiply(scaled, scaled.transpose());
1218 auto innovation = Innovation<MeasurementSpace, Scalar>{
1219 linearization.residual,
1220 std::move(innovationCov),
1221 InnovationStatistics<Scalar>{nis, logDeterminant}
1223 if constexpr (acceptsByNis<Accept>)
1225 if (!accept(nis, m))
1227 return oneBranch(std::move(innovation),
false);
1231 typename Form::MatrixType{stacked.topLeftCorner(n, n)},
1232 typename Form::DifferenceVectorType{stacked.col(n).head(n)}
1234 return oneBranch(std::move(innovation));
1251 typename Reference = NoReference,
1252 typename Accept = AcceptEvery>
1255 SqrtInfoGaussianParams<Space, Scalar> & state,
1256 M
const & measurement,
1257 Reference
const & reference = {},
1258 Accept
const & accept = {}
1262 !hasInnovationRepair<M>,
1263 "repairing the innovation covariance is the covariance form's (decisions.md [gaussian-forms])"
1267 "a consider() update is the covariance form's: the square-root and information forms keep no block's "
1268 "covariance as it was (decisions.md [consider-states]); filter in a Gaussian"
1272 "a Kalman update pushes the prior through the model by a method: observe(method, model, z)"
1274 using Form = SqrtInfoGaussianParams<Space, Scalar>;
1275 using Method =
typename M::MethodType;
1276 using Lin = LinearizationOf<Scalar, Space, M>;
1277 using Result = std::expected<FilterUpdate<typename Lin::MeasurementSpaceType, 1, Scalar>,
GaussianError>;
1278 auto const & space = state.space();
1279 auto const resolved = resolveMeasurement(measurement, space);
1281 auto const mean = state.mean();
1284 return Result{std::unexpected{mean.error()}};
1286 auto root = std::optional<typename Form::MatrixType>{};
1289 state.setReference(*mean);
1290 auto factor = state.covarianceRoot();
1291 root = std::move(*factor);
1293 if constexpr (isLinearizedAbout<Reference>)
1295 return foldIntoSqrtInfo(
1297 linearizeMeasurementAbout<Scalar>(space, state.reference(), reference, resolved),
1302 else if constexpr (isIterated<Method>)
1304 auto spread = std::optional<TriangularRoot<typename Form::MatrixType, Eigen::Upper>>{};
1309 else if constexpr (!isLinearMethod<std::remove_cvref_t<
decltype(measurement.method().method)>>)
1313 auto const iterated = iterateMeasurementLinearization<Scalar>(space, state.reference(), spread, resolved);
1316 return Result{std::unexpected{
iterated.error()}};
1318 return withIterations(foldIntoSqrtInfo(state,
iterated->linearization, root, accept), *iterated);
1320 else if constexpr (isLinearMethod<Method>)
1322 return foldIntoSqrtInfo(
1324 linearizeMeasurementAtPoint<Scalar>(space, state.reference(), resolved),
1335 auto const & reads = resolved.reads();
1336 return foldIntoSqrtInfo(
1338 linearizeMeasurementAtRoot<Scalar>(space, reads, readRootOf(reads, state.reference(), *root), resolved),
1351template <
typename Space,
typename Scalar,
typename Transition,
typename NoiseRoot,
typename Mean>
1354 SqrtGaussianParams<Space, Scalar> & state,
1355 Transition
const & transition,
1356 NoiseRoot
const & noiseRoot,
1360 using Form = SqrtGaussianParams<Space, Scalar>;
1361 constexpr int N = Form::DifferenceDimensionAtCompileTime;
1362 constexpr int NMax = Form::MaxDifferenceDimensionAtCompileTime;
1363 using Stacked = MatrixOf<Scalar, N, sizeSum<N, N>, NMax, sizeSum<NMax, NMax>>;
1364 Eigen::Index
const n = state.differenceDimension();
1365 Stacked stacked(n, 2 * n);
1366 stacked.leftCols(n).noalias() = multiply(transition, asTriangular<Eigen::Lower>(state.root()));
1367 stacked.rightCols(n) = noiseRoot;
1368 state.setMean(std::forward<Mean>(mean));
1369 state.setRoot(lowerTriangularRoot(stacked));
1395 typename Reference = NoReference>
1396[[nodiscard]] std::expected<void, GaussianError>
1397predictRootWithNoise(
1398 Method
const & method,
1399 SqrtGaussianParams<Space, Scalar> & state,
1402 Eigen::MatrixBase<Noise>
const & noise,
1403 Reference
const & about = {}
1406 using Form = SqrtGaussianParams<Space, Scalar>;
1407 using MatrixType =
typename Form::MatrixType;
1408 constexpr int N = Form::DifferenceDimensionAtCompileTime;
1409 constexpr int NMax = Form::MaxDifferenceDimensionAtCompileTime;
1410 auto const & space = state.space();
1411 Eigen::Index
const n = state.differenceDimension();
1414 auto const throughMoments = [&]() -> std::expected<void, GaussianError> {
1415 auto covariance = state.covariance();
1416 auto const prior = GaussianParams<Space, Scalar>{space, state.mean(), std::move(*covariance)};
1417 GaussianParams<Space, Scalar>
const predicted = predictWithNoise(method, prior, resolved, dt, noise, about);
1418 state.setMean(predicted.mean());
1420 state.setRoot(lowerTriangularRoot(defaultRoot(symmetricFromLower<MatrixType>(predicted.covarianceLower()))));
1423 if constexpr (isLinearizedAbout<Reference>)
1425 return throughMoments();
1427 else if constexpr (predictsByJacobian<Method, R>)
1429 MatrixType
const noiseRoot = defaultRoot(symmetricFromLower<MatrixType>(noise));
1430 auto step = stepWithJacobian(resolved, state.mean(), dt);
1431 propagateRoot(state, step.jacobian, noiseRoot, std::move(step.value));
1437 [&](
auto const &... inputs) -> std::expected<void, GaussianError> {
1438 MatrixType
const noiseRoot = defaultRoot(symmetricFromLower<MatrixType>(noise));
1439 auto const f = ProcessStep{resolved, dt};
1440 using Input = RootInput<Space, Scalar>;
1441 using Problem = Transform<
decltype(f)
const, Space, Input, std::remove_cvref_t<
decltype(inputs)>...>;
1442 auto const input = Input{space, state.mean(), state.root()};
1443 if constexpr (isLinearMethod<Method>)
1445 auto const problem = Problem{f, space, input, inputs...};
1446 auto const linearized = linearizeAt(method, problem);
1447 using Stacked = MatrixOf<
1450 sizeSum<Problem::InputDifferenceSize, N>,
1452 sizeSum<Problem::InputDifferenceMaxSize, NMax>>;
1453 Stacked stacked(n, problem.inputDifferenceSize() + n);
1454 problem.forEachUncertain([&]<std::size_t I>(
auto const & in) {
1455 Eigen::Index
const d = in.differenceDimension();
1456 Eigen::Index
const offset = problem.differenceOffset(I);
1457 using In = std::remove_cvref_t<
decltype(in)>;
1459 middleColsOf<In::DifferenceDimensionAtCompileTime>(
linearized.jacobian, offset, d);
1460 if constexpr (I == 0)
1462 stacked.middleCols(offset, d).noalias() =
1463 multiply(
block, asTriangular<Eigen::Lower>(in.root()));
1467 using Cov = MatrixOf<
1469 In::DifferenceDimensionAtCompileTime,
1470 In::DifferenceDimensionAtCompileTime,
1471 In::MaxDifferenceDimensionAtCompileTime,
1472 In::MaxDifferenceDimensionAtCompileTime>;
1473 stacked.middleCols(offset, d).noalias() =
1474 multiply(
block, defaultRoot(symmetricFromLower<Cov>(covarianceLowerOf(in))));
1477 stacked.rightCols(n) = noiseRoot;
1478 state.setMean(
typename Form::VectorType{
linearized.mean});
1479 state.setRoot(lowerTriangularRoot(stacked));
1482 else if constexpr (isSigmaPointMethod<Method>)
1484 auto const problem = Problem{f, space, input, inputs...};
1485 auto deviations = transformRoot(method, problem);
1486 using Deviations =
decltype(deviations);
1487 Eigen::Index
const points = deviations.root.cols();
1488 if (!deviations.centerNegative)
1490 using Stacked = MatrixOf<
1493 sizeSum<Deviations::Points, N>,
1495 sizeSum<Deviations::MaxPoints, NMax>>;
1496 Stacked stacked(n, points + n);
1497 stacked.leftCols(points) = deviations.root;
1498 stacked.rightCols(n) = noiseRoot;
1499 state.setMean(
typename Form::VectorType{std::move(deviations.mean)});
1500 state.setRoot(lowerTriangularRoot(stacked));
1503 auto const spread = deviations.root.leftCols(points - 1);
1504 auto const center = deviations.root.col(points - 1);
1505 MatrixType cov = symmetricFromLower<MatrixType>(noise);
1506 cov.noalias() += multiply(spread,
spread.transpose());
1507 cov.noalias() -= multiply(center, center.transpose());
1508 cov = (Scalar(0.5) * (cov + cov.transpose())).eval();
1509 auto const llt = Eigen::LLT<MatrixType>{cov};
1510 if (llt.info() != Eigen::Success)
1514 state.setMean(
typename Form::VectorType{std::move(deviations.mean)});
1515 state.setRoot(MatrixType{llt.matrixL()});
1520 return throughMoments();
1531template <
typename Method,
typename Space,
typename Scalar, ProcessModel Model,
typename... Args>
1532[[nodiscard]] std::expected<void, GaussianError>
1534 Method
const & method,
1535 SqrtGaussianParams<Space, Scalar> & state,
1536 Model
const & model,
1538 Args
const &... args
1541 internal::assertPartitions(model, state.space());
1542 return withReference(
1543 [&](
auto const & about,
auto const &... inputs) {
1544 auto const call = modelWith(std::cref(model), inputs...);
1545 auto const resolved = resolveProcess(call, state.space());
1546 return predictRootWithNoise(method, state, resolved, dt, resolved.template noise<Scalar>(dt), about);
1564[[nodiscard]] std::expected<void, GaussianError>
1566 SqrtGaussianParams<Space, Scalar> & state,
1567 FixedStepModel<Space_, Model_, Method_, Scalar_>
const & model,
1568 Args
const &... args
1571 using Model = FixedStepModel<Space_, Model_, Method_, Scalar_>;
1572 static_assert(std::is_same_v<Space, Space_>,
"the model must be over the state's space");
1573 static_assert(std::is_same_v<Scalar, Scalar_>,
"the model's scalar must be the state's");
1574 internal::assertPartitions(model, state.space());
1575 if constexpr (Model::CachesTransition &&
sizeof...(Args) == 0)
1577 propagateRoot(state, model.transition(), model.noiseRoot(), model.propagate(state.space(), state.mean()));
1582 return withReference(
1583 [&](
auto const & about,
auto const &... inputs) {
1584 auto const call = modelWith(std::cref(model.model()), inputs...);
1585 auto const resolved = resolveProcess(call, state.space());
1586 return predictRootWithNoise(model.method(), state, resolved, model.timeStep(), model.noise(), about);
1600template <
typename Method,
typename Space,
typename Scalar,
typename Model,
typename... Inputs>
1601[[nodiscard]] std::expected<void, GaussianError>
1603 Method
const & method,
1604 InfoGaussianParams<Space, Scalar> & state,
1605 Model
const & model,
1607 Inputs
const &... inputs
1613 return std::unexpected{gaussian.error()};
1618 return std::unexpected{info.error()};
1620 state = std::move(*info);
1635[[nodiscard]] std::expected<void, GaussianError>
1637 InfoGaussianParams<Space, Scalar> & state,
1638 FixedStepModel<Space_, Model_, Method_, Scalar_>
const & model,
1639 Inputs
const &... inputs
1645 return std::unexpected{gaussian.error()};
1650 return std::unexpected{info.error()};
1652 state = std::move(*info);
1671template <
typename Space,
typename Scalar,
typename Transition,
typename NoiseRoot>
1672[[nodiscard]] std::expected<void, GaussianError>
1674 SqrtInfoGaussianParams<Space, Scalar> & state,
1675 Transition
const & transition,
1676 NoiseRoot
const & noiseRoot,
1681 auto const lu = Eigen::FullPivLU<MatrixType>{transition};
1682 if (!lu.isInvertible())
1686 propagateRootInfoByInverse(state, inverseFrom<MatrixType>(lu), noiseRoot, std::move(propagated));
1694template <
typename Space,
typename Scalar,
typename Inverse,
typename NoiseRoot>
1696propagateRootInfoByInverse(
1697 SqrtInfoGaussianParams<Space, Scalar> & state,
1698 Inverse
const & inverse,
1699 NoiseRoot
const & noiseRoot,
1703 using Form = SqrtInfoGaussianParams<Space, Scalar>;
1704 using MatrixType =
typename Form::MatrixType;
1705 constexpr int N = Form::DifferenceDimensionAtCompileTime;
1706 constexpr int NMax = Form::MaxDifferenceDimensionAtCompileTime;
1707 using Stacked = MatrixOf<Scalar, sizeSum<N, N>, sizeSum<N, N, 1>, sizeSum<NMax, NMax>, sizeSum<NMax, NMax, 1>>;
1708 Eigen::Index
const n = state.differenceDimension();
1710 MatrixType
const scaled = multiply(asTriangular<Eigen::Upper>(state.infoRoot()), inverse);
1711 Stacked stacked = Stacked::Zero(2 * n, 2 * n + 1);
1712 stacked.topLeftCorner(n, n).setIdentity();
1713 stacked.block(n, 0, n, n).noalias() = -multiply(scaled, noiseRoot);
1714 stacked.block(n, n, n, n) = scaled;
1715 stacked.col(2 * n).tail(n) = state.whitenedOffset();
1719 std::move(propagated),
1720 MatrixType{stacked.block(n, n, n, n)},
1721 typename Form::DifferenceVectorType{stacked.col(2 * n).tail(n)}
1746 typename Reference = NoReference>
1747[[nodiscard]] std::expected<void, GaussianError>
1748predictRootInfoWithNoise(
1749 Method
const & method,
1750 SqrtInfoGaussianParams<Space, Scalar> & state,
1753 Eigen::MatrixBase<Noise>
const & noise,
1754 Reference
const & about = {}
1757 using Form = SqrtInfoGaussianParams<Space, Scalar>;
1758 using MatrixType =
typename Form::MatrixType;
1759 using VectorType =
typename Form::VectorType;
1760 auto const & space = state.space();
1761 Eigen::Index
const n = state.differenceDimension();
1762 if constexpr (isLinearMethod<Method>)
1764 auto const mean = state.mean();
1767 state.setReference(*mean);
1771 return std::unexpected{mean.error()};
1773 VectorType
const & reference = state.reference();
1774 MatrixType total = symmetricFromLower<MatrixType>(noise);
1775 if constexpr (isLinearizedAbout<Reference>)
1778 auto const linearization = linearizeStepAbout(method, resolved, space, dt, reference, about);
1779 total += linearization.error();
1780 return propagateRootInfo(
1782 linearization.jacobian,
1784 VectorType{linearization.value}
1787 else if constexpr (predictsByJacobian<Method, R>)
1789 auto step = stepWithJacobian(resolved, reference, dt);
1791 return propagateRootInfo(state, step.jacobian, defaultRoot(total), std::move(step.value));
1796 [&](
auto const &... inputs) -> std::expected<void, GaussianError> {
1797 auto const f = ProcessStep{resolved, dt};
1798 using Point = PointInput<Space, Scalar>;
1800 Transform<
decltype(f)
const, Space, Point, std::remove_cvref_t<
decltype(inputs)>...>;
1801 auto const point = Point{space, reference};
1802 auto const problem = Problem{f, space, point, inputs...};
1803 auto const linearized = linearizeAt(method, problem);
1804 MatrixType
const transition =
linearized.jacobian.middleCols(problem.differenceOffset(0), n);
1805 problem.forEachUncertain([&]<std::size_t I>(
auto const & in) {
1806 if constexpr (I != 0)
1808 using In = std::remove_cvref_t<
decltype(in)>;
1809 using Cov = MatrixOf<
1811 In::DifferenceDimensionAtCompileTime,
1812 In::DifferenceDimensionAtCompileTime,
1813 In::MaxDifferenceDimensionAtCompileTime,
1814 In::MaxDifferenceDimensionAtCompileTime>;
1815 Eigen::Index
const d = in.differenceDimension();
1816 auto const block = middleColsOf<In::DifferenceDimensionAtCompileTime>(
1818 problem.differenceOffset(I),
1821 total.noalias() += multiply(
1822 multiply(
block, symmetricFromLower<Cov>(covarianceLowerOf(in))),
1827 return propagateRootInfo(state, transition, defaultRoot(total), VectorType{
linearized.mean});
1838 return std::unexpected{gaussian.error()};
1840 auto result =
toSqrtInfo(predictWithNoise(method, *gaussian, resolved, dt, noise, about));
1843 return std::unexpected{result.error()};
1845 state = std::move(*result);
1853template <
typename Method,
typename Space,
typename Scalar, ProcessModel Model,
typename... Args>
1854[[nodiscard]] std::expected<void, GaussianError>
1856 Method
const & method,
1857 SqrtInfoGaussianParams<Space, Scalar> & state,
1858 Model
const & model,
1860 Args
const &... args
1863 internal::assertPartitions(model, state.space());
1864 return withReference(
1865 [&](
auto const & about,
auto const &... inputs) {
1866 auto const call = modelWith(std::cref(model), inputs...);
1867 auto const resolved = resolveProcess(call, state.space());
1868 return predictRootInfoWithNoise(method, state, resolved, dt, resolved.template noise<Scalar>(dt), about);
1887[[nodiscard]] std::expected<void, GaussianError>
1889 SqrtInfoGaussianParams<Space, Scalar> & state,
1890 FixedStepModel<Space_, Model_, Method_, Scalar_>
const & model,
1891 Args
const &... args
1894 using Model = FixedStepModel<Space_, Model_, Method_, Scalar_>;
1895 static_assert(std::is_same_v<Space, Space_>,
"the model must be over the state's space");
1896 static_assert(std::is_same_v<Scalar, Scalar_>,
"the model's scalar must be the state's");
1897 internal::assertPartitions(model, state.space());
1898 if constexpr (Model::CachesTransition &&
sizeof...(Args) == 0)
1901 auto const mean = state.mean();
1904 state.setReference(*mean);
1908 return std::unexpected{mean.error()};
1910 VectorType propagated = model.propagate(state.space(), state.reference());
1913 if (!model.transitionInverse())
1917 propagateRootInfoByInverse(state, *(model.transitionInverse()), model.noiseRoot(), std::move(propagated));
1922 return withReference(
1923 [&](
auto const & about,
auto const &... inputs) {
1924 auto const call = modelWith(std::cref(model.model()), inputs...);
1925 auto const resolved = resolveProcess(call, state.space());
1926 return predictRootInfoWithNoise(
What a container of several Gaussians needs of each one (decisions.md [component-first]): the Compone...
The coordinate types (decisions.md [no-bounded-coordinates]): Linear, plain coordinates,...
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
What marginals and conditionals are built from: resolving Eigen index sets against a space; the share...
The information form of the Gaussian (decisions.md [gaussian-forms]): its parameters InfoGaussianPara...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
The update of a Gaussian by a measurement (decisions.md [templated-measurements], [weighted-branches]...
Moments: the mean and covariance that a Gaussian carries and that a mixture or a sample set is moment...
Products of fixed-size matrices by Eigen's fixed-size product at every size: multiply() is by Eigen'...
Process models as functions with reads and writes (decisions.md [model-policies], [continuous-time-no...
The covariance reset (decisions.md [covariance-reset]): hasIdentityReset<>, resetJacobian(),...
Drawing samples: SamplesWithLogDensity and SampleWithLogDensity, the Gaussian draws drawSamples(),...
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...
The square-root form of the Gaussian (decisions.md [gaussian-forms]): its parameters SqrtGaussianPara...
The square-root information form of the Gaussian (decisions.md [gaussian-forms]): its parameters Sqrt...
Triangularization: the triangular factor of a stacked matrix by Householder reflections,...
typename MomentsType::MatrixType MatrixType
a matrix over differences
Definition Gaussian.h:267
typename MomentsType::VectorType VectorType
a value, such as the mean
Definition Gaussian.h:265
typename MomentsType::DifferenceVectorType DifferenceVectorType
a difference, such as a residual
Definition Gaussian.h:266
typename MomentsType::DifferenceVectorType DifferenceVectorType
A difference, or the information vector.
Definition InfoGaussian.h:83
typename MomentsType::MatrixType MatrixType
a matrix over differences
Definition InfoGaussian.h:85
DifferenceMatrix< Space_, Space_, Scalar > MatrixType
Definition Moments.h:76
DifferenceVector< Space_, Scalar > DifferenceVectorType
a difference, such as a residual
Definition Moments.h:75
ValueVector< Space_, Scalar > VectorType
Definition Moments.h:74
static constexpr int MaxDifferenceDimensionAtCompileTime
Definition Moments.h:72
static constexpr int DifferenceDimensionAtCompileTime
Definition Moments.h:69
static constexpr int MaxValueDimensionAtCompileTime
Definition Moments.h:66
static constexpr int ValueDimensionAtCompileTime
Definition Moments.h:63
static constexpr int DifferenceDimensionAtCompileTime
the length of a difference and the rows of the root, or Eigen::Dynamic
Definition SqrtGaussian.h:100
static constexpr int MaxDifferenceDimensionAtCompileTime
a bound on the length of a difference, or Eigen::Dynamic
Definition SqrtGaussian.h:103
typename MomentsType::MatrixType MatrixType
a matrix over differences
Definition SqrtGaussian.h:89
typename MomentsType::VectorType VectorType
a value, such as the reference
Definition SqrtInfoGaussian.h:75
typename MomentsType::MatrixType MatrixType
a matrix over differences
Definition SqrtInfoGaussian.h:77
void triangularize(M &&m)
Reduces m to upper-triangular form in place by Householder reflections from the left,...
Definition Triangularization.h:52
#define EMRYS_FILTER_NO_UNIQUE_ADDRESS
Assertion used for programmer errors (misuse of the API).
Definition Macros.h:38
@ NotPositiveDefinite
the covariance is not positive definite, so it has no Cholesky factor or inverse
Definition NumericError.h:31
@ Singular
the precision is not positive definite, so the mean and covariance are undefined
Definition NumericError.h:32
NumericError GaussianError
Reasons a Gaussian, in any of its forms (decisions.md [gaussian-forms]), can fail to give a density,...
Definition NumericError.h:45
std::expected< InfoGaussianParams< typename G::SpaceType, typename G::Scalar >, GaussianError > toInfo(G const &form)
Definition InfoGaussian.h:798
CategoricalParams< Space, Scalar > predict(CategoricalParams< Space, Scalar > const &prior, MarkovChain< Space, Scalar > const &chain)
Definition Categorical.h:1049
constexpr bool isGaussian
Whether C is a Gaussian in covariance form: the component for which a container offers the convenienc...
Definition Component.h:111
std::expected< GaussianParams< typename G::SpaceType, typename G::Scalar >, GaussianError > toGaussian(G const &form)
Definition GaussianForm.h:91
std::expected< SqrtInfoGaussianParams< typename G::SpaceType, typename G::Scalar >, GaussianError > toSqrtInfo(G const &form)
Definition SqrtInfoGaussian.h:674
std::expected< CategoricalUpdate< Space, Scalar >, WeightError > update(CategoricalParams< Space, Scalar > const &prior, E const &emission)
Definition Emission.h:97
Eigen::Index valueDimension(S const &space)
Definition Space.h:272
auto plus(S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
Definition Space.h:675
auto block(Space auto const &space, X &&x)
Definition TagPath.h:979
auto minus(S const &space, Eigen::MatrixBase< ADerived > const &a, Eigen::MatrixBase< BDerived > const &b)
Definition Space.h:715
auto resetJacobian(S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
Definition Reset.h:377
constexpr bool hasIdentityReset
Whether the reset Jacobian of S is the identity, so that a covariance needs no change when its mean m...
Definition Reset.h:100
Eigen::Index differenceDimension(S const &space)
Definition Space.h:284
void normalizeValues(S const &space, Eigen::MatrixBase< Derived > const &block)
Brings the values in block (rows are space's coordinates, columns samples) into canonical form,...
Definition Space.h:331
internal::MatrixOf< Scalar, valueDimensionAtCompileTime< DifferenceSpace< MeasurementSpace > >, valueDimensionAtCompileTime< DifferenceSpace< Space > >, maxValueDimensionAtCompileTime< DifferenceSpace< MeasurementSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< Space > > > JacobianMatrix
Definition Condition.h:159
internal::MatrixOf< Scalar, valueDimensionAtCompileTime< DifferenceSpace< MeasurementSpace > >, valueDimensionAtCompileTime< DifferenceSpace< MeasurementSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< MeasurementSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< MeasurementSpace > > > ErrorMatrix
Definition Condition.h:167