16#include <Eigen/Cholesky>
53template <
typename Step,
typename Split,
typename Pinned>
59 static constexpr bool EvaluatesBatches =
requires {
requires Step::EvaluatesBatches; };
62 PinnedStep(Step
const & step, Split
const & split, Pinned
const & pinned)
71 template <
typename Rest,
typename... Inputs>
73 operator()(Rest
const & rest, Inputs
const &... inputs)
const
75 return m_step(m_split.assemble(rest, m_pinned), inputs...);
81 template <
typename Y,
typename Rests,
typename... Inputs>
83 evaluateBatch(Y & y, Rests
const & rests, Inputs
const &... inputs)
const
84 requires EvaluatesBatches
86 using T =
typename Rests::Scalar;
88 MatrixOf<T, Y::RowsAtCompileTime, Y::ColsAtCompileTime, Y::MaxRowsAtCompileTime, Y::MaxColsAtCompileTime>;
89 auto states = States{};
90 states.resize(y.rows(), rests.cols());
91 for (Eigen::Index j = 0; j < rests.cols(); ++j)
93 states.col(j) = m_split.assemble(rests.col(j), m_pinned);
95 m_step.evaluateBatch(y, states, inputs...);
101 Split
const & m_split;
102 Pinned
const & m_pinned;
108template <
typename Rest,
typename Scalar,
typename Allocator,
typename Model,
bool = isSwitchingPo
intModel<Model>>
109struct ParticleComponentOf
111 using type = Gaussian<Rest, Scalar>;
115template <
typename Rest,
typename Scalar,
typename Allocator,
typename Model>
116struct ParticleComponentOf<Rest, Scalar, Allocator, Model, true>
118 using type = Hybrid<Gaussian<Rest, Scalar>,
typename Model::ModeSpaceType, Allocator>;
125template <
typename Split,
typename CovDerived,
typename OffsetDerived>
126[[nodiscard]] std::expected<typename CovDerived::Scalar, NumericError>
129 Eigen::MatrixBase<CovDerived>
const & cov,
130 Eigen::MatrixBase<OffsetDerived>
const & offset
133 using Scalar =
typename CovDerived::Scalar;
136 BlockRows
const rows = split.pinnedDifferenceRows();
137 PinnedMatrix
const pinned = blockOf<PinnedRows, PinnedRows>(cov, rows.start, rows.start, rows.size, rows.size);
138 auto const llt = Eigen::LLT<PinnedMatrix>{pinned};
139 if (llt.info() != Eigen::Success)
143 auto const whitened = llt.matrixL().solve(offset.derived()).eval();
144 return Scalar(-0.5) * whitened.squaredNorm() - llt.matrixLLT().diagonal().array().log().sum();
160template <
typename Scalar =
double,
typename Allocator = DefaultAllocator>
165 using ArrayType = Eigen::Map<Eigen::Array<Scalar, Eigen::Dynamic, 1>
const>;
170 : m_points{allocator}
177 return m_points.logLikelihoods();
186 return m_points.nis();
190 [[nodiscard]] Eigen::Index
193 return m_points.innovationSize;
200 return allocator_type(m_points.logLikelihoodData.get_allocator());
207 return m_logLikelihood;
214 friend struct internal::PointLikelihoodsAccess;
215 friend struct internal::UpdateAccess;
217 Scalar m_logLikelihood = 0;
219 internal::PointLikelihoods<Scalar, Allocator> m_points;
310 typename Covariance_ = internal::PointCovarianceFor<Model_>,
316 :
public internal::HeldUpkeep<
317 RbParticleFilter<Space_, Path_, Model_, Covariance_, Method_, Scalar_, Allocator_, Upkeep_>,
320 using UpkeepBase = internal::HeldUpkeep<RbParticleFilter, Upkeep_>;
322 static constexpr bool Shared = std::is_same_v<Covariance_, SharedCovariance>;
325 static constexpr bool Switching = internal::isSwitchingPointModel<Model_>;
327 using RestSpace =
typename internal::BlockSplit<Space_, Path_>::RestSpace;
330 template <
typename P>
331 static constexpr void
332 assertParticlesRunUnder()
335 !Switching || internal::isSequential<P>,
336 "a particle's IMM step writes the recursion's scratch, so the particles of a hybrid state run in "
337 "order: pass Sequential"
342 internal::predictsBy<Model_, Method_>,
343 "a filter with a fixed-step model predicts by the model's method"
345 static_assert(internal::checkPredictionMethod<Method_>());
360 typename internal::ParticleComponentOf<RestSpace, Scalar_, Allocator_, Model_>::type>;
371 std::type_identity_t<Model_>
model,
374 std::type_identity_t<Upkeep_>
upkeep = {}
376 : UpkeepBase{std::move(upkeep)}
378 , m_state{std::move(
state)}
379 , m_posterior{m_state.m_conditionals, m_state.
get_allocator()}
383 assertModelPartitions(m_state);
391 requires(!std::same_as<Upkeep_, Emrys::upkeep::None>)
396 [[nodiscard]] allocator_type
399 return m_state.get_allocator();
403 [[nodiscard]] StateType
const &
412 [[nodiscard]] StateType &
425 assertModelPartitions(
state);
426 m_state = std::move(
state);
427 if (m_normals.get_allocator() != ScalarAllocator(m_state.get_allocator()))
430 m_posterior =
decltype(m_posterior){m_state.m_conditionals, m_state.get_allocator()};
431 m_normals = internal::Buffer<Scalar_, Allocator_>(ScalarAllocator(m_state.get_allocator()));
432 m_moved = internal::Buffer<Scalar_, Allocator_>(ScalarAllocator(m_state.get_allocator()));
433 if constexpr (Switching)
435 m_steps.resetScratch(m_state.get_allocator());
442 [[nodiscard]] Model_
const &
445 return m_steps.model();
449 [[nodiscard]] Model_ &
452 return m_steps.model();
456 [[nodiscard]] Method_
const &
459 return m_steps.method();
474 template <std::uniform_random_bit_generator G,
typename... Inputs>
487 template <
ExecutionPolicy P, std::uniform_random_bit_generator G,
typename... Inputs>
492 Scalar_
const step = internal::toScalarTime<Scalar_>(dt);
493 if constexpr (Switching)
495 assertParticlesRunUnder<P>();
496 return moveHybridParticles(rng, [&](
auto const &
model,
auto const &
method,
auto const & predictBy) {
497 auto const call = internal::modelWith(std::cref(
model), inputs...);
498 auto const resolved = internal::resolveProcess(call, m_state.space());
500 [&](
auto const &... uncertain) {
503 resolved.template noise<Scalar_>(step),
504 internal::ProcessStepValues<std::remove_cvref_t<
decltype(resolved)>, Scalar_>{
508 internal::inputOf(uncertain)...
517 predictOne(std::forward<P>(policy), rng, step, inputs...);
530 template <std::uniform_random_bit_generator G,
typename... Inputs>
535 internal::rejectTimeStep<Inputs...>();
540 template <
ExecutionPolicy P, std::uniform_random_bit_generator G,
typename... Inputs>
543 predict(P && policy, G & rng, Inputs
const &... inputs)
545 internal::rejectTimeStep<Inputs...>();
546 if constexpr (Switching)
548 assertParticlesRunUnder<P>();
549 return moveHybridParticles(rng, [&](
auto const &
model,
auto const &
method,
auto const & predictBy) {
550 auto const call = internal::modelWith(std::cref(
model.model()), inputs...);
551 auto const resolved = internal::resolveProcess(call, m_state.space());
553 [&](
auto const &... uncertain) {
557 internal::ProcessStepValues<
558 std::remove_cvref_t<
decltype(resolved)>,
559 std::remove_cvref_t<
decltype(
model.timeStep())>>{resolved, model.timeStep()},
560 internal::inputOf(uncertain)...
569 predictOneFixed(std::forward<P>(policy), rng, inputs...);
580 template <std::uniform_random_bit_generator G,
typename... Inputs>
591 template <
ExecutionPolicy P, std::uniform_random_bit_generator G,
typename... Inputs>
596 EMRYS_FILTER_ASSERT(steps.
count >= 0 &&
"the number of steps must be nonnegative");
597 if constexpr (Switching)
599 for (Eigen::Index i = 0; i < steps.
count; ++i)
601 if (
auto moved =
predict(policy, rng, inputs...); !moved)
606 return std::expected<void, NumericError>{};
610 for (Eigen::Index i = 0; i < steps.
count; ++i)
612 predict(policy, rng, inputs...);
640 template <
internal::WeighsPo
ints M>
641 [[nodiscard]] std::expected<UpdateType, NumericError>
650 template <ExecutionPolicy P,
internal::WeighsPo
ints M>
651 [[nodiscard]] std::expected<UpdateType, NumericError>
652 update(P && executionPolicy, M
const & measurement)
655 auto const updated =
update(std::forward<P>(executionPolicy), measurement, result);
658 return std::unexpected{updated.error()};
668 template <
internal::WeighsPo
ints M,
typename ResultAllocator>
669 [[nodiscard]] std::expected<void, NumericError>
678 template <ExecutionPolicy P,
internal::WeighsPo
ints M,
typename ResultAllocator>
679 [[nodiscard]] std::expected<void, NumericError>
682 if constexpr (!internal::hasOwnLikelihood<M> && !Shared)
688 if (
auto const total = m_state.logTotalWeight(executionPolicy); !total)
690 return std::unexpected{total.error()};
692 auto & points = internal::PointLikelihoodsAccess::points(result);
693 if constexpr (internal::hasOwnLikelihood<M>)
695 internal::updateGivenLikelihood(
698 m_state.m_conditionals,
702 finish<false>(std::forward<P>(executionPolicy), result);
706 auto const updated = internal::updateGivenShared(
709 m_state.m_conditionals,
710 m_state.mostProbable(),
717 return std::unexpected{updated.error()};
719 finish(std::forward<P>(executionPolicy), result);
730 template <
internal::WeighsPo
ints M,
typename Policy>
731 [[nodiscard]] std::expected<UpdateType, NumericError>
732 update(M
const & measurement, Policy
const & policy)
742 template <ExecutionPolicy P,
internal::WeighsPo
ints M,
typename Policy>
743 [[nodiscard]] std::expected<UpdateType, NumericError>
744 update(P && executionPolicy, M
const & measurement, Policy
const & policy)
748 auto const updated =
update(std::forward<P>(executionPolicy), measurement, policy, result);
751 return std::unexpected{updated.error()};
761 template <
internal::WeighsPo
ints M,
typename Policy,
typename ResultAllocator>
762 [[nodiscard]] std::expected<void, NumericError>
772 template <ExecutionPolicy P,
internal::WeighsPo
ints M,
typename Policy,
typename ResultAllocator>
773 [[nodiscard]] std::expected<void, NumericError>
775 P && executionPolicy,
776 M
const & measurement,
777 Policy
const & policy,
783 !internal::hasOwnLikelihood<M>,
784 "a measurement weighted by its own logLikelihood() has no branches to reduce, so it takes no policy"
787 if (
auto const total = m_state.logTotalWeight(executionPolicy); !total)
789 return std::unexpected{total.error()};
791 if constexpr (Switching && internal::isByMode<M>)
794 return updateParticles(
795 std::forward<P>(executionPolicy),
796 m_steps.template emptyGivenUpdate<M, Space_, Path_>(
get_allocator(), modeCount()),
797 [&](
auto & hybrid,
auto const & pinned,
auto & one) {
798 using Value = std::remove_cvref_t<
decltype(pinned)>;
799 return m_steps.update(
810 else if constexpr (Switching)
812 auto const f = internal::PinnedMeasurement<Space_, Path_, M>{m_state.space(), measurement};
813 return updateParticles(
814 std::forward<P>(executionPolicy),
815 m_steps.template emptyGivenUpdate<M, Space_, Path_>(
get_allocator(), modeCount()),
816 [&](
auto & hybrid,
auto const & pinned,
auto & one) {
817 return m_steps.updateGiven(hybrid, f, pinned, policy, one);
824 auto const updated = internal::updateGivenEach(
827 m_state.m_conditionals,
830 internal::PointLikelihoodsAccess::points(result),
835 return std::unexpected{updated.error()};
837 finish(std::forward<P>(executionPolicy), result);
844 using ScalarAllocator = internal::ReBound<Allocator_, Scalar_>;
850 assertModelPartitions(StateType
const & state)
const
852 internal::assertPartitions(
855 Switching ?
"every mode's process model must write every coordinate of the state space once"
856 :
"the process model must write every coordinate of the state space once"
861 [[nodiscard]] Eigen::Index
865 return m_steps.modeSpace().cardinality();
871 template <
typename P,
typename G,
typename... Inputs>
873 predictOne(P && policy, G & rng, Scalar_ step, Inputs
const &... inputs)
875 auto const call = internal::modelWith(std::cref(m_steps.model()), inputs...);
876 auto const resolved = internal::resolveProcess(call, m_state.space());
878 [&](
auto const &... uncertain) {
880 std::forward<P>(policy),
882 resolved.template noise<Scalar_>(step),
883 [&](
auto const & x,
auto const &... in) {
884 return internal::valueOf(resolved.propagate(x, step, in...));
886 internal::inputOf(uncertain)...
896 template <
typename P,
typename G,
typename... Inputs>
898 predictOneFixed(P && policy, G & rng, Inputs
const &... inputs)
900 auto const & model = m_steps.model();
901 auto const call = internal::modelWith(std::cref(model.model()), inputs...);
902 auto const resolved = internal::resolveProcess(call, m_state.space());
904 [&](
auto const &... uncertain) {
906 std::forward<P>(policy),
909 [&](
auto const & x,
auto const &... in) {
910 return internal::valueOf(resolved.propagate(x, model.timeStep(), in...));
912 internal::inputOf(uncertain)...
923 template <
typename M,
typename NoiseDerived,
typename Propagate,
typename PinnedVector,
typename... Inputs>
927 Eigen::MatrixBase<NoiseDerived>
const & noise,
929 PinnedVector
const & pinned,
931 Inputs
const &... inputs
934 auto const & split = m_state.m_split;
935 auto const f = internal::PinnedStep<Propagate, std::remove_cvref_t<
decltype(split)>, PinnedVector>{
940 auto predicted = internal::transformBy(method, f, m_state.space(), conditional, inputs...);
941 predicted.setCovariance(predicted.covarianceLower() + noise);
963 template <
typename G,
typename StepOf>
964 [[nodiscard]] std::expected<void, NumericError>
965 moveHybridParticles(G & rng, StepOf
const & stepOf)
967 using PinnedSpace =
typename StateType::PinnedSpace;
972 using ComponentType =
typename ConditionalType::ComponentType;
973 using ModesType =
typename ConditionalType::ModesType;
976 constexpr Scalar_
none = -Eigen::NumTraits<Scalar_>::infinity();
977 auto const & split = m_state.m_split;
978 BlockRows const rows = split.pinnedRows();
979 Eigen::Index
const count = m_state.
size();
980 Eigen::Index
const normalSize = split.pinnedDifferenceRows().size;
981 m_normals.resize(std::size_t(normalSize * count));
982 auto z = Eigen::Map<PinnedNormals>{m_normals.data(), normalSize, count};
983 internal::fillStandardNormal(z, rng);
984 m_moved.resize(std::size_t(rows.size * count));
985 auto moved = Eigen::Map<PinnedSamples>{m_moved.data(), rows.size, count};
986 if (m_posterior.size() != count)
988 m_posterior = m_state.m_conditionals;
990 auto const & model = m_steps.model();
991 auto const & transitions = model.chain().matrix();
993 bool const mixes = !transitions.isIdentity(Scalar_(0));
994 Eigen::Index
const modes = modeCount();
995 auto logMixing =
typename ModesType::ArrayType{};
996 logMixing.resize(modes);
999 for (Eigen::Index i = 0; i < count; ++i)
1001 auto const & prior = m_state.m_conditionals.conditional(i);
1002 auto & posterior = m_posterior.conditional(i);
1003 PinnedVector
const pinned = m_state.particle(i);
1004 ModesType predictedModes = mixes ?
Emrys::predict(prior.modes(), model.chain()) : prior.modes();
1005 auto const logTotal = predictedModes.logTotalWeight();
1008 return std::unexpected{logTotal.error()};
1010 Eigen::Index
const drawn = internal::drawIndex<Scalar_>(
1012 [&](Eigen::Index m) {
1013 return Eigen::numext::exp(predictedModes.logWeight(m) - *logTotal);
1018 for (Eigen::Index pass = 0; pass < modes; ++pass)
1021 Eigen::Index
const j = pass == 0 ? drawn : (pass - 1 < drawn ? pass - 1 : pass);
1022 bool const reachable = predictedModes.logWeight(j) >
none;
1023 auto const predictFrom = [&](ComponentType
const & start) {
1024 auto predicted = std::optional<Whole>{};
1025 model.visit(j, m_steps.method(), [&](
auto const & mode,
auto const & modeMethod) {
1026 predicted.emplace(stepOf(
1029 [&](auto const & method, auto const & noise, auto const & propagate, auto const &... in) {
1030 return predictWhole(method, noise, propagate, pinned, start, in...);
1034 return std::move(*predicted);
1036 Whole
const predicted = [&] {
1039 return predictFrom(prior.conditional(j));
1042 for (Eigen::Index m = 0; m < modes; ++m)
1044 logMixing(m) = reachable ? Eigen::numext::log(transitions(m, j)) + prior.modes().logWeight(m)
1045 : (m == j ? Scalar_(0) :
none);
1049 [&](Eigen::Index m) -> ComponentType
const & {
1050 return prior.conditional(m);
1052 [&](Eigen::Index m) {
1053 return logMixing(m);
1056 return predictFrom(mixed);
1058 auto conditioning = internal::pinnedConditioning(split, predicted.covarianceLower());
1059 auto const pinnedMean = internal::middleRowsOf<PinnedValues>(predicted.mean(), rows.start, rows.size);
1060 auto mean = RestVector{};
1063 internal::drawPinned(split, conditioning, predicted.mean(), z.col(i), moved.col(i), mean);
1065 auto const offset =
Emrys::minus(split.pinnedSpace(), moved.col(i), pinnedMean).eval();
1070 predicted.mean()(split.restIndices()),
1071 internal::multiply(conditioning.gain, offset)
1076 auto const logDensity = internal::pinnedLogDensity(split, predicted.covarianceLower(), offset);
1079 return std::unexpected{logDensity.error()};
1083 posterior.setConditional(
1085 ComponentType{split.restSpace(), std::move(mean), std::move(conditioning.cov)}
1089 [[maybe_unused]]
auto const evidence = predictedModes.update(
logLikelihoods);
1090 EMRYS_FILTER_ASSERT(evidence &&
"the draw's mode has a density");
1091 posterior.setModes(std::move(predictedModes));
1094 m_state.m_stamp.touchValues();
1095 m_state.m_conditionals.swap(m_posterior);
1096 m_state.m_particles.setStates(moved);
1107 template <
typename P,
typename OneResult,
typename UpdateOne,
typename ResultAllocator>
1108 [[nodiscard]] std::expected<void, NumericError>
1111 OneResult oneResult,
1112 UpdateOne
const & updateOne,
1113 RbParticleFilterUpdate<Scalar, ResultAllocator> & result
1116 assertParticlesRunUnder<P>();
1118 m_state.m_stamp.touchValues();
1119 auto const updated = internal::updateHybridsGiven(
1121 m_state.m_conditionals,
1122 internal::PointLikelihoodsAccess::points(result),
1130 finish<false>(std::forward<P>(policy), result);
1138 Eigen::Index
const count = m_state.particles().capacity().value_or(m_state.size());
1139 m_posterior.reserve(count);
1140 m_normals.reserve(std::size_t(m_state.pinnedDifferenceRows().size * count));
1141 m_moved.reserve(std::size_t(m_state.pinnedRows().size * count));
1148 template <
typename P,
typename G,
typename Derived,
typename Propagate,
typename... Inputs>
1153 Eigen::MatrixBase<Derived>
const & noise,
1154 Propagate
const & propagate,
1155 Inputs
const &... inputs
1158 using PinnedSamples = SampleSet<typename StateType::PinnedSpace, Scalar_>;
1159 using PinnedNormals = SampleSet<DifferenceSpace<typename StateType::PinnedSpace>, Scalar_>;
1160 using PinnedVector =
typename Moments<typename StateType::PinnedSpace, Scalar_>::VectorType;
1161 using WholeMoments = Moments<Space_, Scalar_>;
1162 using RestMoments = Moments<typename StateType::RestSpace, Scalar_>;
1164 using RestColumns = internal::MatrixOf<
1166 WholeMoments::DifferenceDimensionAtCompileTime,
1167 RestMoments::DifferenceDimensionAtCompileTime,
1168 WholeMoments::MaxDifferenceDimensionAtCompileTime,
1169 RestMoments::MaxDifferenceDimensionAtCompileTime>;
1170 using RestCross = internal::MatrixOf<
1172 RestMoments::DifferenceDimensionAtCompileTime,
1173 WholeMoments::DifferenceDimensionAtCompileTime,
1174 RestMoments::MaxDifferenceDimensionAtCompileTime,
1175 WholeMoments::MaxDifferenceDimensionAtCompileTime>;
1176 constexpr bool cached = internal::cachesTransition<Model_> &&
sizeof...(Inputs) == 0;
1177 auto const & space = m_state.space();
1178 auto const & split = m_state.m_split;
1179 Eigen::Index
const count = m_state.size();
1180 Eigen::Index
const pinnedSize = split.pinnedRows().size;
1181 Eigen::Index
const normalSize = split.pinnedDifferenceRows().size;
1182 m_normals.resize(std::size_t(normalSize * count));
1183 auto z = Eigen::Map<PinnedNormals>{m_normals.data(), normalSize, count};
1184 internal::fillStandardNormal(z, rng);
1186 m_state.m_stamp.touchValues();
1187 auto & conditionals = m_state.m_conditionals;
1188 auto const restColumns = [&] {
1189 if constexpr (cached)
1192 m_steps.model().transition()(Eigen::placeholders::all, split.restDifferenceIndices())
1197 return internal::NoTransition{};
1200 auto const predictGiven = [&](Eigen::Index i) -> GaussianParams<Space_, Scalar_> {
1201 PinnedVector
const pinned = m_state.particle(i);
1202 auto const & conditional = conditionals.conditional(i);
1203 if constexpr (cached)
1205 typename WholeMoments::VectorType mean =
propagate(split.assemble(conditional.mean(), pinned));
1207 RestCross
const cross = internal::multiply(conditional.covarianceLower(), restColumns.transpose());
1208 typename WholeMoments::MatrixType cov = internal::multiply(restColumns, cross);
1209 cov = (Scalar_(0.5) * (cov + cov.transpose()) + noise).eval();
1210 return {space, std::move(mean), std::move(cov)};
1214 return predictWhole(m_steps.method(), noise, propagate, pinned, conditional, inputs...);
1218 m_moved.resize(std::size_t(pinnedSize * count));
1219 auto moved = Eigen::Map<PinnedSamples>{m_moved.data(), pinnedSize, count};
1220 if constexpr (Shared)
1222 auto const conditioning =
1223 internal::pinnedConditioning(split, predictGiven(m_state.mostProbable()).covarianceLower());
1224 auto means = conditionals.means();
1225 internal::forEachIndex(std::forward<P>(policy), count, [&](Eigen::Index i) {
1226 auto mean =
propagate(split.assemble(means.col(i), m_state.particle(i)), internal::meanOf(inputs)...);
1228 internal::drawPinned(split, conditioning, mean, z.col(i), moved.col(i), means.col(i));
1230 conditionals.sharedCovariance() = conditioning.cov;
1234 internal::forEachIndex(std::forward<P>(policy), count, [&](Eigen::Index i) {
1235 auto mean =
typename Moments<typename StateType::RestSpace, Scalar_>::VectorType{};
1236 auto const predicted = predictGiven(i);
1237 auto conditioning = internal::pinnedConditioning(split, predicted.covarianceLower());
1238 internal::drawPinned(split, conditioning, predicted.mean(), z.col(i), moved.col(i), mean);
1239 conditionals.conditional(i) =
1240 ConditionalType{split.restSpace(), std::move(mean), std::move(conditioning.cov)};
1243 m_state.m_particles.setStates(moved);
1251 template <
bool Posterior = true,
typename P,
typename ResultAllocator>
1253 finish(P && policy, RbParticleFilterUpdate<Scalar, ResultAllocator> & result)
1255 auto & points = internal::PointLikelihoodsAccess::points(result);
1257 if constexpr (Posterior)
1259 return m_state.reweight(std::forward<P>(policy), points.logLikelihoods(), m_posterior);
1263 return m_state.reweight(std::forward<P>(policy), points.logLikelihoods());
1266 internal::UpdateAccess::logLikelihood(result) =
logLikelihood;
1267 result.accepted = accepted;
1273 using StepsType = std::conditional_t<
1275 ImmRecursion<Gaussian<RestSpace, Scalar_>, Model_, Method_, Allocator_>,
1276 internal::PointSteps<Model_, Method_>>;
1283 typename StateType::ConditionalsType m_posterior;
1284 internal::Buffer<Scalar_, Allocator_> m_normals;
1285 internal::Buffer<Scalar_, Allocator_> m_moved;
1296 typename Covariance,
1297 typename Method = DefaultMethodFor<Model>,
1301 requires(!internal::UpkeepArgument<Method>)
1302RbParticleFilter(Model, ParticleGaussianParams<Space, Path, Covariance, Scalar, Allocator, Component>, Method = {})
1303 -> RbParticleFilter<Space, Path, internal::BoundStep<Model, Space, Scalar>, Covariance, Method, Scalar, Allocator>;
1309 typename Covariance,
1314 requires internal::UpkeepArgument<U>
1315RbParticleFilter(Model, ParticleGaussianParams<Space, Path, Covariance, Scalar, Allocator, Component>, U)
1316 -> RbParticleFilter<
1319 internal::BoundStep<Model, Space, Scalar>,
1321 DefaultMethodFor<Model>,
1330 typename Covariance,
1338 ParticleGaussianParams<Space, Path, Covariance, Scalar, Allocator, Component>,
1341) -> RbParticleFilter<Space, Path, internal::BoundStep<Model, Space, Scalar>, Covariance, Method, Scalar, Allocator, U>;
1346#ifndef EMRYS_FILTER_NO_IO
1359 typename Covariance_,
1362 typename Allocator_,
1366 std::ostream & stream,
1367 RbParticleFilter<Space_, Path_, Model_, Covariance_, Method_, Scalar_, Allocator_, Upkeep_>
const & filter,
1371 describeFilter(stream,
"Rao-Blackwellized particle filter", filter.state(), indent);
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
The distribution over a discrete space (decisions.md [discrete-spaces], [params-and-density]): Catego...
Execution policies (decisions.md [execution-policies]): execution::sequential, the ExecutionPolicy co...
The upkeep a filter holds (decisions.md [upkeep]): internal::HeldUpkeep, the base that gives every fi...
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
The hybrid state of a discrete mode and a component per mode (decisions.md [imm], [component-first]):...
ImmRecursion and ImmFilter (decisions.md [switching-models], [imm], [filters-and-recursions]): a Hybr...
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'...
NumericError, the reasons a factorization or a normalization can fail, and its two names,...
The state of a Rao-Blackwellized particle filter (decisions.md [rb-particle-filter]): ParticleGaussia...
Printing: operator<< and std::formatter for every distribution, every filter (which prints its name a...
Process models as functions with reads and writes (decisions.md [model-policies], [continuous-time-no...
The update that the Rao-Blackwellized filters share (decisions.md [rb-point-mass],...
The Recursion concept (decisions.md [filters-and-recursions], [user-extension-points]): what a Kalman...
Reducing an update's branches (decisions.md [weighted-branches], [reduction-policies],...
SampleSet: a matrix whose columns are samples in a space, which the samplers return and the unscented...
Drawing samples: SamplesWithLogDensity and SampleWithLogDensity, the Gaussian draws drawSamples(),...
Log-weights: the WeightError a normalization can fail with (NumericError.h), and the streaming log-su...
A Gaussian distribution: a mean and covariance in a space.
Definition Gaussian.h:259
DifferenceMatrix< Space_, Space_, Scalar > MatrixType
a matrix over differences, such as the covariance
Definition Moments.h:76
ValueVector< Space_, Scalar > VectorType
a value, such as the mean
Definition Moments.h:74
static constexpr int DifferenceDimensionAtCompileTime
the length of a difference and the rows of a covariance, or Eigen::Dynamic
Definition Moments.h:69
The parameters of a Rao-Blackwellized particle filter's state: weighted particles for one block of th...
Definition ParticleGaussian.h:192
Params< Component_ > ConditionalType
a particle's distribution over the rest: a Gaussian or a hybrid
Definition ParticleGaussian.h:226
What a Rao-Blackwellized particle filter's update did, per particle and in total.
Definition RbParticleFilter.h:162
Scalar logLikelihood() const
Definition RbParticleFilter.h:205
Eigen::Index innovationSize() const
Definition RbParticleFilter.h:191
RbParticleFilterUpdate(Allocator const &allocator={})
An empty result whose arrays come from allocator.
Definition RbParticleFilter.h:169
Allocator allocator_type
where the per-particle arrays come from
Definition RbParticleFilter.h:166
Eigen::Map< Eigen::Array< Scalar, Eigen::Dynamic, 1 > const > ArrayType
a per-particle array
Definition RbParticleFilter.h:165
ArrayType nis() const
Definition RbParticleFilter.h:184
bool accepted
Definition RbParticleFilter.h:210
allocator_type get_allocator() const
Definition RbParticleFilter.h:198
ArrayType logLikelihoods() const
Definition RbParticleFilter.h:175
typename StateType::ConditionalType ConditionalType
a particle's distribution over the rest
Definition RbParticleFilter.h:361
std::expected< void, NumericError > update(P &&executionPolicy, M const &measurement, RbParticleFilterUpdate< Scalar, ResultAllocator > &result)
update(measurement, result) under executionPolicy, as update(executionPolicy,measurement) runs.
Definition RbParticleFilter.h:680
std::expected< UpdateType, NumericError > update(P &&executionPolicy, M const &measurement)
update() under executionPolicy: each particle's update is a for-each and the evidence a reduction,...
Definition RbParticleFilter.h:652
Allocator_ allocator_type
the state's allocator
Definition RbParticleFilter.h:362
std::expected< UpdateType, NumericError > update(M const &measurement)
Conditions each particle's Gaussian on measurement given the particle, by the measurement's own metho...
Definition RbParticleFilter.h:642
auto predict(G &rng, Inputs const &... inputs)
Moves each particle and its Gaussian forward by the fixed-step model's step, as predict(rng,...
Definition RbParticleFilter.h:533
Model_ const & model() const
Definition RbParticleFilter.h:443
RbParticleFilter(std::type_identity_t< Model_ > model, StateType state, MethodFor< Model_, Method_ > method={}, std::type_identity_t< Upkeep_ > upkeep={})
A filter with process model model over the whole state, initial state state, prediction method method...
Definition RbParticleFilter.h:370
std::expected< void, NumericError > update(P &&executionPolicy, M const &measurement, Policy const &policy, RbParticleFilterUpdate< Scalar, ResultAllocator > &result)
update(measurement, policy, result) under executionPolicy, as update(executionPolicy,...
Definition RbParticleFilter.h:774
Method_ const & method() const
Definition RbParticleFilter.h:457
Space_ SpaceType
the state space
Definition RbParticleFilter.h:350
Model_ & model()
Definition RbParticleFilter.h:450
std::expected< void, NumericError > update(M const &measurement, Policy const &policy, RbParticleFilterUpdate< Scalar, ResultAllocator > &result)
As update(measurement, policy), but into result, whose storage is reused (see update(measurement,...
Definition RbParticleFilter.h:763
std::expected< UpdateType, NumericError > update(M const &measurement, Policy const &policy)
As update(measurement), with PerPointCovariance, but with each particle's branches reduced by policy ...
Definition RbParticleFilter.h:732
auto predict(P &&policy, G &rng, Inputs const &... inputs)
predict(rng, inputs...) under policy, as predict(policy, rng, dt, inputs...) runs.
Definition RbParticleFilter.h:543
RbParticleFilterUpdate< Scalar, Allocator_ > UpdateType
The result of update(): the per-particle arrays from the filter's allocator.
Definition RbParticleFilter.h:618
auto predict(P &&policy, G &rng, Steps steps, Inputs const &... inputs)
predict(rng, steps, inputs...) under policy, as that many calls of predict(policy,...
Definition RbParticleFilter.h:594
auto predict(P &&policy, G &rng, TimeStep< Scalar_ > auto const &dt, Inputs const &... inputs)
predict(rng, dt, inputs...) under policy: the draws are taken first, as the sequential prediction tak...
Definition RbParticleFilter.h:490
auto predict(G &rng, TimeStep< Scalar_ > auto const &dt, Inputs const &... inputs)
Moves each particle and its Gaussian forward by dt, any TimeStep (see Time steps): predicts the whole...
Definition RbParticleFilter.h:477
ParticleGaussianParams< Space_, Path_, Covariance_, Scalar_, Allocator_, typename internal::ParticleComponentOf< RestSpace, Scalar_, Allocator_, Model_ >::type > StateType
The state the filter owns: a Gaussian per particle, or a hybrid under a switching model.
Definition RbParticleFilter.h:354
Scalar_ Scalar
the scalar type
Definition RbParticleFilter.h:349
std::expected< UpdateType, NumericError > update(P &&executionPolicy, M const &measurement, Policy const &policy)
update(measurement, policy) under executionPolicy: each particle's Kalman update and reduction by pol...
Definition RbParticleFilter.h:744
StateType & state()
Definition RbParticleFilter.h:413
Model_ ModelType
the process model
Definition RbParticleFilter.h:351
auto predict(G &rng, Steps steps, Inputs const &... inputs)
Moves each particle and its Gaussian forward by steps of the fixed-step model, as that many calls of ...
Definition RbParticleFilter.h:583
allocator_type get_allocator() const
Definition RbParticleFilter.h:397
std::expected< void, NumericError > update(M const &measurement, RbParticleFilterUpdate< Scalar, ResultAllocator > &result)
As update(measurement), but into result, whose storage is reused: an update into a result kept across...
Definition RbParticleFilter.h:670
Method_ MethodType
the prediction method
Definition RbParticleFilter.h:352
void setState(StateType state)
Replaces the state, as when reinitializing, with one whose space the process model's writes partition...
Definition RbParticleFilter.h:423
RbParticleFilter(std::type_identity_t< Model_ > model, StateType state, std::type_identity_t< Upkeep_ > upkeep)
A filter with process model model over the whole state, initial state state, the default prediction m...
Definition RbParticleFilter.h:390
StateType const & state() const
Definition RbParticleFilter.h:404
An execution policy: execution::sequential, a policy of the standard library such as std::execution::...
Definition Execution.h:459
A type usable as the scalar of a distribution: a real number type such as float, double,...
Definition Math.h:80
A type usable as the space of a distribution.
Definition Space.h:186
A step of time that converts to Scalar: Scalar itself, or any type with a TimeTraits,...
Definition Time.h:128
std::allocator< std::byte > DefaultAllocator
The allocator a type with a run-time count uses unless given one.
Definition Allocation.h:47
@ NotPositiveDefinite
the covariance is not positive definite, so it has no Cholesky factor or inverse
Definition NumericError.h:31
Eigen::Matrix< Scalar, valueDimensionAtCompileTime< Space >, Eigen::Dynamic,(maxValueDimensionAtCompileTime< Space >==1 ? Eigen::RowMajor :Eigen::ColMajor), maxValueDimensionAtCompileTime< Space >, Eigen::Dynamic > SampleSet
A matrix whose columns are samples in Space (see Spaces), with the space's size and storage bound.
Definition SampleSet.h:33
CategoricalParams< Space, Scalar > predict(CategoricalParams< Space, Scalar > const &prior, MarkovChain< Space, Scalar > const &chain)
Definition Categorical.h:1049
constexpr Sequential sequential
The default execution policy: plain loops on the calling thread, in index order (Sequential).
Definition Execution.h:128
constexpr Collapse collapse()
Definition Reduction.h:291
Derived::Scalar logLikelihood(M const &measurement, Space const &space, Eigen::MatrixBase< Derived > const &x)
Definition Likelihood.h:433
typename internal::DefaultMethodOf< Model >::type DefaultMethodFor
The prediction method of a filter with process model Model, unless it is given one: Linearized,...
Definition ProcessModel.h:3220
constexpr bool isFixedStep
Whether Model is a FixedStepModel, whose predictions take no time step.
Definition ProcessModel.h:2776
Moments< Space_, typenameDerived::Scalar >::VectorType propagate(Space_ const &space, Eigen::MatrixBase< Derived > const &x, Model const &model, TimeStep< typename Derived::Scalar > auto const &dt, Args const &... args)
Definition ProcessModel.h:2754
Eigen::Array< typename Derived::Scalar, Eigen::Dynamic, 1 > logLikelihoods(M const &measurement, Space const &space, Eigen::MatrixBase< Derived > const &states)
Definition Likelihood.h:408
std::conditional_t< isFixedStep< Model >, ModelsMethod, Method > MethodFor
The type of a filter constructor's method argument: Method, or ModelsMethod for a fixed-step Model,...
Definition ProcessModel.h:3236
auto plus(S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
Definition Space.h:675
auto minus(S const &space, Eigen::MatrixBase< ADerived > const &a, Eigen::MatrixBase< BDerived > const &b)
Definition Space.h:715
constexpr int valueDimensionAtCompileTime
The value dimension of Space at compile time, or Eigen::Dynamic if it is resizable.
Definition Space.h:251
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
constexpr None none()
Definition Upkeep.h:903
The upkeep operations, each made by its factory (decisions.md [policy-factories], [upkeep]): the acti...
Definition Upkeep.h:380
Rows of a contiguous block of a space.
Definition TagPath.h:825
Eigen::Index size
number of rows
Definition TagPath.h:827
What a container does with a component beyond the component's own members (decisions....
Definition Component.h:104
A block of a state given from outside the Gaussian being updated, as given() makes it,...
Definition Measurement.h:723
A count of a fixed-step model's steps, for predict(Steps{n}).
Definition Time.h:136
Eigen::Index count
the number of steps, at least zero
Definition Time.h:137
The upkeep a filter holds when it is given none: it takes any state, changes nothing,...
Definition Upkeep.h:889