EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
ResolvedReads.h
Go to the documentation of this file.
1#pragma once
2
10
11#include <array>
12#include <cstddef>
13#include <tuple>
14#include <type_traits>
15#include <utility>
16
17#include <unsupported/Eigen/AutoDiff>
18
27
28namespace Emrys
29{
30
31namespace internal
32{
33
35template <typename Space, typename Reads>
36class ReadBlocks;
37
41template <typename Space, typename... Paths>
42class ReadBlocks<Space, TagPaths<Paths...>>
43{
44 static_assert(sizeof...(Paths) > 0, "a model reads at least one block of the state");
45
47 using First = std::tuple_element_t<0, std::tuple<Paths...>>;
48
49public:
50
51 static constexpr std::size_t Count = sizeof...(Paths);
52
54 using JointSpace = std::conditional_t<Count == 1, PathTag<First>, Composite<PathTag<Paths>...>>;
55
56 static constexpr int Size = valueDimensionAtCompileTime<JointSpace>;
57 static constexpr int MaxSize = maxValueDimensionAtCompileTime<JointSpace>;
58 static constexpr int DifferenceSize =
60 static constexpr int DifferenceMaxSize =
62 using Indices = IndexVector<Size, MaxSize>;
63 using DifferenceIndices = IndexVector<DifferenceSize, DifferenceMaxSize>;
64 using Selection = Coordinates<Indices, DifferenceIndices>;
65
67 explicit ReadBlocks(Space const & space)
68 : m_rows{blockRows<Paths>(space)...}
69 , m_differenceRows{differenceBlockRows<Paths>(space)...}
70 , m_space{makeSpace(space)}
71 {
72 Eigen::Index offset = 0;
73 Eigen::Index differenceOffset = 0;
74 for (std::size_t i = 0; i < Count; ++i)
75 {
76 m_jointStarts[i] = offset;
77 m_jointDifferenceStarts[i] = differenceOffset;
78 offset += m_rows[i].size;
79 differenceOffset += m_differenceRows[i].size;
80 }
81 m_indices = concatenate<Indices>(m_rows);
82 m_differenceIndices = concatenate<DifferenceIndices>(m_differenceRows);
83 EMRYS_FILTER_ASSERT(distinctIndices(m_indices) && "a model must not read a coordinate twice");
84 }
85
87 [[nodiscard]] JointSpace const &
88 space() const
89 {
90 return m_space;
91 }
92
94 [[nodiscard]] Indices const &
95 indices() const
96 {
97 return m_indices;
98 }
99
101 [[nodiscard]] DifferenceIndices const &
102 differenceIndices() const
103 {
104 return m_differenceIndices;
105 }
106
108 [[nodiscard]] Selection
109 selection() const
110 {
111 return {m_indices, m_differenceIndices};
112 }
113
115 [[nodiscard]] BlockRows const &
116 rows(std::size_t k) const
117 {
118 return m_rows[k];
119 }
120
122 [[nodiscard]] BlockRows const &
123 differenceRows(std::size_t k) const
124 {
125 return m_differenceRows[k];
126 }
127
129 [[nodiscard]] Eigen::Index
130 jointStart(std::size_t k) const
131 {
132 return m_jointStarts[k];
133 }
134
136 [[nodiscard]] Eigen::Index
137 jointDifferenceStart(std::size_t k) const
138 {
139 return m_jointDifferenceStarts[k];
140 }
141
142private:
143
145 [[nodiscard]] static JointSpace
146 makeSpace(Space const & space)
147 {
148 if constexpr (Count == 1)
149 {
150 return pathBlock<First>(space);
151 }
152 else
153 {
154 return JointSpace{pathBlock<Paths>(space)...};
155 }
156 }
157
159 template <typename Result>
160 [[nodiscard]] static Result
161 concatenate(std::array<BlockRows, Count> const & blocks)
162 {
163 Eigen::Index size = 0;
164 for (BlockRows const & rows : blocks)
165 {
166 size += rows.size;
167 }
168 auto result = Result{};
169 result.resize(size);
170 Eigen::Index k = 0;
171 for (BlockRows const & rows : blocks)
172 {
173 for (Eigen::Index j = 0; j < rows.size; ++j)
174 {
175 result(k++) = rows.start + j;
176 }
177 }
178 return result;
179 }
180
181 std::array<BlockRows, Count> m_rows;
182 std::array<BlockRows, Count> m_differenceRows;
183 std::array<Eigen::Index, Count> m_jointStarts{};
184 std::array<Eigen::Index, Count> m_jointDifferenceStarts{};
185 Indices m_indices;
186 DifferenceIndices m_differenceIndices;
187 JointSpace m_space;
188};
189
193template <typename Space>
194class ReadBlocks<Space, TagPaths<WholeSpace>>
195{
196public:
197
198 static constexpr std::size_t Count = 1;
199
201 using JointSpace = Space;
202
203 static constexpr int Size = valueDimensionAtCompileTime<Space>;
204 static constexpr int MaxSize = maxValueDimensionAtCompileTime<Space>;
205 static constexpr int DifferenceSize =
207 static constexpr int DifferenceMaxSize = maxValueDimensionAtCompileTime<DifferenceSpace<Space>>;
208 using Indices = IndexVector<Size, MaxSize>;
209 using DifferenceIndices = IndexVector<DifferenceSize, DifferenceMaxSize>;
210 using Selection = Coordinates<Indices, DifferenceIndices>;
211
213 explicit ReadBlocks(Space const & space)
214 : m_rows{0, valueDimension(space)}
215 , m_differenceRows{0, differenceDimension(space)}
216 , m_indices{Indices::LinSpaced(m_rows.size, 0, m_rows.size - 1)}
217 , m_differenceIndices{DifferenceIndices::LinSpaced(m_differenceRows.size, 0, m_differenceRows.size - 1)}
218 , m_space{space}
219 {}
220
222 [[nodiscard]] JointSpace const &
223 space() const
224 {
225 return m_space;
226 }
227
229 [[nodiscard]] Indices const &
230 indices() const
231 {
232 return m_indices;
233 }
234
236 [[nodiscard]] DifferenceIndices const &
237 differenceIndices() const
238 {
239 return m_differenceIndices;
240 }
241
243 [[nodiscard]] Selection
244 selection() const
245 {
246 return {m_indices, m_differenceIndices};
247 }
248
250 [[nodiscard]] BlockRows const &
251 rows(std::size_t) const
252 {
253 return m_rows;
254 }
255
257 [[nodiscard]] BlockRows const &
258 differenceRows(std::size_t) const
259 {
260 return m_differenceRows;
261 }
262
264 [[nodiscard]] Eigen::Index
265 jointStart(std::size_t) const
266 {
267 return 0;
268 }
269
271 [[nodiscard]] Eigen::Index
272 jointDifferenceStart(std::size_t) const
273 {
274 return 0;
275 }
276
277private:
278
279 BlockRows m_rows;
280 BlockRows m_differenceRows;
281 Indices m_indices;
282 DifferenceIndices m_differenceIndices;
283 Space m_space;
284};
285
290template <typename Space>
291struct ReadsWhole
292{
293 static constexpr std::size_t Count = 1;
294
296 using InputSpace = Space;
297
299 template <std::size_t I>
300 using Item = ReadItem<WholeSpace, Space>;
301};
302
304template <typename Model>
305inline constexpr bool readsWholeState = !Model::template has<PolicyKind::reads>;
306
313template <typename Model>
314struct WholeStateRefusal
315{
316 static_assert(
317 !readsWholeState<Model>,
318 "a model without reads() and writes() reads and writes the whole state, so it is not placed by on() or "
319 "onEach() or composed by compose(): give it reads() and writes() to name its blocks"
320 );
321
322 static constexpr bool value = true;
323};
324
328template <typename Model>
329inline constexpr bool wholeStateRefused = WholeStateRefusal<Model>::value;
330
332template <typename Model, typename Space>
333using ReadsIn =
334 std::conditional_t<readsWholeState<Model>, ReadsWhole<Space>, typename Model::template Policy<PolicyKind::reads>>;
335
337template <typename Tuple>
338struct TagPathsOfTuple;
339
341template <typename... Paths>
342struct TagPathsOfTuple<std::tuple<Paths...>>
343{
344 using type = TagPaths<Paths...>;
345};
346
348
350template <typename Policy, typename Name>
351inline constexpr bool affineNames = false;
352
354template <typename... Names, typename Name>
355inline constexpr bool affineNames<AffineIn<Names...>, Name> = (std::is_same_v<Names, Name> || ...);
356
358
363template <typename Name, typename Block>
364[[nodiscard]] Name
365nameOf(Block const & block)
366{
367 if constexpr (std::is_same_v<Name, Block>)
368 {
369 return block;
370 }
371 else if constexpr (FixedSizeSpace<Name>)
372 {
373 return Name{};
374 }
375 else
376 {
377 auto name = Name{};
378 fitValueDimension(name, valueDimension(block));
379 return name;
380 }
381}
382
386template <typename T>
387struct PlainScalarOf
388{
389 using type = T;
390};
391
393template <typename Derivatives>
394struct PlainScalarOf<Eigen::AutoDiffScalar<Derivatives>>
395{
396 using type = Eigen::AutoDiffScalar<typename std::remove_cvref_t<Derivatives>::PlainObject>;
397};
398
400
406template <typename R>
407[[nodiscard]] auto
408vectorReturned(R && returned)
409{
410 using Plain = std::remove_cvref_t<R>;
411 if constexpr (!MatrixExpression<Plain> && !isWithJacobian<Plain>)
412 {
413 static_assert(
414 std::is_same_v<Plain, typename PlainScalarOf<Plain>::type>,
415 "a function that returns a scalar returns it as its input's scalar type, T{...}: an expression of "
416 "automatic-differentiation scalars refers to temporaries of the function; or return a vector of one "
417 "coordinate"
418 );
419 return Eigen::Matrix<Plain, 1, 1>{std::forward<R>(returned)};
420 }
421 else
422 {
423 return std::forward<R>(returned);
424 }
425}
426
431template <typename Model>
432[[nodiscard]] consteval bool
433affineInEverything()
434{
435 if constexpr (readsWholeState<Model>)
436 {
437 return requires { requires Model::FunctionType::IsAffine; };
438 }
439 else
440 {
441 using Affine = typename Model::template Policy<PolicyKind::affineIn>;
442 return []<typename... Items>(Reads<Items...> const *) {
443 return (affineNames<Affine, typename Items::NameType> && ... && true);
444 }(static_cast<typename Model::template Policy<PolicyKind::reads> const *>(nullptr));
445 }
446}
447
455template <typename Model, typename Arguments, typename Space>
456class ResolvedReads
457{
458public:
459
460 using ModelType = Model;
461 using SpaceType = Space;
462
464 static constexpr bool Whole = readsWholeState<Model>;
465
467 using ReadsPolicy = ReadsIn<Model, Space>;
468
469 static constexpr std::size_t ItemCount = ReadsPolicy::Count;
470
472 template <std::size_t I>
473 using Item = typename ReadsPolicy::template Item<I>;
474
476 using In = typename ReadsPolicy::InputSpace;
477
479 using ArgumentsType = Arguments;
480
481 static constexpr std::size_t ArgumentCount = std::tuple_size_v<Arguments>;
482
484 template <std::size_t J>
485 using Argument = std::tuple_element_t<J, Arguments>;
486
487protected:
488
490 template <std::size_t I>
491 [[nodiscard]] static consteval bool
492 itemInState()
493 {
494 if constexpr (Whole)
495 {
496 return true;
497 }
498 else
499 {
500 return []<typename First, typename... Rest>(TagPath<First, Rest...> *) {
501 return countTag<First, Space>() > 0;
502 }(static_cast<typename Item<I>::PathType *>(nullptr));
503 }
504 }
505
509 template <std::size_t I>
510 [[nodiscard]] static consteval std::size_t
511 argumentOfItem()
512 {
513 if constexpr (itemInState<I>())
514 {
515 return ArgumentCount;
516 }
517 else
518 {
519 static_assert(
520 Item<I>::SingleTag,
521 "an item of reads() that names no block of the state names an input of the call by one tag, so a "
522 "path of several tags must be in the state"
523 );
524 using Tag = PathTag<typename Item<I>::PathType>;
525 constexpr auto matches = []<std::size_t... J>(std::index_sequence<J...>) {
526 return std::array<bool, ArgumentCount + 1>{std::is_same_v<InputTag<Argument<J>>, Tag>..., false};
527 }(std::make_index_sequence<ArgumentCount>{});
528 for (std::size_t j = 0; j < ArgumentCount; ++j)
529 {
530 if (matches[j])
531 {
532 return j;
533 }
534 }
535 return ArgumentCount;
536 }
537 }
538
539 // These are consteval functions of an index rather than static constexpr arrays: MSVC reads a
540 // class template's constexpr array members in a class-scope static_assert before it has
541 // initialized them ("read of an uninitialized symbol"), and a function has nothing to read.
542
544 [[nodiscard]] static consteval bool
545 inState(std::size_t i)
546 {
547 return []<std::size_t... I>(std::size_t item, std::index_sequence<I...>) {
548 return ((I == item && itemInState<I>()) || ... || false);
549 }(i, std::make_index_sequence<ItemCount>{});
550 }
551
553 [[nodiscard]] static consteval std::size_t
554 argumentOf(std::size_t i)
555 {
556 return []<std::size_t... I>(std::size_t item, std::index_sequence<I...>) {
557 std::size_t found = ArgumentCount;
558 ((I == item ? (found = argumentOfItem<I>(), 0) : 0), ...);
559 return found;
560 }(i, std::make_index_sequence<ItemCount>{});
561 }
562
563 static_assert(
564 []<std::size_t... I>(std::index_sequence<I...>) {
565 return ((itemInState<I>() || argumentOfItem<I>() < ArgumentCount) && ...);
566 }(std::make_index_sequence<ItemCount>{}),
567 "the model reads an input that the state lacks, which the call must give as an uncertain input over the "
568 "tag's space or as sure<Tag>(value)"
569 );
570
572 template <std::size_t J>
573 [[nodiscard]] static consteval bool
574 argumentRead()
575 {
576 if constexpr (std::is_void_v<InputTag<Argument<J>>>)
577 {
578 return true;
579 }
580 else
581 {
582 return []<std::size_t... I>(std::index_sequence<I...>) {
583 return ((argumentOfItem<I>() == J) || ... || false);
584 }(std::make_index_sequence<ItemCount>{});
585 }
586 }
587
588 static_assert(
589 []<std::size_t... J>(std::index_sequence<J...>) {
590 return (argumentRead<J>() && ... && true);
591 }(std::make_index_sequence<ArgumentCount>{}),
592 "the call was given an input the model does not read"
593 );
594
596 [[nodiscard]] static consteval bool
597 uncertainArgument(std::size_t j)
598 {
599 return []<std::size_t... J>(std::size_t argument, std::index_sequence<J...>) {
600 return ((J == argument && argumentKind<Argument<J>> == ArgumentKind::uncertain) || ... || false);
601 }(j, std::make_index_sequence<ArgumentCount>{});
602 }
603
605 [[nodiscard]] static consteval bool
606 argumentIsUncertain(std::size_t i)
607 {
608 return !inState(i) && uncertainArgument(argumentOf(i));
609 }
610
612 [[nodiscard]] static consteval std::size_t
613 countItems(bool state)
614 {
615 std::size_t count = 0;
616 for (std::size_t i = 0; i < ItemCount; ++i)
617 {
618 if (state ? inState(i) : argumentIsUncertain(i))
619 {
620 ++count;
621 }
622 }
623 return count;
624 }
625
626public:
627
628 static constexpr std::size_t StateCount = countItems(true);
629 static constexpr std::size_t InputCount = countItems(false);
630
631protected:
632
636 [[nodiscard]] static consteval std::size_t
637 itemWhere(bool state, std::size_t n)
638 {
639 std::size_t seen = 0;
640 for (std::size_t i = 0; i < ItemCount; ++i)
641 {
642 if (state ? inState(i) : argumentIsUncertain(i))
643 {
644 if (seen == n)
645 {
646 return i;
647 }
648 ++seen;
649 }
650 }
651 return ItemCount;
652 }
653
655 [[nodiscard]] static consteval std::size_t
656 stateItems(std::size_t k)
657 {
658 return itemWhere(true, k);
659 }
660
662 [[nodiscard]] static consteval std::size_t
663 inputItems(std::size_t p)
664 {
665 return itemWhere(false, p);
666 }
667
669 [[nodiscard]] static consteval std::size_t
670 stateIndexOf(std::size_t i)
671 {
672 for (std::size_t k = 0; k < StateCount; ++k)
673 {
674 if (stateItems(k) == i)
675 {
676 return k;
677 }
678 }
679 return StateCount;
680 }
681
683 [[nodiscard]] static consteval std::size_t
684 inputIndexOf(std::size_t i)
685 {
686 for (std::size_t p = 0; p < InputCount; ++p)
687 {
688 if (inputItems(p) == i)
689 {
690 return p;
691 }
692 }
693 return InputCount;
694 }
695
696public:
697
699 using StatePaths = typename TagPathsOfTuple<decltype([]<std::size_t... K>(std::index_sequence<K...>) {
700 return std::tuple<typename Item<stateItems(K)>::PathType...>{};
701 }(std::make_index_sequence<StateCount>{}))>::type;
702
704 using Reads = ReadBlocks<Space, StatePaths>;
705
707 template <typename T>
708 using InVector = typename Moments<In, T>::VectorType;
709
713 ResolvedReads(Arguments const & arguments, Space const & space)
714 : m_arguments{arguments}
715 , m_reads{space}
716 , m_in{makeIn(arguments, space)}
717 , m_stateDifferenceSize{differenceDimension(space)}
718 {
719 if constexpr (Whole)
720 {
721 m_valueRows[0] = BlockRows{0, valueDimension(m_in)};
722 m_differenceRows[0] = BlockRows{0, differenceDimension(m_in)};
723 }
724 else
725 {
726 static_assert(checkReadNames<ReadsPolicy, Space>());
727 [&]<std::size_t... I>(std::index_sequence<I...>) {
728 ((m_valueRows[I] = blockRows<typename Item<I>::NameType>(m_in),
729 m_differenceRows[I] = differenceBlockRows<typename Item<I>::NameType>(m_in)),
730 ...);
731 }(std::make_index_sequence<ItemCount>{});
732 }
733 }
734
736 [[nodiscard]] Arguments const &
737 arguments() const
738 {
739 return m_arguments;
740 }
741
743 [[nodiscard]] Reads const &
744 reads() const
745 {
746 return m_reads;
747 }
748
750 [[nodiscard]] In const &
751 in() const
752 {
753 return m_in;
754 }
755
757 [[nodiscard]] Eigen::Index
758 stateDifferenceSize() const
759 {
760 return m_stateDifferenceSize;
761 }
762
764 [[nodiscard]] BlockRows const &
765 valueRows(std::size_t i) const
766 {
767 return m_valueRows[i];
768 }
769
771 [[nodiscard]] BlockRows const &
772 differenceRows(std::size_t i) const
773 {
774 return m_differenceRows[i];
775 }
776
778 [[nodiscard]] auto
779 inputs() const
780 {
781 return [&]<std::size_t... P>(std::index_sequence<P...>) {
782 return std::tuple<Argument<argumentOf(inputItems(P))> const &...>{
783 std::get<argumentOf(inputItems(P))>(m_arguments)...
784 };
785 }(std::make_index_sequence<InputCount>{});
786 }
787
789 [[nodiscard]] static consteval bool
790 inputsAffine()
791 {
792 using Affine = typename Model::template Policy<PolicyKind::affineIn>;
793 return []<std::size_t... P>(std::index_sequence<P...>) {
794 return (affineNames<Affine, typename Item<inputItems(P)>::NameType> && ... && true);
795 }(std::make_index_sequence<InputCount>{});
796 }
797
801 template <std::size_t I>
802 [[nodiscard]] static consteval bool
803 itemFactored()
804 {
805 using Affine = typename Model::template Policy<PolicyKind::affineIn>;
806 using Name = typename Item<I>::NameType;
807 return affineNames<Affine, Name> && isLinear<Name> && (inState(I) || argumentIsUncertain(I));
808 }
809
814 [[nodiscard]] static consteval int
815 affineSize()
816 {
817 return []<std::size_t... I>(std::index_sequence<I...>) {
818 return sizeSum<
819 (itemFactored<I>() ? valueDimensionAtCompileTime<DifferenceSpace<typename Item<I>::NameType>> : 0)...>;
820 }(std::make_index_sequence<ItemCount>{});
821 }
822
824 [[nodiscard]] static consteval int
825 affineMaxSize()
826 {
827 return []<std::size_t... I>(std::index_sequence<I...>) {
828 return sizeSum<(
829 itemFactored<I>() ? maxValueDimensionAtCompileTime<DifferenceSpace<typename Item<I>::NameType>> : 0
830 )...>;
831 }(std::make_index_sequence<ItemCount>{});
832 }
833
837 [[nodiscard]] static consteval bool
838 factorsAffine()
839 {
840 return []<std::size_t... I>(std::index_sequence<I...>) {
841 return (itemFactored<I>() || ... || false);
842 }(std::make_index_sequence<ItemCount>{});
843 }
844
850 template <bool WholeState>
851 [[nodiscard]] IndexVector<affineSize(), affineMaxSize()>
852 affineCoordinates() const
853 {
854 std::array<Eigen::Index, InputCount + 1> inputStarts{};
855 inputStarts[0] = WholeState ? m_stateDifferenceSize : m_reads.differenceIndices().size();
856 std::apply(
857 [&](auto const &... input) {
858 std::size_t p = 0;
859 ((inputStarts[p + 1] = inputStarts[p] + inputOf(input).differenceDimension(), ++p), ...);
860 },
861 inputs()
862 );
863 Eigen::Index count = 0;
864 [&]<std::size_t... I>(std::index_sequence<I...>) {
865 ((count += itemFactored<I>() ? m_differenceRows[I].size : 0), ...);
866 }(std::make_index_sequence<ItemCount>{});
867 auto result = IndexVector<affineSize(), affineMaxSize()>{};
868 result.resize(count);
869 Eigen::Index next = 0;
870 [&]<std::size_t... I>(std::index_sequence<I...>) {
871 (
872 [&] {
873 if constexpr (itemFactored<I>())
874 {
875 Eigen::Index start = 0;
876 if constexpr (inState(I))
877 {
878 start = WholeState ? m_reads.differenceRows(stateIndexOf(I)).start
879 : m_reads.jointDifferenceStart(stateIndexOf(I));
880 }
881 else
882 {
883 start = inputStarts[inputIndexOf(I)];
884 }
885 for (Eigen::Index r = 0; r < m_differenceRows[I].size; ++r)
886 {
887 result(next++) = start + r;
888 }
889 }
890 }(),
891 ...
892 );
893 }(std::make_index_sequence<ItemCount>{});
894 return result;
895 }
896
901 template <typename T, typename Joint, typename Inputs>
902 [[nodiscard]] InVector<T>
903 gather(Joint const & joint, Inputs const & inputs) const
904 {
905 auto x = InVector<T>{};
906 x.resize(valueDimension(m_in));
907 [&]<std::size_t... I>(std::index_sequence<I...>) {
908 (gatherItem<I, T>(x, joint, inputs), ...);
909 }(std::make_index_sequence<ItemCount>{});
910 return x;
911 }
912
917 template <typename T, typename Rows, typename Inputs>
918 [[nodiscard]] InVector<T>
919 gatherFromRows(Rows const & rows, Eigen::Index start, Inputs const & inputs) const
920 {
921 auto x = InVector<T>{};
922 x.resize(valueDimension(m_in));
923 [&]<std::size_t... I>(std::index_sequence<I...>) {
924 (gatherItemFromRows<I, T>(x, rows, start, inputs), ...);
925 }(std::make_index_sequence<ItemCount>{});
926 return x;
927 }
928
934 template <typename T, typename X, typename RowsOf>
935 void
936 gatherColumnsFromRows(X & x, RowsOf const & rowsOf, Eigen::Index start) const
937 {
938 EMRYS_FILTER_ASSERT(
939 x.rows() == valueDimension(m_in) && "the batch has a row per value coordinate of the input"
940 );
941 for (Eigen::Index j = 0; j < x.cols(); ++j)
942 {
943 auto column = x.col(j);
944 auto const & rows = rowsOf(j);
945 [&]<std::size_t... I>(std::index_sequence<I...>) {
946 (gatherItemFromRows<I, T>(column, rows, start, std::tuple<>{}), ...);
947 }(std::make_index_sequence<ItemCount>{});
948 }
949 }
950
951protected:
952
956 [[nodiscard]] static In
957 makeIn([[maybe_unused]] Arguments const & arguments, Space const & space)
958 {
959 if constexpr (Whole)
960 {
961 return space;
962 }
963 else
964 {
965 return [&]<std::size_t... I>(std::index_sequence<I...>) {
966 return In{nameOf<typename Item<I>::NameType>(blockOf<I>(arguments, space))...};
967 }(std::make_index_sequence<ItemCount>{});
968 }
969 }
970
972 template <std::size_t I>
973 [[nodiscard]] static auto
974 blockOf([[maybe_unused]] Arguments const & arguments, [[maybe_unused]] Space const & space)
975 {
976 if constexpr (inState(I))
977 {
978 return pathSubspace<typename Item<I>::PathType>(space);
979 }
980 else
981 {
982 auto const & argument = std::get<argumentOf(I)>(arguments);
983 if constexpr (isSure<std::remove_cvref_t<decltype(argument)>>)
984 {
985 return argument.space;
986 }
987 else
988 {
989 return inputOf(argument).space();
990 }
991 }
992 }
993
997 template <std::size_t I, typename T, typename Joint, typename Inputs>
998 void
999 gatherItem(InVector<T> & x, Joint const & joint, Inputs const & inputs) const
1000 {
1001 constexpr int Rows = valueDimensionAtCompileTime<typename Item<I>::NameType>;
1002 auto target = middleRowsOf<Rows>(x, m_valueRows[I].start, m_valueRows[I].size);
1003 if constexpr (inState(I))
1004 {
1005 target = middleRowsOf<Rows>(joint, m_reads.jointStart(stateIndexOf(I)), m_valueRows[I].size);
1006 }
1007 else
1008 {
1009 gatherArgument<I, T>(target, inputs);
1010 }
1011 }
1012
1016 template <std::size_t I, typename T, typename X, typename Rows, typename Inputs>
1017 void
1018 gatherItemFromRows(X & x, Rows const & rows, Eigen::Index start, Inputs const & inputs) const
1019 {
1020 constexpr int Size = valueDimensionAtCompileTime<typename Item<I>::NameType>;
1021 auto target = middleRowsOf<Size>(x, m_valueRows[I].start, m_valueRows[I].size);
1022 if constexpr (inState(I))
1023 {
1024 BlockRows const & block = m_reads.rows(stateIndexOf(I));
1025 EMRYS_FILTER_ASSERT(
1026 block.start >= start && block.start + block.size <= start + rows.size()
1027 && "the rows must hold every block read"
1028 );
1029 target = middleRowsOf<Size>(rows, block.start - start, block.size).template cast<T>();
1030 }
1031 else
1032 {
1033 gatherArgument<I, T>(target, inputs);
1034 }
1035 }
1036
1040 template <std::size_t I, typename T, typename Target, typename Inputs>
1041 void
1042 gatherArgument(Target & target, [[maybe_unused]] Inputs const & inputs) const
1043 {
1044 auto const & argument = std::get<argumentOf(I)>(m_arguments);
1045 if constexpr (!argumentIsUncertain(I))
1046 {
1047 target = argument.value.template cast<T>();
1048 }
1049 else if constexpr (std::tuple_size_v<Inputs> > 0)
1050 {
1051 target = std::get<inputIndexOf(I)>(inputs);
1052 }
1053 else
1054 {
1055 target = inputOf(argument).mean().template cast<T>();
1056 }
1057 }
1058
1059 Arguments const & m_arguments;
1060 Reads m_reads;
1061 In m_in;
1062 Eigen::Index m_stateDifferenceSize;
1063 std::array<BlockRows, ItemCount> m_valueRows{};
1064 std::array<BlockRows, ItemCount> m_differenceRows{};
1065};
1066
1067} // namespace internal
1068
1069} // namespace Emrys
Spaces built from other spaces (decisions.md [sizes-and-dimensions], [several-resizable-blocks]): Com...
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],...
The policies a model is built from, and the marks on a step's arguments (decisions....
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...
ValueVector< Space_, Scalar > VectorType
a value, such as the mean
Definition Moments.h:74
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 bool isLinear
Whether S is linear: its values and its differences are both plain vectors.
Definition Space.h:321
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