EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
GridGaussian.h
Go to the documentation of this file.
1#pragma once
2
11
12#include <algorithm>
13#include <array>
14#include <expected>
15#include <cmath>
16#include <cstddef>
17#include <optional>
18#include <expected>
19#include <span>
20#include <type_traits>
21#include <utility>
22#include <vector>
23
43
44namespace Emrys
45{
46
47template <typename Grid_, typename Model_, typename Covariance_, typename Method_, typename Upkeep_>
49
50template <
51 typename Grid_,
52 typename Covariance_ = SharedCovariance,
54class GridGaussian;
55
66template <typename Block, int I = 0>
67struct GridAxis : Finite<Eigen::Dynamic>
68{
70 using Finite::Finite;
71};
72
73namespace internal
74{
75
77template <typename Block, std::size_t... I>
78std::tuple<GridAxis<Block, int(I)>...> leafGridAxes(std::index_sequence<I...>);
79
81template <typename Block>
82struct GridAxesOf
83{
85 using type = decltype(leafGridAxes<Block>(std::make_index_sequence<std::size_t(Block::FixedValueDimension)>{}));
86};
87
89template <typename Block>
90 requires IsComposite<Block>
91struct GridAxesOf<Block>
92{
94 template <typename... Blocks>
95 static auto
96 of(std::tuple<Blocks...> *) -> decltype(std::tuple_cat(std::declval<typename GridAxesOf<Blocks>::type>()...));
97
99 using type = decltype(of(static_cast<CompositeBlocks<Block> *>(nullptr)));
100};
101
103template <typename... Axes>
104DiscreteProduct<Axes...>
105gridProduct(std::tuple<Axes...> *);
106
108template <typename Axis, typename... Axes>
109inline constexpr int axisOccurrences = (0 + ... + int(std::is_same_v<Axis, Axes>));
110
112template <typename... Axes>
113consteval bool
114distinctAxes(std::tuple<Axes...> *)
115{
116 return ((axisOccurrences<Axes, Axes...> == 1) && ...);
117}
118
120template <typename Path>
121using GridAxes = typename GridAxesOf<PathTag<Path>>::type;
122
123} // namespace internal
124
133template <typename Path>
134struct GridCells : decltype(internal::gridProduct(static_cast<internal::GridAxes<Path> *>(nullptr)))
135{
136 static_assert(
137 internal::distinctAxes(static_cast<internal::GridAxes<Path> *>(nullptr)),
138 "two coordinates of the block lie in blocks with the same tag, so their grid axes would share a name"
139 );
140
142 using Product = decltype(internal::gridProduct(static_cast<internal::GridAxes<Path> *>(nullptr)));
143
144 using Product::Product;
145};
146
151template <typename Path>
152struct PointCells : Finite<Eigen::Dynamic>
153{
155 using Finite::Finite;
156};
157
158namespace internal
159{
160
162template <typename Cells>
163struct IsGridCells : std::false_type
164{};
165
167template <typename Path>
168struct IsGridCells<GridCells<Path>> : std::true_type
169{};
170
171} // namespace internal
172
201template <
202 Space Space_,
203 typename Path_,
204 DiscreteSpace Cells_,
205 typename CellCovariance_ = SharedCovariance,
206 RealScalar Scalar_ = double,
207 typename Allocator_ = DefaultAllocator>
209{
210 static_assert(
211 internal::CovarianceForm<CellCovariance_>,
212 "the cell covariance is SharedCovariance or PerPointCovariance"
213 );
214
215 static constexpr bool Shared = std::is_same_v<CellCovariance_, SharedCovariance>;
216
217public:
218
220 using Scalar = Scalar_;
221
223 using SpaceType = Space_;
224
226 using CellsType = Cells_;
227
229 using PathType = Path_;
230
232 using CellCovarianceType = CellCovariance_;
233
235 using allocator_type = Allocator_;
236
238 using PinnedSpace = typename internal::BlockSplit<Space_, Path_>::PinnedSpace;
239
241 using RestSpace = typename internal::BlockSplit<Space_, Path_>::RestSpace;
242
245
248
251
253 static constexpr bool Regular = internal::IsGridCells<Cells_>::value;
254
255 static_assert(
256 !Regular || std::is_same_v<Cells_, GridCells<Path_>>,
257 "a regular grid's cells are the GridCells of its own block"
258 );
259
265 template <typename CentersDerived>
267 Space_ space,
268 Cells_ cells,
269 Eigen::MatrixBase<CentersDerived> const & centers,
270 std::optional<PinnedMatrix> cellCovariance = {},
271 Allocator_ const & allocator = {}
272 )
273 requires(Shared && !Regular)
274 : PointGrid{Parts{}, std::move(space), std::move(cells), listOf(cellCovariance), allocator}
275 {
276 setCenters(centers);
277 }
278
283 template <typename CentersDerived>
285 Space_ space,
286 Cells_ cells,
287 Eigen::MatrixBase<CentersDerived> const & centers,
288 std::span<PinnedMatrix const> cellCovariances,
289 Allocator_ const & allocator = {}
290 )
291 requires(!Shared && !Regular)
292 : PointGrid{Parts{}, std::move(space), std::move(cells), cellCovariances, allocator}
293 {
294 setCenters(centers);
295 }
296
303 Space_ space,
304 Cells_ cells,
307 std::optional<PinnedMatrix> cellCovariance = {},
308 Allocator_ const & allocator = {}
309 )
310 requires(Shared && Regular)
311 : PointGrid{Parts{}, std::move(space), std::move(cells), listOf(cellCovariance), allocator}
312 {
313 setGeometry(std::move(first), std::move(spacing));
314 }
315
320 Space_ space,
321 Cells_ cells,
324 std::span<PinnedMatrix const> cellCovariances,
325 Allocator_ const & allocator = {}
326 )
327 requires(!Shared && Regular)
328 : PointGrid{Parts{}, std::move(space), std::move(cells), cellCovariances, allocator}
329 {
330 setGeometry(std::move(first), std::move(spacing));
331 }
332
334 [[nodiscard]] allocator_type
336 {
337 return allocator_type(m_cellCovariances.get_allocator());
338 }
339
341 [[nodiscard]] Space_ const &
342 space() const
343 {
344 return m_space;
345 }
346
348 [[nodiscard]] Cells_ const &
349 cells() const
350 {
351 return m_cells;
352 }
353
355 [[nodiscard]] PinnedSpace const &
357 {
358 return m_split.pinnedSpace();
359 }
360
362 [[nodiscard]] RestSpace const &
363 restSpace() const
364 {
365 return m_split.restSpace();
366 }
367
369 [[nodiscard]] Eigen::Index
370 size() const
371 {
372 return m_cells.cardinality();
373 }
374
376 [[nodiscard]] PinnedVector
377 center(Eigen::Index cell) const
378 {
379 EMRYS_FILTER_ASSERT(cell >= 0 && cell < size() && "the cell is out of range");
380 if constexpr (Regular)
381 {
382 auto const coordinates = m_cells.coordinates(cell);
383 PinnedVector result = m_first;
384 for (std::size_t i = 0; i < coordinates.size(); ++i)
385 {
386 Eigen::Index const row = Eigen::Index(i);
387 result(row) += Scalar(coordinates[i]) * m_spacing(row);
388 }
389 normalizeValues(pinnedSpace(), result);
390 return result;
391 }
392 else
393 {
394 return PinnedVector{centers().col(cell)};
395 }
396 }
397
400 centers() const
401 requires(!Regular)
402 {
403 return {m_centers.data(), pinnedRows().size, size()};
404 }
405
407 [[nodiscard]] PinnedVector const &
408 first() const
409 requires Regular
410 {
411 return m_first;
412 }
413
415 [[nodiscard]] PinnedVector const &
416 spacing() const
417 requires Regular
418 {
419 return m_spacing;
420 }
421
423 [[nodiscard]] bool
425 {
426 return !m_cellCovariances.empty();
427 }
428
430 [[nodiscard]] PinnedMatrix const &
431 cellCovariance(Eigen::Index cell) const
432 {
433 EMRYS_FILTER_ASSERT(hasCellCovariance() && "the cells are point masses");
434 EMRYS_FILTER_ASSERT(cell >= 0 && cell < size() && "the cell is out of range");
435 return m_cellCovariances[Shared ? 0 : std::size_t(cell)];
436 }
437
439 [[nodiscard]] BlockRows
441 {
442 return m_split.pinnedRows();
443 }
444
446 [[nodiscard]] auto const &
448 {
449 return m_split.restIndices();
450 }
451
453 [[nodiscard]] BlockRows
455 {
456 return m_split.pinnedDifferenceRows();
457 }
458
460 [[nodiscard]] auto const &
462 {
463 return m_split.restDifferenceIndices();
464 }
465
474 [[nodiscard]] PointGrid
475 subdivided(Eigen::Index factor) const
476 requires(Shared && Regular)
477 {
478 EMRYS_FILTER_ASSERT(factor >= 1 && "subdivide each cell into at least one");
479 Cells_ cells = [&]<std::size_t... I>(std::index_sequence<I...>) {
480 return Cells_{std::tuple_element_t<I, internal::DiscreteProductAxes<Cells_>>{
481 m_cells.template axis<I>().cardinality() * factor
482 }...};
483 }(std::make_index_sequence<Cells_::AxisCount>{});
484 PinnedVector spacing = m_spacing / Scalar(factor);
485 PinnedVector first = m_first - Scalar(0.5) * Scalar(factor - 1) * spacing;
486 auto cellCovariance = std::optional<PinnedMatrix>{};
487 if (hasCellCovariance())
488 {
489 cellCovariance = m_cellCovariances.front() / Scalar(factor * factor);
490 }
491 return PointGrid{
492 m_space,
493 std::move(cells),
494 std::move(first),
495 std::move(spacing),
496 std::move(cellCovariance),
498 };
499 }
500
501private:
502
504 struct Parts
505 {};
506
508 [[nodiscard]] static std::span<PinnedMatrix const>
509 listOf(std::optional<PinnedMatrix> const & covariance)
510 {
511 return covariance ? std::span<PinnedMatrix const>{&*covariance, 1} : std::span<PinnedMatrix const>{};
512 }
513
517 PointGrid(
518 Parts,
519 Space_ space,
520 Cells_ cells,
521 std::span<PinnedMatrix const> cellCovariances,
522 Allocator_ const & allocator
523 )
524 : m_space{std::move(space)}
525 , m_cells{std::move(cells)}
526 , m_split{m_space}
527 , m_cellCovariances(cellCovariances.begin(), cellCovariances.end(), MatrixAllocator(allocator))
528 , m_centers(ScalarAllocator(allocator))
529 {
530 EMRYS_FILTER_ASSERT(
531 (Shared || Eigen::Index(m_cellCovariances.size()) == size()) && "give one covariance per cell"
532 );
533 for (PinnedMatrix const & covariance : m_cellCovariances)
534 {
535 checkCovariance(covariance);
536 }
537 }
538
540 template <typename CentersDerived>
541 void
542 setCenters(Eigen::MatrixBase<CentersDerived> const & centers)
543 {
544 EMRYS_FILTER_ASSERT(centers.cols() == m_cells.cardinality() && "give one center per cell");
545 EMRYS_FILTER_ASSERT(centers.rows() == pinnedRows().size && "the centers do not fit the block");
546 m_centers.resize(std::size_t(centers.size()));
547 auto stored = SampleSetMap<PinnedSpace, Scalar_>{m_centers.data(), centers.rows(), centers.cols()};
548 stored = centers;
549 normalizeValues(pinnedSpace(), stored);
550 }
551
553 void
555 {
556 EMRYS_FILTER_ASSERT(
557 first.size() == pinnedRows().size && spacing.size() == pinnedRows().size
558 && pinnedRows().size == Eigen::Index(Cells_::AxisCount)
559 && "give the first point and spacing per axis, one axis per coordinate of the block"
560 );
561 m_first = std::move(first);
562 m_spacing = std::move(spacing);
563 }
564
566 void
567 checkCovariance(PinnedMatrix const & covariance) const
568 {
569 EMRYS_FILTER_ASSERT(
570 covariance.rows() == pinnedDifferenceRows().size && covariance.cols() == pinnedDifferenceRows().size
571 && "a cell covariance does not fit the block"
572 );
573 }
574
576 using MatrixAllocator = internal::ReBound<Allocator_, PinnedMatrix>;
577
579 using ScalarAllocator = internal::ReBound<Allocator_, Scalar_>;
580
581 Space_ m_space;
582 Cells_ m_cells;
583 internal::BlockSplit<Space_, Path_> m_split;
584 internal::Buffer<PinnedMatrix, Allocator_> m_cellCovariances;
585 internal::Buffer<Scalar_, Allocator_> m_centers;
586 PinnedVector m_first;
587 PinnedVector m_spacing;
588};
589
595template <typename P, Space S, typename Derived, typename Allocator = DefaultAllocator>
596[[nodiscard]] auto
598 S space,
599 Eigen::MatrixBase<Derived> const & centers,
600 std::optional<typename Moments<internal::PathTag<P>, typename Derived::Scalar>::MatrixType> cellCovariance = {},
601 Allocator const & allocator = {}
602)
603{
604 using Grid = PointGrid<S, P, PointCells<P>, SharedCovariance, typename Derived::Scalar, Allocator>;
605 return Grid{std::move(space), PointCells<P>{centers.cols()}, centers, std::move(cellCovariance), allocator};
606}
607
613template <typename P, Space S, typename Derived, typename Allocator = DefaultAllocator>
614[[nodiscard]] auto
616 S space,
617 Eigen::MatrixBase<Derived> const & centers,
618 std::span<typename Moments<internal::PathTag<P>, typename Derived::Scalar>::MatrixType const> cellCovariances,
619 Allocator const & allocator = {}
620)
621{
622 using Grid = PointGrid<S, P, PointCells<P>, PerPointCovariance, typename Derived::Scalar, Allocator>;
623 return Grid{std::move(space), PointCells<P>{centers.cols()}, centers, cellCovariances, allocator};
624}
625
630template <FixedSizeSpace S, typename P, typename Derived, typename Allocator = DefaultAllocator>
631[[nodiscard]] auto
633 Eigen::MatrixBase<Derived> const & centers,
634 std::optional<typename Moments<internal::PathTag<P>, typename Derived::Scalar>::MatrixType> cellCovariance = {},
635 Allocator const & allocator = {}
636)
637{
638 return pointGrid<P>(S{}, centers, std::move(cellCovariance), allocator);
639}
640
645template <FixedSizeSpace S, typename P, typename Derived, typename Allocator = DefaultAllocator>
646[[nodiscard]] auto
648 Eigen::MatrixBase<Derived> const & centers,
649 std::span<typename Moments<internal::PathTag<P>, typename Derived::Scalar>::MatrixType const> cellCovariances,
650 Allocator const & allocator = {}
651)
652{
653 return pointGrid<P>(S{}, centers, cellCovariances, allocator);
654}
655
656namespace internal
657{
658
660template <typename Cells, std::size_t D>
661[[nodiscard]] Cells
662regularCells(std::array<Eigen::Index, D> const & counts)
663{
664 return [&]<std::size_t... I>(std::index_sequence<I...>) {
665 return Cells{std::tuple_element_t<I, DiscreteProductAxes<Cells>>{counts[I]}...};
666 }(std::make_index_sequence<D>{});
667}
668
669} // namespace internal
670
679template <typename P, Space S, typename FirstDerived, typename SpacingDerived, typename Allocator = DefaultAllocator>
680[[nodiscard]] auto
682 S space,
683 Eigen::MatrixBase<FirstDerived> const & first,
684 Eigen::MatrixBase<SpacingDerived> const & spacing,
685 std::array<Eigen::Index, std::size_t(internal::PathTag<P>::FixedValueDimension)> const & counts,
686 std::optional<typename Moments<internal::PathTag<P>, typename FirstDerived::Scalar>::MatrixType> cellCovariance =
687 {},
688 Allocator const & allocator = {}
689)
690{
691 static_assert(internal::PathTag<P>::ValueDimensionStep == 0, "a regular grid needs a fixed-size block");
692 using Grid = PointGrid<S, P, GridCells<P>, SharedCovariance, typename FirstDerived::Scalar, Allocator>;
693 return Grid{
694 std::move(space),
695 internal::regularCells<typename Grid::CellsType>(counts),
696 typename Grid::PinnedVector{first},
697 typename Grid::PinnedVector{spacing},
698 std::move(cellCovariance),
699 allocator
700 };
701}
702
708template <typename P, Space S, typename FirstDerived, typename SpacingDerived, typename Allocator = DefaultAllocator>
709[[nodiscard]] auto
711 S space,
712 Eigen::MatrixBase<FirstDerived> const & first,
713 Eigen::MatrixBase<SpacingDerived> const & spacing,
714 std::array<Eigen::Index, std::size_t(internal::PathTag<P>::FixedValueDimension)> const & counts,
715 std::span<typename Moments<internal::PathTag<P>, typename FirstDerived::Scalar>::MatrixType const> cellCovariances,
716 Allocator const & allocator = {}
717)
718{
719 static_assert(internal::PathTag<P>::ValueDimensionStep == 0, "a regular grid needs a fixed-size block");
720 using Grid = PointGrid<S, P, GridCells<P>, PerPointCovariance, typename FirstDerived::Scalar, Allocator>;
721 return Grid{
722 std::move(space),
723 internal::regularCells<typename Grid::CellsType>(counts),
724 typename Grid::PinnedVector{first},
725 typename Grid::PinnedVector{spacing},
726 cellCovariances,
727 allocator
728 };
729}
730
736template <
738 typename P,
739 typename FirstDerived,
740 typename SpacingDerived,
741 typename Allocator = DefaultAllocator>
742[[nodiscard]] auto
744 Eigen::MatrixBase<FirstDerived> const & first,
745 Eigen::MatrixBase<SpacingDerived> const & spacing,
746 std::array<Eigen::Index, std::size_t(internal::PathTag<P>::FixedValueDimension)> const & counts,
747 std::optional<typename Moments<internal::PathTag<P>, typename FirstDerived::Scalar>::MatrixType> cellCovariance =
748 {},
749 Allocator const & allocator = {}
750)
751{
752 return regularGrid<P>(S{}, first, spacing, counts, std::move(cellCovariance), allocator);
753}
754
759template <
761 typename P,
762 typename FirstDerived,
763 typename SpacingDerived,
764 typename Allocator = DefaultAllocator>
765[[nodiscard]] auto
767 Eigen::MatrixBase<FirstDerived> const & first,
768 Eigen::MatrixBase<SpacingDerived> const & spacing,
769 std::array<Eigen::Index, std::size_t(internal::PathTag<P>::FixedValueDimension)> const & counts,
770 std::span<typename Moments<internal::PathTag<P>, typename FirstDerived::Scalar>::MatrixType const> cellCovariances,
771 Allocator const & allocator = {}
772)
773{
774 return regularGrid<P>(S{}, first, spacing, counts, cellCovariances, allocator);
775}
776
777namespace internal
778{
779
781template <typename Grid>
782class GridPoints
783{
784public:
785
787 using Scalar = typename Grid::Scalar;
788
790 using SpaceType = typename Grid::SpaceType;
791
793 using PathType = typename Grid::PathType;
794
796 using PinnedSpace = typename Grid::PinnedSpace;
797
799 using RestSpace = typename Grid::RestSpace;
800
802 static constexpr bool HasKernels = true;
803
805 GridPoints(Grid const & grid, std::span<Eigen::Index const> cells)
806 : m_grid{grid}
807 , m_cells{cells}
808 {}
809
811 [[nodiscard]] SpaceType const &
812 space() const
813 {
814 return m_grid.space();
815 }
816
818 [[nodiscard]] PinnedSpace const &
819 pinnedSpace() const
820 {
821 return m_grid.pinnedSpace();
822 }
823
825 [[nodiscard]] RestSpace const &
826 restSpace() const
827 {
828 return m_grid.restSpace();
829 }
830
832 [[nodiscard]] BlockRows
833 pinnedRows() const
834 {
835 return m_grid.pinnedRows();
836 }
837
839 [[nodiscard]] auto const &
840 restIndices() const
841 {
842 return m_grid.restIndices();
843 }
844
846 [[nodiscard]] BlockRows
847 pinnedDifferenceRows() const
848 {
849 return m_grid.pinnedDifferenceRows();
850 }
851
853 [[nodiscard]] auto const &
854 restDifferenceIndices() const
855 {
856 return m_grid.restDifferenceIndices();
857 }
858
860 [[nodiscard]] Eigen::Index
861 size() const
862 {
863 return Eigen::Index(m_cells.size());
864 }
865
867 [[nodiscard]] auto
868 center(Eigen::Index i) const
869 {
870 return m_grid.center(m_cells[std::size_t(i)]);
871 }
872
876 [[nodiscard]] typename Grid::PinnedMatrix const *
877 kernel(Eigen::Index i) const
878 {
879 return m_grid.hasCellCovariance() ? &m_grid.cellCovariance(m_cells[std::size_t(i)]) : nullptr;
880 }
881
882private:
883
884 Grid const & m_grid;
885 std::span<Eigen::Index const> m_cells;
886};
887
888} // namespace internal
889
931template <
932 typename Grid_,
933 typename Covariance_ = SharedCovariance,
936{
937 static_assert(internal::CovarianceForm<Covariance_>, "the covariance is SharedCovariance or PerPointCovariance");
938 static constexpr bool Shared = std::is_same_v<Covariance_, SharedCovariance>;
939
940 static_assert(
941 !Shared || std::is_same_v<typename Grid_::CellCovarianceType, SharedCovariance>,
942 "cells with covariances of their own give each cell its own innovation covariance, so the "
943 "filter needs PerPointCovariance"
944 );
945
947 static constexpr bool IsHybrid = internal::isGaussianHybrid<Params<Component_>>;
948
949 static_assert(
950 std::is_same_v<
953 || IsHybrid,
954 "a cell holds a Gaussian or a hybrid of Gaussians"
955 );
956 static_assert(
957 std::is_same_v<typename Params<Component_>::SpaceType, typename Grid_::RestSpace>
958 && std::is_same_v<typename Params<Component_>::Scalar, typename Grid_::Scalar>,
959 "a cell's distribution is over the grid's RestSpace, in the grid's scalar"
960 );
961 static_assert(
962 !(IsHybrid && Shared),
963 "mixing a cell's modes gives each cell covariances of its own, so a hybrid per cell needs PerPointCovariance"
964 );
965
966public:
967
969 using GridType = Grid_;
970
972 using Scalar = typename Grid_::Scalar;
973
975 using SpaceType = typename Grid_::SpaceType;
976
978 using CellsType = typename Grid_::CellsType;
979
981 using RestSpace = typename Grid_::RestSpace;
982
984 using PinnedSpace = typename Grid_::PinnedSpace;
985
987 using CovarianceType = Covariance_;
988
991
993 using WeightArrayType = Eigen::Array<Scalar, Eigen::Dynamic, 1>;
994
996 using LogWeightsType = Eigen::Map<WeightArrayType const>;
997
999 using allocator_type = typename Grid_::allocator_type;
1000
1003
1004 static constexpr bool IsParams = true;
1005
1009 GridGaussianParams(Grid_ grid, ConditionalType const & conditional, Covariance_ = {})
1010 : m_grid{std::move(grid)}
1011 , m_cells(IndexAllocator(m_grid.get_allocator()))
1012 , m_logWeights(ScalarAllocator(m_grid.get_allocator()))
1013 , m_conditionals{conditional, m_grid.size(), m_grid.get_allocator()}
1014 , m_kept(IndexAllocator(m_grid.get_allocator()))
1015 , m_weightScratch(ScalarAllocator(m_grid.get_allocator()))
1016 , m_children(ChildAllocator(m_grid.get_allocator()))
1017 {
1018 EMRYS_FILTER_ASSERT(
1019 conditional.space() == m_grid.restSpace() && "the Gaussian must be over the rest of the state"
1020 );
1021 m_cells.resize(std::size_t(m_grid.size()));
1022 for (std::size_t c = 0; c < m_cells.size(); ++c)
1023 {
1024 m_cells[c] = Eigen::Index(c);
1025 }
1026 m_logWeights.assign(std::size_t(m_grid.size()), -Eigen::numext::log(Scalar(m_grid.size())));
1027 m_kept.reserve(m_cells.size());
1028 m_weightScratch.reserve(m_cells.size());
1029 }
1030
1032 [[nodiscard]] allocator_type
1034 {
1035 return m_grid.get_allocator();
1036 }
1037
1039 [[nodiscard]] Grid_ const &
1040 grid() const
1041 {
1042 return m_grid;
1043 }
1044
1046 [[nodiscard]] Eigen::Index
1047 size() const
1048 {
1049 return Eigen::Index(m_cells.size());
1050 }
1051
1053 [[nodiscard]] Eigen::Index
1054 cell(Eigen::Index i) const
1055 {
1056 assertPosition(i);
1057 return m_cells[std::size_t(i)];
1058 }
1059
1061 [[nodiscard]] std::span<Eigen::Index const>
1062 cells() const
1063 {
1064 return {m_cells.data(), m_cells.size()};
1065 }
1066
1068 [[nodiscard]] std::optional<Eigen::Index>
1069 find(Eigen::Index cell) const
1070 {
1071 auto const found = std::lower_bound(m_cells.begin(), m_cells.end(), cell);
1072 if (found == m_cells.end() || *found != cell)
1073 {
1074 return std::nullopt;
1075 }
1076 return Eigen::Index(found - m_cells.begin());
1077 }
1078
1080 [[nodiscard]] auto
1081 center(Eigen::Index i) const
1082 {
1083 return m_grid.center(cell(i));
1084 }
1085
1087 [[nodiscard]] LogWeightsType
1089 {
1090 return {m_logWeights.data(), size()};
1091 }
1092
1094 [[nodiscard]] Scalar
1095 logWeight(Eigen::Index i) const
1096 {
1097 assertPosition(i);
1098 return m_logWeights[std::size_t(i)];
1099 }
1100
1102 [[nodiscard]] Eigen::Index
1104 {
1105 Eigen::Index best = 0;
1106 logWeights().maxCoeff(&best);
1107 return best;
1108 }
1109
1113 {
1114 using ArrayType = typename CategoricalParams<CellsType, Scalar>::ArrayType;
1115 ArrayType logP = ArrayType::Constant(m_grid.size(), -Eigen::NumTraits<Scalar>::infinity());
1116 for (Eigen::Index i = 0; i < size(); ++i)
1117 {
1118 logP(m_cells[std::size_t(i)]) = logWeight(i);
1119 }
1120 return CategoricalParams<CellsType, Scalar>{m_grid.cells(), logP};
1121 }
1122
1127 template <typename P>
1128 [[nodiscard]] auto
1129 marginal() const
1130 {
1131 auto const [stride, axis] = internal::locateAxisByPath<P>(m_grid.cells());
1132 using Axis = std::remove_cvref_t<decltype(*axis)>;
1133 using ArrayType = typename CategoricalParams<Axis, Scalar>::ArrayType;
1134 Eigen::Index const count = axis->cardinality();
1135 // One pass over the cells per value, so the totals take only the axis's own storage.
1136 auto logP = ArrayType{};
1137 logP.resize(count);
1138 for (Eigen::Index v = 0; v < count; ++v)
1139 {
1140 auto total = LogSumExp<Scalar>{};
1141 for (Eigen::Index i = 0; i < size(); ++i)
1142 {
1143 if ((m_cells[std::size_t(i)] / stride) % count == v)
1144 {
1145 total.add(logWeight(i));
1146 }
1147 }
1148 logP(v) = total.value();
1149 }
1150 return CategoricalParams<Axis, Scalar>{*axis, logP};
1151 }
1152
1161 [[nodiscard]] std::expected<void, WeightError>
1163 {
1164 EMRYS_FILTER_ASSERT(weights.space() == m_grid.cells() && "the weights are over different cells");
1165 m_stamp.touchShape();
1166 m_weightScratch.resize(m_logWeights.size());
1167 for (Eigen::Index i = 0; i < size(); ++i)
1168 {
1169 m_weightScratch[std::size_t(i)] = weights.logWeight(m_cells[std::size_t(i)]);
1170 }
1171 auto const total =
1172 internal::logTotalWeight<Scalar>(std::span<Scalar const>{m_weightScratch.data(), m_weightScratch.size()});
1173 if (!total)
1174 {
1175 return std::unexpected{total.error()};
1176 }
1177 m_logWeights.swap(m_weightScratch);
1178 normalizeAndRemoveDead();
1179 return {};
1180 }
1181
1185 [[nodiscard]] decltype(auto)
1186 conditional(Eigen::Index i) const
1187 {
1188 assertPosition(i);
1189 return m_conditionals.conditional(i);
1190 }
1191
1195 [[nodiscard]] auto
1196 modes() const
1197 requires IsHybrid
1198 {
1199 return internal::summedModes(m_conditionals, logWeights());
1200 }
1201
1203 [[nodiscard]] typename Moments<RestSpace, Scalar>::MatrixType const &
1205 requires Shared
1206 {
1207 return m_conditionals.sharedCovariance();
1208 }
1209
1216 [[nodiscard]] std::expected<void, NumericError>
1218 {
1219 return m_conditionals.factorize();
1220 }
1221
1226 [[nodiscard]] std::expected<DensityType, NumericError>
1227 toDensity() const &
1228 {
1229 if (auto result = factorize(); !result)
1230 {
1231 return std::unexpected{result.error()};
1232 }
1233 return DensityType{*this};
1234 }
1235
1237 void
1238 toDensity() const && = delete;
1239
1250 [[nodiscard]] Scalar
1251 pruneBelow(Scalar logThreshold)
1252 {
1253 return pruneWith(internal::PruneBelowRule<Scalar>{logThreshold});
1254 }
1255
1265 [[nodiscard]] Scalar
1266 pruneTail(Scalar logFraction)
1267 {
1268 return pruneWith(internal::PruneTailRule<Scalar>{logFraction});
1269 }
1270
1279 [[nodiscard]] Scalar
1280 pruneToSize(Eigen::Index maxSize)
1281 {
1282 return pruneWith(internal::PruneToSizeRule{maxSize});
1283 }
1284
1296 void
1297 subdivide(Eigen::Index factor)
1298 requires(Grid_::Regular && std::is_same_v<typename Grid_::CellCovarianceType, SharedCovariance>)
1299 {
1300 constexpr std::size_t D = CellsType::AxisCount;
1301 EMRYS_FILTER_ASSERT(factor >= 1 && "subdivide each cell into at least one");
1302 m_stamp.touchShape();
1303 Grid_ refined = m_grid.subdivided(factor);
1304 Eigen::Index offsets = 1;
1305 for (std::size_t d = 0; d < D; ++d)
1306 {
1307 offsets *= factor;
1308 }
1309 auto & children = m_children;
1310 children.clear();
1311 children.reserve(m_cells.size() * std::size_t(offsets));
1312 for (Eigen::Index i = 0; i < size(); ++i)
1313 {
1314 auto const parent = m_grid.cells().coordinates(m_cells[std::size_t(i)]);
1315 for (Eigen::Index o = 0; o < offsets; ++o)
1316 {
1317 auto child = std::array<Eigen::Index, D>{};
1318 Eigen::Index rest = o;
1319 for (std::size_t d = D; d-- > 0;)
1320 {
1321 child[d] = factor * parent[d] + rest % factor;
1322 rest /= factor;
1323 }
1324 children.emplace_back(refined.cells().value(child), i);
1325 }
1326 }
1327 std::sort(children.begin(), children.end());
1328 m_kept.clear();
1329 m_weightScratch.clear();
1330 Scalar const share = Eigen::numext::log(Scalar(offsets));
1331 for (std::size_t k = 0; k < children.size(); ++k)
1332 {
1333 m_kept.push_back(children[k].second);
1334 m_weightScratch.push_back(m_logWeights[std::size_t(children[k].second)] - share);
1335 }
1336 m_conditionals.select(m_kept);
1337 m_grid = std::move(refined);
1338 m_cells.resize(children.size());
1339 for (std::size_t k = 0; k < children.size(); ++k)
1340 {
1341 m_cells[k] = children[k].first;
1342 }
1343 m_logWeights.swap(m_weightScratch);
1344 }
1345
1346private:
1347
1349 template <typename, typename, typename, typename, typename>
1350 friend class RbPointMassFilter;
1351
1352 friend DensityType;
1353
1355 template <typename>
1356 friend class internal::ValuesCheck;
1357
1359 using ConditionalsType = internal::Conditionals<RestSpace, Covariance_, Scalar, allocator_type, ConditionalType>;
1360
1362 using IndexAllocator = internal::ReBound<allocator_type, Eigen::Index>;
1363
1365 using ScalarAllocator = internal::ReBound<allocator_type, Scalar>;
1366
1368 [[nodiscard]] internal::GridPoints<Grid_>
1369 points() const
1370 {
1371 return {m_grid, cells()};
1372 }
1373
1379 [[nodiscard]] GaussianParams<SpaceType, Scalar>
1380 collapseCells() const
1381 {
1382 if constexpr (IsHybrid)
1383 {
1384 return internal::collapseGivenHybrids(points(), m_conditionals, logWeights(), get_allocator());
1385 }
1386 else
1387 {
1388 return internal::collapseGivenPoints(points(), m_conditionals, logWeights());
1389 }
1390 }
1391
1393 void
1394 assertPosition([[maybe_unused]] Eigen::Index i) const
1395 {
1396 EMRYS_FILTER_ASSERT(i >= 0 && i < size() && "the position is out of range");
1397 }
1398
1406 template <ExecutionPolicy P, typename Derived>
1407 [[nodiscard]] std::pair<Scalar, bool>
1408 reweight(P && policy, Eigen::ArrayBase<Derived> const & logLikelihoods, ConditionalsType & posterior)
1409 {
1410 return reweightThen(std::forward<P>(policy), logLikelihoods, [&] {
1411 m_conditionals.swap(posterior);
1412 });
1413 }
1414
1421 template <ExecutionPolicy P, typename Derived>
1422 [[nodiscard]] std::pair<Scalar, bool>
1423 reweight(P && policy, Eigen::ArrayBase<Derived> const & logLikelihoods)
1424 {
1425 return reweightThen(std::forward<P>(policy), logLikelihoods, [] {});
1426 }
1427
1431 template <ExecutionPolicy P, typename Derived, typename Place>
1432 [[nodiscard]] std::pair<Scalar, bool>
1433 reweightThen(P && policy, Eigen::ArrayBase<Derived> const & logLikelihoods, Place const & place)
1434 {
1435 EMRYS_FILTER_ASSERT(logLikelihoods.size() == size() && "give one log-likelihood per live cell");
1436 m_weightScratch.resize(m_logWeights.size());
1437 internal::forEachIndex(policy, size(), [&](Eigen::Index i) {
1438 m_weightScratch[std::size_t(i)] = m_logWeights[std::size_t(i)] + logLikelihoods(i);
1439 });
1440 auto const evidence = internal::logTotalWeight<Scalar>(
1441 policy,
1442 std::span<Scalar const>{m_weightScratch.data(), m_weightScratch.size()}
1443 );
1444 if (!evidence)
1445 {
1446 return {
1448 std::forward<P>(policy),
1449 size(),
1450 [&](Eigen::Index i) {
1451 return m_weightScratch[std::size_t(i)];
1452 }
1453 ),
1454 false
1455 };
1456 }
1457 m_stamp.touchShape();
1458 m_logWeights.swap(m_weightScratch);
1459 place();
1460 normalizeAndRemoveDead();
1461 return {*evidence, true};
1462 }
1463
1470 template <typename Rule>
1471 [[nodiscard]] Scalar
1472 pruneWith(Rule const & rule)
1473 {
1474 m_stamp.touchShape();
1475 auto cut = rule(
1476 size(),
1477 [&](Eigen::Index i) {
1478 return m_logWeights[std::size_t(i)];
1479 },
1480 Scalar(0),
1481 m_weightScratch
1482 );
1483 auto removed = LogSumExp<Scalar>{};
1484 for (Scalar & logWeight : m_logWeights)
1485 {
1486 if (cut.removes(logWeight))
1487 {
1488 removed.add(logWeight);
1489 logWeight = -Eigen::NumTraits<Scalar>::infinity();
1490 }
1491 }
1492 normalizeAndRemoveDead();
1493 return removed.value();
1494 }
1495
1500 void
1501 normalizeAndRemoveDead()
1502 {
1503 auto const total = internal::logTotalWeight<Scalar>(m_logWeights);
1504 EMRYS_FILTER_ASSERT(total && "some live cell must keep a nonzero weight");
1505 for (Scalar & logWeight : m_logWeights)
1506 {
1507 logWeight -= *total;
1508 }
1509 m_kept.clear();
1510 for (Eigen::Index i = 0; i < size(); ++i)
1511 {
1512 if (m_logWeights[std::size_t(i)] > -Eigen::NumTraits<Scalar>::infinity())
1513 {
1514 m_kept.push_back(i);
1515 }
1516 }
1517 if (m_kept.size() == m_cells.size())
1518 {
1519 return;
1520 }
1521 for (std::size_t k = 0; k < m_kept.size(); ++k)
1522 {
1523 m_cells[k] = m_cells[std::size_t(m_kept[k])];
1524 m_logWeights[k] = m_logWeights[std::size_t(m_kept[k])];
1525 }
1526 m_conditionals.keep(m_kept);
1527 m_cells.resize(m_kept.size());
1528 m_logWeights.resize(m_kept.size());
1529 }
1530
1531 Grid_ m_grid;
1532 internal::Buffer<Eigen::Index, allocator_type> m_cells;
1533 internal::Buffer<Scalar, allocator_type> m_logWeights;
1534 ConditionalsType m_conditionals;
1535
1536 // Scratch, reused: the cells kept, and the reweighted log-probabilities.
1537 internal::Buffer<Eigen::Index, allocator_type> m_kept;
1538
1539 internal::Buffer<Scalar, allocator_type> m_weightScratch;
1540
1542 using Child = std::pair<Eigen::Index, Eigen::Index>;
1543
1545 using ChildAllocator = internal::ReBound<allocator_type, Child>;
1546
1547 internal::Buffer<Child, allocator_type> m_children;
1548
1549 internal::Stamp m_stamp;
1550};
1551
1569template <typename Grid_, typename Covariance_, typename Component_>
1570class GridGaussian
1571{
1572public:
1573
1575 using GridType = Grid_;
1576 using Scalar = typename Grid_::Scalar;
1577 using SpaceType = typename Grid_::SpaceType;
1581
1582 static constexpr bool IsParams = false;
1583
1585 [[nodiscard]] Grid_ const &
1586 grid() const
1587 {
1588 return source().grid();
1589 }
1590
1592 [[nodiscard]] Eigen::Index
1593 size() const
1594 {
1595 return source().size();
1596 }
1597
1599 [[nodiscard]] decltype(auto)
1600 conditional(Eigen::Index i) const
1601 {
1602 return source().conditional(i);
1603 }
1604
1611 {
1612 return source().collapseCells();
1613 }
1614
1616 [[nodiscard]] MomentsType
1617 moments() const
1618 {
1619 return collapsed().moments();
1620 }
1621
1622private:
1623
1624 friend ParamsType;
1625
1629 explicit GridGaussian(ParamsType const & source)
1630 : m_check{source}
1631 {}
1632
1634 [[nodiscard]] ParamsType const &
1635 source() const
1636 {
1637 return m_check.get();
1638 }
1639
1640 internal::ValuesCheck<ParamsType> m_check;
1641};
1642
1644// A hybrid conditional names the component, and its cells have covariances of their own.
1645template <typename Grid_, typename Component_, typename ModeSpace_, typename Allocator_>
1649
1650} // namespace Emrys
1651
1652#ifndef EMRYS_FILTER_NO_IO
1653
1654namespace Emrys
1655{
1656
1657namespace internal
1658{
1659
1663template <typename Grid_, typename Covariance_, typename Component_>
1664void
1665describe(std::ostream & stream, GridGaussianParams<Grid_, Covariance_, Component_> const & state, Indent indent)
1666{
1667 stream << indent << "Rao-Blackwellized grid of ";
1668 printCount(stream, state.size(), "cell");
1669 // Every step leaves the cells' weights normalized, so only a cell's distribution can fail.
1670 auto const density = state.toDensity();
1671 if (!density)
1672 {
1673 stream << '\n';
1674 describe(stream, density.error(), indent.deeper());
1675 return;
1676 }
1677 auto const collapsed = density->collapsed();
1678 printDimension(stream, collapsed.valueDimension(), collapsed.differenceDimension());
1679 printMoments(stream, indent.deeper(), collapsed.moments());
1680}
1681
1682} // namespace internal
1683
1684} // namespace Emrys
1685
1686#endif // EMRYS_FILTER_NO_IO
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
The distribution over a discrete space (decisions.md [discrete-spaces], [params-and-density]): Catego...
What the Rao-Blackwellized states share (decisions.md [rao-blackwellized-core], [rb-particle-filter])...
Discrete spaces (decisions.md [discrete-spaces]): the DiscreteSpace concept; Finite,...
Execution policies (decisions.md [execution-policies]): execution::sequential, the ExecutionPolicy co...
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]):...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
Moments: the mean and covariance that a Gaussian carries and that a mixture or a sample set is moment...
Params and Density: the traits that pair a distribution's parameters with its density,...
Printing: operator<< and std::formatter for every distribution, every filter (which prints its name a...
SampleSet: a matrix whose columns are samples in a space, which the samplers return and the unscented...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
What parameters and their views share (decisions.md [view-stamp], [params-and-density]): Stamp,...
Weighted statistics over points, all in internal, which the containers of weighted elements (Gaussian...
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...
The parameters of a probability distribution over a discrete space: one weight per value.
Definition Categorical.h:257
Space_ const & space() const
Definition Categorical.h:330
Scalar logWeight(Eigen::Index value) const
Definition Categorical.h:351
Eigen::Array< Scalar_, CardinalityAtCompileTime, 1, Eigen::ColMajor, MaxCardinalityAtCompileTime, 1 > ArrayType
One entry per value, in flat-index order.
Definition Categorical.h:268
A Gaussian distribution: a mean and covariance in a space.
Definition Gaussian.h:259
The density of a Gaussian whose covariance has been factorized: a read-only view.
Definition Gaussian.h:1011
The parameters of a Rao-Blackwellized point-mass filter's state: the cells of a grid still alive,...
Definition GridGaussian.h:936
Params< Component_ > ConditionalType
A cell's distribution over the rest: a Gaussian, or a hybrid of Gaussians.
Definition GridGaussian.h:990
GridGaussian< Grid_, Covariance_, Component_ > DensityType
The view toDensity() returns.
Definition GridGaussian.h:1002
void toDensity() const &&=delete
A density of a temporary would outlive it.
static constexpr bool IsParams
Definition GridGaussian.h:1004
Eigen::Index mostProbable() const
Definition GridGaussian.h:1103
Scalar pruneTail(Scalar logFraction)
Removes the least probable live cells, as many as can be while their combined probability stays below...
Definition GridGaussian.h:1266
auto modes() const
Definition GridGaussian.h:1196
Scalar pruneBelow(Scalar logThreshold)
Definition GridGaussian.h:1251
friend class RbPointMassFilter
Definition GridGaussian.h:1350
auto center(Eigen::Index i) const
Definition GridGaussian.h:1081
LogWeightsType logWeights() const
Definition GridGaussian.h:1088
std::expected< void, WeightError > setWeights(CategoricalParams< CellsType, Scalar > const &weights)
Replaces the live cells' weights with those of weights, normalized over the live cells,...
Definition GridGaussian.h:1162
typename Grid_::RestSpace RestSpace
The rest's space, in order.
Definition GridGaussian.h:981
Eigen::Index cell(Eigen::Index i) const
Definition GridGaussian.h:1054
typename Grid_::PinnedSpace PinnedSpace
The fixed block's space.
Definition GridGaussian.h:984
GridGaussianParams(Grid_ grid, ConditionalType const &conditional, Covariance_={})
Every cell of grid alive and equally probable, each with conditional as its Gaussian over the rest of...
Definition GridGaussian.h:1009
void subdivide(Eigen::Index factor)
Splits every live cell into factor cells along each axis (see PointGrid::subdivided()),...
Definition GridGaussian.h:1297
Scalar logWeight(Eigen::Index i) const
Definition GridGaussian.h:1095
std::expected< void, NumericError > factorize() const
Factorizes each live cell's Gaussian, the one they share once, or checks each cell's hybrid,...
Definition GridGaussian.h:1217
Eigen::Array< Scalar, Eigen::Dynamic, 1 > WeightArrayType
One entry per live cell.
Definition GridGaussian.h:993
Eigen::Index size() const
Definition GridGaussian.h:1047
typename Grid_::Scalar Scalar
The scalar type.
Definition GridGaussian.h:972
Covariance_ CovarianceType
SharedCovariance or PerPointCovariance.
Definition GridGaussian.h:987
Scalar pruneToSize(Eigen::Index maxSize)
Removes the least probable live cells until at most maxSize, at least one, remain,...
Definition GridGaussian.h:1280
Grid_ GridType
The grid.
Definition GridGaussian.h:969
std::span< Eigen::Index const > cells() const
Definition GridGaussian.h:1062
Eigen::Map< WeightArrayType const > LogWeightsType
The live cells' log-probabilities.
Definition GridGaussian.h:996
Moments< RestSpace, Scalar >::MatrixType const & sharedCovariance() const
Definition GridGaussian.h:1204
Grid_ const & grid() const
Definition GridGaussian.h:1040
std::optional< Eigen::Index > find(Eigen::Index cell) const
Definition GridGaussian.h:1069
decltype(auto) conditional(Eigen::Index i) const
Definition GridGaussian.h:1186
allocator_type get_allocator() const
Definition GridGaussian.h:1033
typename Grid_::SpaceType SpaceType
The whole state space.
Definition GridGaussian.h:975
std::expected< DensityType, NumericError > toDensity() const &
Checks the cells (factorize()) and views the state.
Definition GridGaussian.h:1227
typename Grid_::allocator_type allocator_type
The grid's allocator.
Definition GridGaussian.h:999
CategoricalParams< CellsType, Scalar > toCategorical() const
Definition GridGaussian.h:1112
typename Grid_::CellsType CellsType
The discrete space of cells.
Definition GridGaussian.h:978
auto marginal() const
Definition GridGaussian.h:1129
The density of a Rao-Blackwellized point-mass filter's state, a checked view of its GridGaussianParam...
Definition GridGaussian.h:1571
typename ParamsType::ConditionalType ConditionalType
a cell's distribution over the rest
Definition GridGaussian.h:1578
static constexpr bool IsParams
a view: it checks its parameters
Definition GridGaussian.h:1582
Eigen::Index size() const
Definition GridGaussian.h:1593
MomentsType moments() const
Definition GridGaussian.h:1617
Moments< SpaceType, Scalar > MomentsType
a mean and covariance of the whole state
Definition GridGaussian.h:1579
typename Grid_::Scalar Scalar
the scalar type
Definition GridGaussian.h:1576
decltype(auto) conditional(Eigen::Index i) const
Definition GridGaussian.h:1600
typename Grid_::SpaceType SpaceType
the whole state space
Definition GridGaussian.h:1577
Grid_ const & grid() const
Definition GridGaussian.h:1586
GaussianParams< SpaceType, Scalar > collapsed() const
Definition GridGaussian.h:1610
Grid_ GridType
the grid
Definition GridGaussian.h:1575
typename ParamsType::allocator_type allocator_type
the parameters' allocator
Definition GridGaussian.h:1580
GridGaussianParams< Grid_, Covariance_, Component_ > ParamsType
the parameters it reads
Definition GridGaussian.h:1574
The parameters of a hybrid state: a discrete mode, and a component conditioned on each mode.
Definition Hybrid.h:86
The density of a hybrid state, a checked view of its HybridParams (decisions.md [params-and-density],...
Definition Hybrid.h:528
Streaming log-sum-exp: accumulates without overflow.
Definition Weights.h:46
Scalar value() const
Definition Weights.h:133
First and second moments (mean and covariance) of a distribution.
Definition Moments.h:55
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
Fixed points for the block named by the path Path_ of a state in Space_, one per value of the discret...
Definition GridGaussian.h:209
Path_ PathType
The path naming the fixed block.
Definition GridGaussian.h:229
typename internal::BlockSplit< Space_, Path_ >::PinnedSpace PinnedSpace
The space of the fixed block.
Definition GridGaussian.h:238
PinnedMatrix const & cellCovariance(Eigen::Index cell) const
Definition GridGaussian.h:431
PinnedSpace const & pinnedSpace() const
Definition GridGaussian.h:356
PointGrid(Space_ space, Cells_ cells, Eigen::MatrixBase< CentersDerived > const &centers, std::span< PinnedMatrix const > cellCovariances, Allocator_ const &allocator={})
Points in space with centers, one column per value of cells in flat-index order, and cellCovariances,...
Definition GridGaussian.h:284
typename Moments< PinnedSpace, Scalar_ >::MatrixType PinnedMatrix
A covariance over the block.
Definition GridGaussian.h:250
Eigen::Index size() const
Definition GridGaussian.h:370
auto const & restDifferenceIndices() const
Definition GridGaussian.h:461
Cells_ CellsType
The discrete space of cells.
Definition GridGaussian.h:226
PointGrid(Space_ space, Cells_ cells, PinnedVector first, PinnedVector spacing, std::span< PinnedMatrix const > cellCovariances, Allocator_ const &allocator={})
A regular grid as above, with cellCovariances, each cell's covariance about its center in flat-index ...
Definition GridGaussian.h:319
PinnedVector const & first() const
Definition GridGaussian.h:408
BlockRows pinnedDifferenceRows() const
Definition GridGaussian.h:454
bool hasCellCovariance() const
Definition GridGaussian.h:424
SampleSet< PinnedSpace, Scalar_ > CentersType
A plain matrix of centers, one per column, laid out as centers() is.
Definition GridGaussian.h:244
Allocator_ allocator_type
The allocator, re-bound per buffer.
Definition GridGaussian.h:235
Scalar_ Scalar
The scalar type.
Definition GridGaussian.h:220
Space_ const & space() const
Definition GridGaussian.h:342
PinnedVector center(Eigen::Index cell) const
Definition GridGaussian.h:377
PointGrid(Space_ space, Cells_ cells, Eigen::MatrixBase< CentersDerived > const &centers, std::optional< PinnedMatrix > cellCovariance={}, Allocator_ const &allocator={})
Points in space with centers, one column per value of cells in flat-index order, and cellCovariance,...
Definition GridGaussian.h:266
PointGrid subdivided(Eigen::Index factor) const
Definition GridGaussian.h:475
PinnedVector const & spacing() const
Definition GridGaussian.h:416
Cells_ const & cells() const
Definition GridGaussian.h:349
PointGrid(Space_ space, Cells_ cells, PinnedVector first, PinnedVector spacing, std::optional< PinnedMatrix > cellCovariance={}, Allocator_ const &allocator={})
A regular grid in space over cells, whose cell with coordinates (see DiscreteProduct::coordinates())...
Definition GridGaussian.h:302
typename internal::BlockSplit< Space_, Path_ >::RestSpace RestSpace
The space of the rest of the state, in order.
Definition GridGaussian.h:241
RestSpace const & restSpace() const
Definition GridGaussian.h:363
allocator_type get_allocator() const
Definition GridGaussian.h:335
ConstSampleSetMap< PinnedSpace, Scalar_ > centers() const
Definition GridGaussian.h:400
auto const & restIndices() const
Definition GridGaussian.h:447
static constexpr bool Regular
Whether the grid is regular: its cells are GridCells, and its centers are computed.
Definition GridGaussian.h:253
BlockRows pinnedRows() const
Definition GridGaussian.h:440
typename Moments< PinnedSpace, Scalar_ >::VectorType PinnedVector
A value of the block, such as a center.
Definition GridGaussian.h:247
CellCovariance_ CellCovarianceType
SharedCovariance or PerPointCovariance.
Definition GridGaussian.h:232
Space_ SpaceType
The whole state space.
Definition GridGaussian.h:223
Product(Space_ space, Placed... placed)
The product of the factors placed, made by on() or onEach(), in space.
Definition Product.h:821
A Rao-Blackwellized point-mass filter: fixed points for one block of the state, such as a coarse posi...
Definition RbPointMassFilter.h:241
A type usable as a discrete space: a finite set of values.
Definition Discrete.h:72
A space whose instance holds nothing, so that S{} is the only one there is: a space of fixed size,...
Definition Space.h:217
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
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
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
Eigen::Map< SampleSet< Space, Scalar > > SampleSetMap
A writable view of samples in Space, one per column, over memory it does not own, laid out as a Sampl...
Definition SampleSet.h:50
auto regularGrid(S space, Eigen::MatrixBase< FirstDerived > const &first, Eigen::MatrixBase< SpacingDerived > const &spacing, std::array< Eigen::Index, std::size_t(internal::PathTag< P >::FixedValueDimension)> const &counts, std::optional< typename Moments< internal::PathTag< P >, typename FirstDerived::Scalar >::MatrixType > cellCovariance={}, Allocator const &allocator={})
Definition GridGaussian.h:681
Eigen::Map< SampleSet< Space, Scalar > const > ConstSampleSetMap
A read-only view of samples in Space, one per column, over memory it does not own,...
Definition SampleSet.h:60
auto pointGrid(S space, Eigen::MatrixBase< Derived > const &centers, std::optional< typename Moments< internal::PathTag< P >, typename Derived::Scalar >::MatrixType > cellCovariance={}, Allocator const &allocator={})
Definition GridGaussian.h:597
typename ParamsOf< D >::type Params
The parameters of the density D: GaussianParams for a Gaussian, and D itself for a distribution whose...
Definition Params.h:42
Eigen::Array< typename Derived::Scalar, Eigen::Dynamic, 1 > logLikelihoods(M const &measurement, Space const &space, Eigen::MatrixBase< Derived > const &states)
Definition Likelihood.h:408
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
Rows of a contiguous block of a space.
Definition TagPath.h:825
Eigen::Index size
number of rows
Definition TagPath.h:827
The axis of a regular grid of points (see regularGrid()) along coordinate I of the block Block: a run...
Definition GridGaussian.h:68
Finite()=default
A GridAxis is made like a Finite, with its number of cells.
The cells of a regular grid over the block named by the path Path: the DiscreteProduct of its GridAxi...
Definition GridGaussian.h:135
decltype(internal::gridProduct(static_cast< internal::GridAxes< Path > * >(nullptr))) Product
The DiscreteProduct of the axes.
Definition GridGaussian.h:142
A covariance per point.
Definition Conditionals.h:59
The cells of a grid of given points (see pointGrid()) for the block named by the path Path: one value...
Definition GridGaussian.h:153
Finite()=default
PointCells are made like a Finite, with their number of points.
One covariance for every point.
Definition Conditionals.h:49