22#include <Eigen/Cholesky>
56template <
typename Scalar,
typename Noise,
typename Res
idual,
typename Omega>
58widenedLogDensity(Noise
const & noise, Residual
const & residual, Omega
const & omega)
62 return Eigen::NumTraits<Scalar>::quiet_NaN();
64 auto const component = [&](
auto const & gaussian) {
65 using Gaussian = std::remove_cvref_t<
decltype(gaussian)>;
66 using Widened = GaussianParams<typename Gaussian::SpaceType, Scalar>;
67 using Matrix =
typename Widened::MatrixType;
68 Matrix cov = symmetricFromLower<Matrix>(gaussian.covarianceLower());
70 auto const widened = Widened{
72 typename Widened::VectorType{gaussian.mean().template cast<Scalar>()},
75 auto const density = widened.toDensity();
76 EMRYS_FILTER_ASSERT(density &&
"the measurement noise must factorize");
77 return Scalar(density->logDensity(residual));
79 if constexpr (isGaussianMixture<Noise>)
81 auto const total = noise.logTotalWeight();
82 EMRYS_FILTER_ASSERT(total &&
"the noise mixture's weights must be valid");
83 auto sum = LogSumExp<Scalar>{};
84 for (
auto const & entry : noise)
86 sum.add(Scalar(entry.logWeight) - Scalar(*total) + component(entry.component));
92 return component(noise);
103template <ExecutionPolicy P,
typename R,
typename RowsOf,
typename Scalar,
typename Scratch>
105fillBatchedLogLikelihoods(
109 RowsOf
const & rowsOf,
115 using InMatrix =
typename R::template InMatrix<Scalar>;
117 scratch.resize(std::size_t(rows * count));
118 forEachChunk(std::forward<P>(policy), count, [&](Eigen::Index begin, Eigen::Index length) {
119 auto x = Eigen::Map<InMatrix>{scratch.data() + rows * begin, rows, length};
120 resolved.template gatherColumnsFromRows<Scalar>(
122 [&](Eigen::Index j) {
123 return rowsOf(begin + j);
127 resolved.batchedLogLikelihoods(
128 Eigen::Map<InMatrix const>{x.data(), rows, length},
129 Eigen::Map<Eigen::Matrix<Scalar, 1, Eigen::Dynamic>>{result + begin, length}
146template <ExecutionPolicy P, WeighsPo
ints M,
typename Space,
typename Derived,
typename Result,
typename Scratch>
150 M
const & measurement,
152 Eigen::MatrixBase<Derived>
const & states,
157 using Scalar =
typename Derived::Scalar;
158 EMRYS_FILTER_ASSERT(states.rows() ==
valueDimension(space) &&
"the states do not fit the space");
159 EMRYS_FILTER_ASSERT(result.size() == states.cols() &&
"give one entry per state");
162 "consider() is a Kalman update's; a filter that weights points moves no block it does not condition "
163 "(decisions.md [consider-states])"
165 auto const resolved = resolveMeasurement(measurement, space);
166 using R = std::remove_cvref_t<
decltype(resolved)>;
167 if constexpr (R::BatchedLikelihood)
169 fillBatchedLogLikelihoods(
170 std::forward<P>(policy),
173 [&](Eigen::Index j) {
174 return states.col(j);
181 else if constexpr (R::HasLogLikelihood)
183 forEachIndex(std::forward<P>(policy), states.cols(), [&](Eigen::Index j) {
184 result(j) = Scalar(resolved.logLikelihoodAt(states.col(j)));
191 "a measurement model with no additive noise has no likelihood of its own at a point; give it "
192 "logLikelihood(g), or name the inputs it is affine in with affineIn() beside additiveNoise()"
196 "the likelihood at a point of noise that passes through the function is exact only where the model is "
197 "affine in it, so name the input in affineIn(), or give the model logLikelihood(g) (decisions.md "
198 "[likelihood-measurements])"
200 auto const & space_ = resolved.space();
201 if constexpr (R::InputCount == 0 && R::BatchedFunction)
204 auto const & noise = resolved.noise().distribution();
205 auto const density = noise.toDensity();
206 EMRYS_FILTER_ASSERT(density &&
"the measurement noise must factorize");
207 using InMatrix =
typename R::template InMatrix<Scalar>;
208 using OutMatrix =
typename R::template OutMatrix<Scalar>;
209 Eigen::Index
const count = states.cols();
212 scratch.resize(std::size_t((inRows + outRows) * count));
213 forEachChunk(std::forward<P>(policy), count, [&](Eigen::Index begin, Eigen::Index length) {
214 auto x = Eigen::Map<InMatrix>{scratch.data() + inRows * begin, inRows, length};
215 auto y = Eigen::Map<OutMatrix>{scratch.data() + inRows * count + outRows * begin, outRows, length};
216 resolved.template gatherColumnsFromRows<Scalar>(
218 [&](Eigen::Index j) {
219 return states.col(begin + j);
223 resolved.evaluateBatch(Eigen::Map<InMatrix const>{x.data(), inRows, length}, y);
224 for (Eigen::Index j = 0; j < length; ++j)
226 result(begin + j) = density->logDensity(observedResidual<Scalar>(resolved, space_, y.col(j)));
230 else if constexpr (R::InputCount == 0)
232 auto const & noise = resolved.noise().distribution();
233 auto const density = noise.toDensity();
234 EMRYS_FILTER_ASSERT(density &&
"the measurement noise must factorize");
235 forEachIndex(std::forward<P>(policy), states.cols(), [&](Eigen::Index j) {
236 auto const predicted = valueOf(resolved.evaluateAtState(states.col(j))).eval();
237 result(j) = density->logDensity(observedResidual<Scalar>(resolved, space_, predicted));
240 else if constexpr (R::BatchedFunction)
245 using Out =
typename R::Out;
246 using InMatrix =
typename R::template InMatrix<Scalar>;
247 using OutMatrix =
typename R::template OutMatrix<Scalar>;
248 using JacobianMatrix = MatrixOf<
255 auto const inputs = resolved.inputs();
258 [&](
auto const &... input) {
259 ((w += inputOf(input).differenceDimension()), ...);
263 Eigen::Index
const count = states.cols();
267 scratch.resize(std::size_t((inRows + outRows + m * w) * count));
268 Scalar *
const outputs = scratch.data() + inRows * count;
269 Scalar *
const jacobianData = outputs + outRows * count;
270 forEachChunk(std::forward<P>(policy), count, [&](Eigen::Index begin, Eigen::Index length) {
271 auto x = Eigen::Map<InMatrix>{scratch.data() + inRows * begin, inRows, length};
272 auto y = Eigen::Map<OutMatrix>{outputs + outRows * begin, outRows, length};
273 auto jacobians = Eigen::Map<JacobianMatrix>{jacobianData + m * w * begin, m, w * length};
274 resolved.template gatherColumnsFromRows<Scalar>(
276 [&](Eigen::Index j) {
277 return states.col(begin + j);
281 resolved.evaluateBatchWithInputJacobians(
282 Eigen::Map<InMatrix const>{x.data(), inRows, length},
286 for (Eigen::Index j = 0; j < length; ++j)
288 Omega omega = Omega::Zero(m, m);
289 Eigen::Index offset = j * w;
291 [&](
auto const &... argument) {
293 [&](
auto const & input) {
294 using Input = std::remove_cvref_t<
decltype(input)>;
295 using Cov = MatrixOf<
297 Input::DifferenceDimensionAtCompileTime,
298 Input::DifferenceDimensionAtCompileTime,
299 Input::MaxDifferenceDimensionAtCompileTime,
300 Input::MaxDifferenceDimensionAtCompileTime>;
301 Eigen::Index
const d = input.differenceDimension();
303 middleColsOf<Input::DifferenceDimensionAtCompileTime>(jacobians, offset, d);
304 Cov
const cov = symmetricFromLower<Cov>(covarianceLowerOf(input));
305 omega.noalias() += multiply(multiply(
block, cov),
block.transpose());
307 }(inputOf(argument)),
313 omega = (Scalar(0.5) * (omega + omega.transpose())).eval();
314 result(begin + j) = widenedLogDensity<Scalar>(
315 resolved.noise().distribution(),
316 observedResidual<Scalar>(resolved, space_, y.col(j)),
326 auto const & reads = resolved.reads();
327 using Reads =
typename R::Reads;
328 using ReadPoint = PointInput<typename Reads::JointSpace, Scalar>;
329 auto const f = ResolvedFunction{resolved};
330 forEachIndex(std::forward<P>(policy), states.cols(), [&](Eigen::Index j) {
332 ReadPoint{reads.space(), typename ReadPoint::VectorType{states.col(j)(reads.indices())}};
333 result(j) = linearizeMeasurement(
338 [&](
auto const & problem,
auto const & linearized) {
339 using Problem = std::remove_cvref_t<
decltype(problem)>;
340 using Omega =
typename Problem::OutputMatrix;
341 Omega
const omega = inputsCovariance<Omega>(resolved, problem,
linearized.jacobian);
342 return widenedLogDensity<Scalar>(
343 resolved.noise().distribution(),
344 observedResidual<Scalar>(resolved, space_,
linearized.mean),
355template <ExecutionPolicy P, WeighsPo
ints M,
typename Space,
typename Derived,
typename Result>
359 M
const & measurement,
361 Eigen::MatrixBase<Derived>
const & states,
365 auto scratch = Buffer<typename Derived::Scalar, DefaultAllocator>();
366 fillLogLikelihoods(std::forward<P>(policy), measurement, space, states, std::forward<Result>(result), scratch);
370template <WeighsPo
ints M,
typename Space,
typename Derived,
typename Result>
373 M
const & measurement,
375 Eigen::MatrixBase<Derived>
const & states,
406template <
internal::WeighsPo
ints M,
typename Space,
typename Derived>
407[[nodiscard]] Eigen::Array<typename Derived::Scalar, Eigen::Dynamic, 1>
418template <ExecutionPolicy P,
internal::WeighsPo
ints M,
typename Space,
typename Derived>
419[[nodiscard]] Eigen::Array<typename Derived::Scalar, Eigen::Dynamic, 1>
420logLikelihoods(P && policy, M
const & measurement,
Space const & space, Eigen::MatrixBase<Derived>
const & states)
422 auto result = Eigen::Array<typename Derived::Scalar, Eigen::Dynamic, 1>{states.cols()};
423 internal::fillLogLikelihoods(std::forward<P>(policy), measurement, space, states, result);
431template <
internal::WeighsPo
ints M,
typename Space,
typename Derived>
432[[nodiscard]]
typename Derived::Scalar
435 EMRYS_FILTER_ASSERT(x.cols() == 1 &&
"the state point must be a column vector");
443template <FixedSizeSpace S,
internal::WeighsPo
ints M,
typename Derived>
445[[nodiscard]] Eigen::Array<typename Derived::Scalar, Eigen::Dynamic, 1>
455template <FixedSizeSpace S, ExecutionPolicy P,
internal::WeighsPo
ints M,
typename Derived>
457[[nodiscard]] Eigen::Array<typename Derived::Scalar, Eigen::Dynamic, 1>
458logLikelihoods(P && policy, M
const & measurement, Eigen::MatrixBase<Derived>
const & states)
460 return logLikelihoods(std::forward<P>(policy), measurement, S{}, states);
467template <FixedSizeSpace S,
internal::WeighsPo
ints M,
typename Derived>
469[[nodiscard]]
typename Derived::Scalar
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
Spaces built from other spaces (decisions.md [sizes-and-dimensions], [several-resizable-blocks]): Com...
The coordinate types (decisions.md [no-bounded-coordinates]): Linear, plain coordinates,...
Execution policies (decisions.md [execution-policies]): execution::sequential, the ExecutionPolicy co...
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 macros every header includes first.
Measurement models and their observations (decisions.md [model-policies], [sensors],...
How an update reads a measurement, all internal (decisions.md [model-policies], [measurement-space-fu...
The mixture: the parameters MixtureParams of weighted components of one type (decisions....
Products of fixed-size matrices by Eigen's fixed-size product at every size: multiply() is by Eigen'...
Product: the product of independent densities, each on its own block of a space, built with on<Path>(...
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...
Subspaces, and growing and shrinking blocks (decisions.md [several-resizable-blocks]).
Tag paths and the index utilities (decisions.md [tag-addressing], [index-names]): TagPath and TagPath...
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
A type usable as the space of a distribution.
Definition Space.h:186
bool allFinite(Eigen::DenseBase< Derived > const &x)
Definition Math.h:354
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
Eigen::Array< typename Derived::Scalar, Eigen::Dynamic, 1 > logLikelihoods(M const &measurement, Space const &space, Eigen::MatrixBase< Derived > const &states)
Definition Likelihood.h:408
Eigen::Index valueDimension(S const &space)
Definition Space.h:272
auto block(Space auto const &space, X &&x)
Definition TagPath.h:979
Eigen::Index differenceDimension(S const &space)
Definition Space.h:284
constexpr int valueDimensionAtCompileTime
The value dimension of Space at compile time, or Eigen::Dynamic if it is resizable.
Definition Space.h:251
constexpr int maxValueDimensionAtCompileTime
The largest valid value dimension of Space, or Eigen::Dynamic if it is unbounded.
Definition Space.h:258