EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
ParticleFilter.h
Go to the documentation of this file.
1#pragma once
2
9
10#include <expected>
11#include <random>
12#include <tuple>
13#include <type_traits>
14#include <utility>
15
33
34namespace Emrys
35{
36
45template <typename Scalar = double>
47{
48public:
49
51 [[nodiscard]] Scalar
53 {
54 return m_logLikelihood;
55 }
56
57 bool accepted = false;
58
59private:
60
61 friend struct internal::UpdateAccess;
62
63 Scalar m_logLikelihood = 0;
64};
65
66namespace internal
67{
68
72template <typename Input>
73struct DrawnInput
74{
76 DrawnInput(Input const & input, Eigen::Index & /*row*/)
77 : input{input}
78 {}
79
80 static constexpr int RowsAtCompileTime = 0;
81 static constexpr int MaxRowsAtCompileTime = 0;
82
83 Input const & input;
84
86 template <typename Derived, typename G>
87 void
88 fill(Derived && /*draws*/, G & /*rng*/) const
89 {}
90
92 template <typename Derived>
93 [[nodiscard]] Input const &
94 at(Eigen::MatrixBase<Derived> const & /*draws*/) const
95 {
96 return input;
97 }
98};
99
103template <UncertainInput Input>
104struct DrawnInput<Input>
105{
106 using Space = typename Input::SpaceType;
107 using Scalar = typename Input::Scalar;
108
112 DrawnInput(Input const & input, Eigen::Index & row)
113 : input{input}
114 , factor{defaultRoot(covarianceLowerOf(input))}
115 , firstRow{row}
116 {
117 row += input.differenceDimension();
118 }
119
121 static constexpr int RowsAtCompileTime = rowsAtCompileTime<true, Space>;
122
124 static constexpr int MaxRowsAtCompileTime = maxValueDimensionAtCompileTime<DifferenceSpace<Space>>;
125
126 Input const & input;
127
130
131 Eigen::Index firstRow;
132
136 template <typename Derived, typename G>
137 void
138 fill(Derived && draws, G & rng, std::normal_distribution<Scalar> & normal) const
139 {
140 fillStandardNormal(middleRowsOf<RowsAtCompileTime>(draws, firstRow, input.differenceDimension()), rng, normal);
141 }
142
146 template <typename Derived>
147 [[nodiscard]] typename Moments<Space, Scalar>::VectorType
148 at(Eigen::MatrixBase<Derived> const & draws) const
149 {
151 middleRowsOf<RowsAtCompileTime>(draws.derived(), firstRow, input.differenceDimension());
152 return Emrys::plus(input.space(), input.mean(), multiply(factor, z));
153 }
154};
155
159template <typename Input>
160[[nodiscard]] Eigen::Index
161drawnRows([[maybe_unused]] Input const & input)
162{
163 if constexpr (UncertainInput<Input>)
164 {
165 return input.differenceDimension();
166 }
167 else
168 {
169 return 0;
170 }
171}
172
173} // namespace internal
174
241template <
242 Space Space_,
243 typename Model_,
244 RealScalar Scalar_ = double,
245 typename Allocator_ = DefaultAllocator,
246 typename Upkeep_ = upkeep::None>
248 : public internal::HeldUpkeep<ParticleFilter<Space_, Model_, Scalar_, Allocator_, Upkeep_>, Upkeep_>
249{
250 using UpkeepBase = internal::HeldUpkeep<ParticleFilter, Upkeep_>;
251
252public:
253
254 using Scalar = Scalar_;
255 using SpaceType = Space_;
256 using ModelType = Model_;
258 using allocator_type = Allocator_;
259
266 ParticleFilter(std::type_identity_t<Model_> model, StateType state, std::type_identity_t<Upkeep_> upkeep = {})
267 : UpkeepBase{std::move(upkeep)}
268 , m_model{std::move(model)}
269 , m_state{std::move(state)}
270 , m_logLikelihoods(ScalarAllocator(m_state.get_allocator()))
271 , m_draws(ScalarAllocator(m_state.get_allocator()))
272 , m_batch(ScalarAllocator(m_state.get_allocator()))
273 {
274 EMRYS_FILTER_ASSERT(!m_state.empty() && "the initial particle set must have a particle");
275 internal::assertPartitions(m_model, m_state.space());
276 reserveScratch();
277 }
278
280 [[nodiscard]] allocator_type
282 {
283 return m_state.get_allocator();
284 }
285
287 [[nodiscard]] StateType const &
288 state() const
289 {
290 return m_state;
291 }
292
297 [[nodiscard]] StateType &
299 {
300 return m_state;
301 }
302
307 void
309 {
310 EMRYS_FILTER_ASSERT(!state.empty() && "the particle set must have a particle");
311 internal::assertPartitions(m_model, state.space());
312 m_state = std::move(state);
313 if (m_logLikelihoods.get_allocator() != ScalarAllocator(m_state.get_allocator()))
314 {
315 // The assignment carried the new set's allocator in, so the scratch follows it.
316 m_logLikelihoods = internal::Buffer<Scalar_, Allocator_>(ScalarAllocator(m_state.get_allocator()));
317 m_draws = internal::Buffer<Scalar_, Allocator_>(ScalarAllocator(m_state.get_allocator()));
318 m_batch = internal::Buffer<Scalar_, Allocator_>(ScalarAllocator(m_state.get_allocator()));
319 }
320 reserveScratch();
321 }
322
324 [[nodiscard]] Model_ const &
325 model() const
326 {
327 return m_model;
328 }
329
331 [[nodiscard]] Model_ &
333 {
334 return m_model;
335 }
336
346 template <std::uniform_random_bit_generator G, typename... Inputs>
347 requires(!isFixedStep<Model_>)
348 void
349 predict(G & rng, TimeStep<Scalar_> auto const & dt, Inputs const &... inputs)
350 {
351 predict(execution::sequential, rng, dt, inputs...);
352 }
353
359 template <ExecutionPolicy P, std::uniform_random_bit_generator G, typename... Inputs>
360 requires(!isFixedStep<Model_>)
361 void
362 predict(P && policy, G & rng, TimeStep<Scalar_> auto const & dt, Inputs const &... inputs)
363 {
364 auto const & space = m_state.space();
365 Scalar_ const step = internal::toScalarTime<Scalar_>(dt);
366 auto const call = internal::modelWith(std::cref(m_model), inputs...);
367 auto const resolved = internal::resolveProcess(call, space);
368 std::apply(
369 [&](auto const &... uncertain) {
370 if constexpr (std::remove_cvref_t<decltype(resolved)>::BatchedFunction)
371 {
372 moveInBatches(
373 std::forward<P>(policy),
374 rng,
375 internal::defaultRoot(resolved.template noise<Scalar_>(step)),
376 resolved,
377 step,
378 internal::inputOf(uncertain)...
379 );
380 }
381 else
382 {
383 moveParticles(
384 std::forward<P>(policy),
385 rng,
386 internal::defaultRoot(resolved.template noise<Scalar_>(step)),
387 [&](auto const & x, auto const &... in) {
388 return internal::valueOf(resolved.propagate(x, step, in...));
389 },
390 internal::inputOf(uncertain)...
391 );
392 }
393 },
394 resolved.inputs()
395 );
396 }
397
401 template <std::uniform_random_bit_generator G, typename... Inputs>
402 requires(isFixedStep<Model_> && !internal::leadsWithSteps<Inputs...>)
403 void
404 predict(G & rng, Inputs const &... inputs)
405 {
406 internal::rejectTimeStep<Inputs...>();
407 predict(execution::sequential, rng, inputs...);
408 }
409
413 template <ExecutionPolicy P, std::uniform_random_bit_generator G, typename... Inputs>
414 requires(isFixedStep<Model_> && !internal::leadsWithSteps<Inputs...>)
415 void
416 predict(P && policy, G & rng, Inputs const &... inputs)
417 {
418 internal::rejectTimeStep<Inputs...>();
419 auto const & space = m_state.space();
420 auto const call = internal::modelWith(std::cref(m_model.model()), inputs...);
421 auto const resolved = internal::resolveProcess(call, space);
422 std::apply(
423 [&](auto const &... uncertain) {
424 if constexpr (std::remove_cvref_t<decltype(resolved)>::BatchedFunction)
425 {
426 moveInBatches(
427 std::forward<P>(policy),
428 rng,
429 m_model.noiseRoot(),
430 resolved,
431 m_model.timeStep(),
432 internal::inputOf(uncertain)...
433 );
434 }
435 else
436 {
437 moveParticles(
438 std::forward<P>(policy),
439 rng,
440 m_model.noiseRoot(),
441 [&](auto const & x, auto const &... in) {
442 return internal::valueOf(resolved.propagate(x, m_model.timeStep(), in...));
443 },
444 internal::inputOf(uncertain)...
445 );
446 }
447 },
448 resolved.inputs()
449 );
450 }
451
455 template <std::uniform_random_bit_generator G, typename... Inputs>
456 requires isFixedStep<Model_>
457 void
458 predict(G & rng, Steps steps, Inputs const &... inputs)
459 {
460 predict(execution::sequential, rng, steps, inputs...);
461 }
462
466 template <ExecutionPolicy P, std::uniform_random_bit_generator G, typename... Inputs>
467 requires isFixedStep<Model_>
468 void
469 predict(P && policy, G & rng, Steps steps, Inputs const &... inputs)
470 {
471 EMRYS_FILTER_ASSERT(steps.count >= 0 && "the number of steps must be nonnegative");
472 for (Eigen::Index i = 0; i < steps.count; ++i)
473 {
474 predict(policy, rng, inputs...);
475 }
476 }
477
487 template <internal::WeighsPoints M>
488 [[nodiscard]] std::expected<ParticleFilterUpdate<Scalar_>, WeightError>
489 update(M const & measurement)
490 {
491 return update(execution::sequential, measurement);
492 }
493
498 template <ExecutionPolicy P, internal::WeighsPoints M>
499 [[nodiscard]] std::expected<ParticleFilterUpdate<Scalar_>, WeightError>
500 update(P && policy, M const & measurement)
501 {
502 auto const logTotal = m_state.logTotalWeight(policy);
503 if (!logTotal)
504 {
505 return std::unexpected{logTotal.error()};
506 }
507 m_logLikelihoods.resize(std::size_t(m_state.size()));
508 auto logWeights = Eigen::Map<typename StateType::WeightArrayType>{m_logLikelihoods.data(), m_state.size()};
509 internal::fillLogLikelihoods(policy, measurement, m_state.space(), m_state.states(), logWeights, m_batch);
510 logWeights += m_state.logWeights() - *logTotal;
511 // A NaN log-likelihood at any particle makes the evidence NaN.
512 Scalar_ const logLikelihood = logSumExp(std::forward<P>(policy), logWeights);
513 EMRYS_FILTER_ASSERT(!isNaN(logLikelihood) && "the measurement's log-likelihood must not be NaN");
514 auto result = ParticleFilterUpdate<Scalar_>{};
515 internal::UpdateAccess::logLikelihood(result) = logLikelihood;
516 result.accepted = logLikelihood > -Eigen::NumTraits<Scalar_>::infinity();
517 if (result.accepted)
518 {
519 internal::ParticleSetAccess::setNormalizedLogWeights(m_state, logWeights - logLikelihood);
520 }
521 return result;
522 }
523
524private:
525
526 using ScalarAllocator = internal::ReBound<Allocator_, Scalar_>;
527
529 void
530 reserveScratch()
531 {
532 auto const count = std::size_t(m_state.capacity().value_or(m_state.size()));
533 m_logLikelihoods.reserve(count);
534 m_draws.reserve(std::size_t(m_state.differenceDimension()) * count);
535 }
536
551 template <typename P, typename G, typename Derived, typename Propagate, typename... Inputs>
552 void
553 moveParticles(
554 P && policy,
555 G & rng,
556 Eigen::MatrixBase<Derived> const & noiseFactor,
557 Propagate const & propagate,
558 Inputs const &... inputs
559 )
560 {
561 using Vector = ValueVector<Space_, Scalar_>;
562 using Difference = DifferenceVector<Space_, Scalar_>;
563 constexpr int NoiseRows = internal::rowsAtCompileTime<true, Space_>;
564 constexpr int Rows = internal::sizeSum<NoiseRows, internal::DrawnInput<Inputs>::RowsAtCompileTime...>;
565 constexpr int MaxRows = internal::sizeSum<
567 internal::DrawnInput<Inputs>::MaxRowsAtCompileTime...>;
568 auto const & space = m_state.space();
569 Eigen::Index const count = m_state.size();
570 EMRYS_FILTER_ASSERT(count > 0 && "the particle set must have a particle");
571 Eigen::Index const noiseRows = differenceDimension(space);
572 // Initialized in order, each input taking its rows after those before it.
573 Eigen::Index row = noiseRows;
574 auto const drawn = std::tuple{internal::DrawnInput<Inputs>{inputs, row}...};
575 Eigen::Index const rows = noiseRows + (Eigen::Index{0} + ... + internal::drawnRows(inputs));
576 EMRYS_FILTER_ASSERT(row == rows);
577 // One distribution for every draw, which may keep a value between them, so that the draws
578 // are those of filling every particle's column at once.
579 auto normal = std::normal_distribution<Scalar_>{};
580 auto const draw = [&](auto && column) {
581 internal::fillStandardNormal(internal::middleRowsOf<NoiseRows>(column, 0, noiseRows), rng, normal);
582 std::apply(
583 [&](auto const &... inputDraws) {
584 (inputDraws.fill(column, rng, normal), ...);
585 },
586 drawn
587 );
588 };
589 auto const move = [&](Eigen::Index i, auto const & column) {
590 Difference const z = internal::middleRowsOf<NoiseRows>(column, 0, noiseRows);
591 Vector const moved = std::apply(
592 [&](auto const &... inputDraws) {
593 return Vector{propagate(m_state.state(i), inputDraws.at(column)...)};
594 },
595 drawn
596 );
597 m_state.setState(i, Emrys::plus(space, moved, Difference{internal::multiply(noiseFactor, z)}));
598 };
599 if constexpr (internal::isSequential<P>)
600 {
601 auto column = internal::MatrixOf<Scalar_, Rows, 1, MaxRows, 1>{};
602 column.resize(rows);
603 for (Eigen::Index i = 0; i < count; ++i)
604 {
605 draw(column);
606 move(i, column);
607 }
608 }
609 else
610 {
611 using Draws = internal::MatrixOf<Scalar_, Rows, Eigen::Dynamic, MaxRows, Eigen::Dynamic>;
612 m_draws.resize(std::size_t(rows * count));
613 auto draws = Eigen::Map<Draws>{m_draws.data(), rows, count};
614 for (Eigen::Index i = 0; i < count; ++i)
615 {
616 draw(draws.col(i));
617 }
618 internal::forEachIndex(std::forward<P>(policy), count, [&](Eigen::Index i) {
619 move(i, draws.col(i));
620 });
621 }
622 }
623
630 template <typename P, typename G, typename Derived, typename R, typename TimeScalar, typename... Inputs>
631 void
632 moveInBatches(
633 P && policy,
634 G & rng,
635 Eigen::MatrixBase<Derived> const & noiseFactor,
636 R const & resolved,
637 TimeScalar dt,
638 Inputs const &... inputs
639 )
640 {
641 using Difference = DifferenceVector<Space_, Scalar_>;
642 constexpr int NoiseRows = internal::rowsAtCompileTime<true, Space_>;
643 constexpr int Rows = internal::sizeSum<NoiseRows, internal::DrawnInput<Inputs>::RowsAtCompileTime...>;
644 constexpr int MaxRows = internal::sizeSum<
646 internal::DrawnInput<Inputs>::MaxRowsAtCompileTime...>;
647 using Draws = internal::MatrixOf<Scalar_, Rows, Eigen::Dynamic, MaxRows, Eigen::Dynamic>;
648 using X = typename R::template Columns<typename R::In, Scalar_>;
649 using Y = typename R::template Columns<typename R::Out, Scalar_>;
650 auto const & space = m_state.space();
651 Eigen::Index const count = m_state.size();
652 EMRYS_FILTER_ASSERT(count > 0 && "the particle set must have a particle");
653 Eigen::Index const noiseRows = differenceDimension(space);
654 Eigen::Index row = noiseRows;
655 auto const drawn = std::tuple{internal::DrawnInput<Inputs>{inputs, row}...};
656 Eigen::Index const rows = noiseRows + (Eigen::Index{0} + ... + internal::drawnRows(inputs));
657 EMRYS_FILTER_ASSERT(row == rows);
658 auto normal = std::normal_distribution<Scalar_>{};
659 m_draws.resize(std::size_t(rows * count));
660 auto draws = Eigen::Map<Draws>{m_draws.data(), rows, count};
661 for (Eigen::Index i = 0; i < count; ++i)
662 {
663 auto column = draws.col(i);
664 internal::fillStandardNormal(internal::middleRowsOf<NoiseRows>(column, 0, noiseRows), rng, normal);
665 std::apply(
666 [&](auto const &... inputDraws) {
667 (inputDraws.fill(column, rng, normal), ...);
668 },
669 drawn
670 );
671 }
672 Eigen::Index const inRows = valueDimension(resolved.in());
673 Eigen::Index const outRows = valueDimension(resolved.out());
674 m_batch.resize(std::size_t((inRows + outRows) * count));
675 internal::forEachChunk(std::forward<P>(policy), count, [&](Eigen::Index begin, Eigen::Index length) {
676 auto x = Eigen::Map<X>{m_batch.data() + inRows * begin, inRows, length};
677 auto y = Eigen::Map<Y>{m_batch.data() + inRows * count + outRows * begin, outRows, length};
678 for (Eigen::Index j = 0; j < length; ++j)
679 {
680 std::apply(
681 [&](auto const &... inputDraws) {
682 resolved.template gatherColumn<Scalar_>(
683 x.col(j),
684 m_state.state(begin + j),
685 inputDraws.at(draws.col(begin + j))...
686 );
687 },
688 drawn
689 );
690 }
691 resolved.stepBatch(Eigen::Map<X const>{x.data(), inRows, length}, dt, y);
692 for (Eigen::Index j = 0; j < length; ++j)
693 {
694 Eigen::Index const i = begin + j;
695 auto const column = draws.col(i);
696 Difference const z = internal::middleRowsOf<NoiseRows>(column, 0, noiseRows);
697 auto const moved = resolved.scattered(m_state.state(i), y.col(j));
698 m_state.setState(i, Emrys::plus(space, moved, Difference{internal::multiply(noiseFactor, z)}));
699 }
700 });
701 }
702
703 Model_ m_model;
704 StateType m_state;
705 internal::Buffer<Scalar_, Allocator_> m_logLikelihoods;
706 internal::Buffer<Scalar_, Allocator_> m_draws;
707 internal::Buffer<Scalar_, Allocator_> m_batch;
708};
709
711template <typename Space, typename Model, typename Scalar, typename Allocator>
714
715template <typename Space, typename Model, typename Scalar, typename Allocator, typename U>
719
720} // namespace Emrys
721
722#ifndef EMRYS_FILTER_NO_IO
723
724namespace Emrys
725{
726
727namespace internal
728{
729
731template <typename Space_, typename Model_, typename Scalar_, typename Allocator_, typename Upkeep_>
732void
733describe(
734 std::ostream & stream,
735 ParticleFilter<Space_, Model_, Scalar_, Allocator_, Upkeep_> const & filter,
736 Indent indent
737)
738{
739 describeFilter(stream, "particle filter", filter.state(), indent);
740}
741
742} // namespace internal
743
744} // namespace Emrys
745
746#endif // EMRYS_FILTER_NO_IO
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
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 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'...
The particle set: ParticleSet, the weighted samples, with resampling, upkeep of weights and particles...
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 Recursion concept (decisions.md [filters-and-recursions], [user-extension-points]): what a Kalman...
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(),...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
Propagating a distribution through a function (decisions.md [method-per-measurement],...
Log-weights: the WeightError a normalization can fail with (NumericError.h), and the streaming log-su...
DifferenceMatrix< Space_, Space_, Scalar > MatrixType
a matrix over differences, such as the covariance
Definition Moments.h:76
DifferenceVector< Space_, Scalar > DifferenceVectorType
a difference, such as a residual
Definition Moments.h:75
ValueVector< Space_, Scalar > VectorType
a value, such as the mean
Definition Moments.h:74
What a particle filter's update did: the observation's log-likelihood under the particles,...
Definition ParticleFilter.h:47
bool accepted
whether any particle could explain the observation
Definition ParticleFilter.h:57
Scalar logLikelihood() const
Definition ParticleFilter.h:52
A particle filter: a weighted set of state points, moved by sampling the process model and weighted b...
Definition ParticleFilter.h:249
void predict(G &rng, TimeStep< Scalar_ > auto const &dt, Inputs const &... inputs)
Moves each particle forward by dt, any TimeStep (see Time steps), through the process model and adds ...
Definition ParticleFilter.h:349
Model_ & model()
Definition ParticleFilter.h:332
StateType const & state() const
Definition ParticleFilter.h:288
std::expected< ParticleFilterUpdate< Scalar_ >, WeightError > update(P &&policy, M const &measurement)
update() under policy: the likelihoods are a for-each over the particles and the evidence and the tot...
Definition ParticleFilter.h:500
ParticleSet< Space_, Scalar_, Allocator_ > StateType
the state the filter owns
Definition ParticleFilter.h:257
void setState(StateType state)
Replaces the particles, as when reinitializing, with a set that has at least one and whose space the ...
Definition ParticleFilter.h:308
void predict(G &rng, Inputs const &... inputs)
Moves each particle forward by the fixed-step model's step, as predict(rng, dt, inputs....
Definition ParticleFilter.h:404
void predict(P &&policy, G &rng, Inputs const &... inputs)
predict(rng, inputs...) with a fixed-step model, under policy, as predict(policy, rng,...
Definition ParticleFilter.h:416
void 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 ParticleFilter.h:362
Model_ ModelType
the process model
Definition ParticleFilter.h:256
ParticleFilter(std::type_identity_t< Model_ > model, StateType state, std::type_identity_t< Upkeep_ > upkeep={})
A filter with process model model, initial particles state, which must not be empty,...
Definition ParticleFilter.h:266
void predict(G &rng, Steps steps, Inputs const &... inputs)
Moves each particle forward by steps of the fixed-step model, as that many calls of predict(rng,...
Definition ParticleFilter.h:458
Allocator_ allocator_type
the state's allocator
Definition ParticleFilter.h:258
allocator_type get_allocator() const
Definition ParticleFilter.h:281
std::expected< ParticleFilterUpdate< Scalar_ >, WeightError > update(M const &measurement)
Multiplies each particle's weight by the observation's likelihood there, , and normalizes the weights...
Definition ParticleFilter.h:489
void predict(P &&policy, G &rng, Steps steps, Inputs const &... inputs)
predict(rng, steps, inputs...) under policy, as that many calls of predict(policy,...
Definition ParticleFilter.h:469
Scalar_ Scalar
the scalar type
Definition ParticleFilter.h:254
StateType & state()
Definition ParticleFilter.h:298
Space_ SpaceType
the state space
Definition ParticleFilter.h:255
Model_ const & model() const
Definition ParticleFilter.h:325
A set of weighted samples: the empirical distribution.
Definition ParticleSet.h:279
Index size() const
Definition ParticleSet.h:606
bool empty() const
Definition ParticleSet.h:613
std::optional< Index > capacity() const
Definition ParticleSet.h:620
Space_ const & space() const
Definition ParticleSet.h:652
Index differenceDimension() const
Definition ParticleSet.h:645
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
Scalar logSumExp(P &&policy, Eigen::Index count, LogAt const &logAt)
Definition Weights.h:151
bool isNaN(T const &x)
Definition Math.h:329
NumericError WeightError
Reasons a collection of log-weights cannot be normalized: Empty, ZeroSum, or NonFinite of NumericErro...
Definition NumericError.h:53
constexpr Sequential sequential
The default execution policy: plain loops on the calling thread, in index order (Sequential).
Definition Execution.h:128
Derived::Scalar logLikelihood(M const &measurement, Space const &space, Eigen::MatrixBase< Derived > const &x)
Definition Likelihood.h:433
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::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
ValueVector< DifferenceSpace< S >, Scalar > DifferenceVector
A difference in S as an Eigen column vector of Scalar, the type of minus() and of the offset plus() t...
Definition Space.h:650
Eigen::Index differenceDimension(S const &space)
Definition Space.h:284
constexpr int maxValueDimensionAtCompileTime
The largest valid value dimension of Space, or Eigen::Dynamic if it is unbounded.
Definition Space.h:258
Eigen::Matrix< Scalar, valueDimensionAtCompileTime< S >, 1, Eigen::ColMajor, maxValueDimensionAtCompileTime< S >, 1 > ValueVector
A value in S as an Eigen column vector of Scalar: a mean, a sample, or a true state.
Definition Space.h:640
The upkeep operations, each made by its factory (decisions.md [policy-factories], [upkeep]): the acti...
Definition Upkeep.h:380
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