37template <
typename Jo
int,
typename Gains,
typename Next,
typename Smoothed>
39smoothHybridStep(Joint
const & joint, Gains
const & gains, Next
const & next, Smoothed & smoothed)
41 using Scalar =
typename Joint::Scalar;
42 using ModesType =
typename Joint::ModesType;
43 using ArrayType =
typename ModesType::ArrayType;
44 using GaussianType = GaussianParams<typename Joint::SpaceType, Scalar>;
45 Scalar
const minusInfinity = -Eigen::NumTraits<Scalar>::infinity();
46 Eigen::Index
const count = joint.modes.cardinality();
48 Eigen::Index(joint.joints.size()) == count && Eigen::Index(gains.size()) == count && next.size() == count
49 && smoothed.size() == count
50 &&
"the joint, its gains, the next state, and the smoothed state must have one Gaussian per mode"
52 auto const &
pi = joint.transitions;
53 auto const logFiltered = logProbabilitiesOf(joint.modes);
54 auto const logNext = logProbabilitiesOf(next.modes());
55 auto const logTransition = [&](Eigen::Index from, Eigen::Index to) {
56 return pi(from, to) > Scalar(0) ? Scalar(Eigen::numext::log(
pi(from, to))) : minusInfinity;
61 auto logPredicted = ArrayType{};
62 logPredicted.resize(count);
63 for (Eigen::Index i = 0; i < count; ++i)
65 auto total = LogSumExp<Scalar>{};
66 for (Eigen::Index l = 0; l < count; ++l)
68 total.add(logTransition(l, i) + logFiltered(l));
70 logPredicted(i) = total.value();
73 auto logMixing = ArrayType{};
74 logMixing.resize(count);
75 auto logModes = ArrayType{};
76 logModes.resize(count);
77 for (Eigen::Index j = 0; j < count; ++j)
80 for (Eigen::Index i = 0; i < count; ++i)
82 logMixing(i) = logPredicted(i) == minusInfinity
84 : logTransition(j, i) + logFiltered(j) - logPredicted(i) + logNext(i);
86 auto const & modeJoint = joint.joints[std::size_t(j)];
87 if (logTotalWeight<Scalar>(logMixing))
90 GaussianType
const mixed = ComponentTraits<GaussianType>::collapse(
92 [&](Eigen::Index i) -> GaussianType
const & {
93 return next.conditional(i);
99 smoothed.setConditional(j,
smoothStep(modeJoint, gains[std::size_t(j)], mixed));
104 smoothed.setConditional(j, modeJoint.filtered);
113 auto const logAdd = [](Scalar a, Scalar b) {
114 auto sum = LogSumExp<Scalar>{};
119 logModes.setConstant(minusInfinity);
120 auto logPair = ArrayType{};
121 logPair.resize(count);
122 auto logBackward = ArrayType{};
123 logBackward.resize(count);
124 for (Eigen::Index i = 0; i < count; ++i)
126 if (logNext(i) == minusInfinity || logPredicted(i) == minusInfinity)
130 auto const & smoothedMean = next.conditional(i).mean();
131 for (Eigen::Index j = 0; j < count; ++j)
133 logBackward(j) = logTransition(j, i) + logFiltered(j) - logPredicted(i);
134 logPair(j) = minusInfinity;
135 if (logBackward(j) > minusInfinity)
137 if (
auto const density = joint.predictedThrough(j, i).toDensity())
139 logPair(j) = logBackward(j) + density->logDensity(smoothedMean);
143 auto const logNormalizer = logTotalWeight<Scalar>(logPair);
144 for (Eigen::Index j = 0; j < count; ++j)
146 Scalar
const logGiven = logNormalizer ? logPair(j) - *logNormalizer : logBackward(j);
147 logModes(j) = logAdd(logModes(j), logNext(i) + logGiven);
150 auto modes = ModesType{joint.modes.space(), logModes};
151 [[maybe_unused]]
auto const normalized = modes.normalize();
152 EMRYS_FILTER_ASSERT(normalized &&
"no mode smoothed at the step's end came from a mode at its start");
153 smoothed.setModes(std::move(modes));
239template <Space Space_, DiscreteSpace ModeSpace_, RealScalar Scalar_ =
double,
typename Allocator_ = DefaultAllocator>
268 explicit Step(
JointType const & recorded, Allocator_
const & allocator = {})
269 :
joint{copyJoint(recorded, allocator)}
270 ,
smoothed{recorded.modes, recorded.joints.
front().filtered, allocator}
278 Step(
Step const & other, Allocator_
const & allocator)
289 std::move(other.
joint.modes),
290 typename
JointType::JointsType(std::move(other.
joint.joints), allocator),
291 std::move(other.
joint.transitions),
292 typename
JointType::PredictionsType(std::move(other.
joint.throughOtherModels), allocator)
320 smoothed.setConditional(j,
joint.joints[std::size_t(j)].filtered);
329 for (std::size_t j = 0; j <
gains.size(); ++j)
331 gains[j] = internal::rtsGain(
joint.joints[j]);
341 internal::Buffer<GainType, Allocator_>
gains;
347 copyJoint(
JointType const & recorded, Allocator_
const & allocator)
360 using StepAllocator = internal::ReBound<Allocator_, Step>;
361 using ListType = std::list<Step, StepAllocator>;
372 : m_steps(StepAllocator(allocator))
377 : m_steps(StepAllocator(allocator))
380 EMRYS_FILTER_ASSERT(
lag.steps > 0 &&
"a fixed-lag history keeps at least one step");
390 : m_steps(other.m_steps, StepAllocator(allocator))
401 : m_steps(std::move(other.m_steps), StepAllocator(allocator))
423 [[nodiscard]] std::optional<Index>
426 return m_lag > 0 ? std::optional<Index>{m_lag} : std::nullopt;
433 return Index(m_steps.size());
440 return m_steps.empty();
444 [[nodiscard]] Step
const &
447 EMRYS_FILTER_ASSERT(!
empty() &&
"the history is empty");
448 return m_steps.front();
452 [[nodiscard]] Step
const &
455 EMRYS_FILTER_ASSERT(!
empty() &&
"the history is empty");
456 return m_steps.back();
463 return m_steps.begin();
470 return m_steps.end();
479 EMRYS_FILTER_ASSERT(!joint.
joints.empty() &&
"the joint has no modes");
480 if (m_lag > 0 &&
size() == m_lag)
482 m_steps.splice(m_steps.end(), m_steps, m_steps.begin());
483 Step & step = m_steps.back();
493 m_steps.emplace_back(joint);
501 template <
typename LatestAllocator>
505 auto step = m_steps.rbegin();
506 if (step == m_steps.rend())
510 internal::smoothHybridStep(step->joint, step->gains, latest, step->smoothed);
511 for (
auto next = step++; step != m_steps.rend(); next = step++)
513 internal::smoothHybridStep(step->joint, step->gains, next->smoothed, step->smoothed);
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
Discrete spaces (decisions.md [discrete-spaces]): the DiscreteSpace concept; Finite,...
Smoothing the Kalman family (decisions.md [smoothing]): smoothStep(), the Rauch-Tung-Striebel backwar...
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...
Lag, the number of steps a fixed-lag history keeps, which every history of the Smoothers layer takes ...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
Log-weights: the WeightError a normalization can fail with (NumericError.h), and the streaming log-su...
typename MomentsType::MatrixType MatrixType
a matrix over differences
Definition Gaussian.h:267
One recorded prediction and its smoothed hybrid state, built from the history's allocator.
Definition HybridGaussianHistory.h:254
internal::ReBound< Allocator_, GainType > GainAllocator
The allocator of the gains.
Definition HybridGaussianHistory.h:263
Step & operator=(Step &&)=default
Takes the other step's storage, as the members' do.
Step(Step &&)=default
moves the joint and the smoothed state
JointType joint
the prediction as predictJoint() recorded it
Definition HybridGaussianHistory.h:335
Step(Step const &)=default
copies the joint and the smoothed state
Step(JointType const &recorded, Allocator_ const &allocator={})
A copy of recorded in storage from allocator, with the filtered state as its smoothed one until smoot...
Definition HybridGaussianHistory.h:268
void resetSmoothed()
Replaces the smoothed state with the filtered one: the joint's mode probabilities and each mode's fil...
Definition HybridGaussianHistory.h:315
Step & operator=(Step const &)=default
Copies into this step's storage.
void computeGains()
Computes each mode's gain from its joint (internal::rtsGain()), once per recording.
Definition HybridGaussianHistory.h:326
Step(Step const &other, Allocator_ const &allocator)
Copies other into storage from allocator.
Definition HybridGaussianHistory.h:278
Allocator_ allocator_type
the allocator its joints and Gaussians come from
Definition HybridGaussianHistory.h:257
Step(Step &&other, Allocator_ const &allocator)
Moves other into storage from allocator, taking its storage when the allocators are equal.
Definition HybridGaussianHistory.h:287
internal::Buffer< GainType, Allocator_ > gains
Each mode's Rauch-Tung-Striebel gain, made once when the joint is recorded.
Definition HybridGaussianHistory.h:341
typename GaussianParams< Space_, Scalar_ >::MatrixType GainType
One mode's Rauch-Tung-Striebel gain.
Definition HybridGaussianHistory.h:260
SmoothedType smoothed
as of the last smooth(); the filtered state until then
Definition HybridGaussianHistory.h:338
The record of an IMM filter's forward pass that its smoother runs backward over: one HybridPredictedJ...
Definition HybridGaussianHistory.h:241
std::optional< Index > lag() const
Definition HybridGaussianHistory.h:424
HybridGaussianHistory & operator=(HybridGaussianHistory &&other)=default
Takes other's steps and lag, as std::list's move assignment does.
HybridGaussianHistory()=default
An empty history that keeps every step.
HybridGaussianHistory & operator=(HybridGaussianHistory const &other)=default
Copies other's steps and lag.
Allocator_ allocator_type
the allocator the steps come from
Definition HybridGaussianHistory.h:249
allocator_type get_allocator() const
Definition HybridGaussianHistory.h:417
HybridGaussianHistory(HybridGaussianHistory const &other)
Copies the steps into nodes from other's allocator (see Allocation).
Definition HybridGaussianHistory.h:384
HybridPredictedJoint< Space_, ModeSpace_, Scalar_, Allocator_ > JointType
what each step records
Definition HybridGaussianHistory.h:247
typename ListType::const_iterator const_iterator
iterates the steps, oldest first
Definition HybridGaussianHistory.h:365
Step const & front() const
Definition HybridGaussianHistory.h:445
ModeSpace_ ModeSpaceType
the discrete mode space
Definition HybridGaussianHistory.h:246
Index size() const
Definition HybridGaussianHistory.h:431
HybridGaussianParams< Space_, ModeSpace_, Scalar_, Allocator_ > SmoothedType
the smoothed state's type
Definition HybridGaussianHistory.h:248
void push(JointType const &joint)
Records a copy of joint as the newest step.
Definition HybridGaussianHistory.h:477
const_iterator begin() const
Definition HybridGaussianHistory.h:461
Space_ SpaceType
the continuous state space
Definition HybridGaussianHistory.h:245
Scalar_ Scalar
the scalar type
Definition HybridGaussianHistory.h:244
HybridGaussianHistory(Allocator_ const &allocator)
An empty history that keeps every step, with storage from allocator.
Definition HybridGaussianHistory.h:371
Step const & back() const
Definition HybridGaussianHistory.h:453
void clear()
Drops every step, keeping the lag.
Definition HybridGaussianHistory.h:519
HybridGaussianHistory(HybridGaussianHistory &&other, Allocator_ const &allocator)
Moves other's steps into storage from allocator, taking its storage when the allocators are equal.
Definition HybridGaussianHistory.h:400
HybridGaussianHistory(HybridGaussianHistory &&other)=default
Takes other's steps.
bool empty() const
Definition HybridGaussianHistory.h:438
Eigen::Index Index
Eigen's index type.
Definition HybridGaussianHistory.h:250
HybridGaussianHistory(Lag lag, Allocator_ const &allocator={})
An empty history that keeps the newest lag steps, with storage from allocator.
Definition HybridGaussianHistory.h:376
HybridGaussianHistory(HybridGaussianHistory const &other, Allocator_ const &allocator)
Copies other's steps into storage from allocator.
Definition HybridGaussianHistory.h:389
const_iterator end() const
Definition HybridGaussianHistory.h:468
void smooth(HybridGaussianParams< Space_, ModeSpace_, Scalar_, LatestAllocator > const &latest)
Fills every step's smoothed hybrid state by the backward IMM step above, from the newest back,...
Definition HybridGaussianHistory.h:503
Scalar pi()
Definition Math.h:145
HybridParams< Gaussian< Space_, Scalar_ >, ModeSpace_, Allocator_ > HybridGaussianParams
The HybridParams of Gaussians in covariance form: the parameters of a HybridGaussian,...
Definition Hybrid.h:754
CategoricalParams< Space, Scalar > smoothStep(CategoricalPredictedJoint< Space, Scalar > const &joint, CategoricalParams< Space, Scalar > const &smoothedNext)
Definition CategoricalHistory.h:114
One IMM prediction as its smoother needs it: the mode probabilities the step started from,...
Definition ImmFilter.h:138
ModesType modes
, the mode probabilities before the step
Definition ImmFilter.h:148
internal::Buffer< JointType, Allocator_ > JointsType
Definition ImmFilter.h:144
PredictionsType throughOtherModels
Mode j's filtered Gaussian moved through mode i's model for every i other than j, j major and i minor...
Definition ImmFilter.h:155
internal::Buffer< GaussianParams< Space_, Scalar_ >, Allocator_ > PredictionsType
Definition ImmFilter.h:146
TransitionsType transitions
, with
Definition ImmFilter.h:150
JointsType joints
one per mode, in flat-index order
Definition ImmFilter.h:149
The number of steps a fixed-lag history keeps.
Definition Lag.h:17