17#include <unsupported/Eigen/AutoDiff>
35template <
typename Space,
typename Reads>
41template <
typename Space,
typename... Paths>
42class ReadBlocks<Space, TagPaths<Paths...>>
44 static_assert(
sizeof...(Paths) > 0,
"a model reads at least one block of the state");
47 using First = std::tuple_element_t<0, std::tuple<Paths...>>;
51 static constexpr std::size_t Count =
sizeof...(Paths);
54 using JointSpace = std::conditional_t<Count == 1, PathTag<First>, Composite<PathTag<Paths>...>>;
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>;
67 explicit ReadBlocks(Space
const & space)
68 : m_rows{blockRows<Paths>(space)...}
69 , m_differenceRows{differenceBlockRows<Paths>(space)...}
70 , m_space{makeSpace(space)}
72 Eigen::Index offset = 0;
73 Eigen::Index differenceOffset = 0;
74 for (std::size_t i = 0; i < Count; ++i)
76 m_jointStarts[i] = offset;
77 m_jointDifferenceStarts[i] = differenceOffset;
78 offset += m_rows[i].size;
79 differenceOffset += m_differenceRows[i].size;
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");
87 [[nodiscard]] JointSpace
const &
94 [[nodiscard]] Indices
const &
101 [[nodiscard]] DifferenceIndices
const &
102 differenceIndices()
const
104 return m_differenceIndices;
108 [[nodiscard]] Selection
111 return {m_indices, m_differenceIndices};
115 [[nodiscard]] BlockRows
const &
116 rows(std::size_t k)
const
122 [[nodiscard]] BlockRows
const &
123 differenceRows(std::size_t k)
const
125 return m_differenceRows[k];
129 [[nodiscard]] Eigen::Index
130 jointStart(std::size_t k)
const
132 return m_jointStarts[k];
136 [[nodiscard]] Eigen::Index
137 jointDifferenceStart(std::size_t k)
const
139 return m_jointDifferenceStarts[k];
145 [[nodiscard]]
static JointSpace
146 makeSpace(Space
const & space)
148 if constexpr (Count == 1)
150 return pathBlock<First>(space);
154 return JointSpace{pathBlock<Paths>(space)...};
159 template <
typename Result>
160 [[nodiscard]]
static Result
161 concatenate(std::array<BlockRows, Count>
const & blocks)
163 Eigen::Index size = 0;
164 for (BlockRows
const & rows : blocks)
168 auto result = Result{};
171 for (BlockRows
const & rows : blocks)
173 for (Eigen::Index j = 0; j < rows.size; ++j)
175 result(k++) = rows.start + j;
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{};
186 DifferenceIndices m_differenceIndices;
193template <
typename Space>
194class ReadBlocks<Space, TagPaths<WholeSpace>>
198 static constexpr std::size_t Count = 1;
201 using JointSpace = Space;
205 static constexpr int DifferenceSize =
208 using Indices = IndexVector<Size, MaxSize>;
209 using DifferenceIndices = IndexVector<DifferenceSize, DifferenceMaxSize>;
210 using Selection = Coordinates<Indices, DifferenceIndices>;
213 explicit ReadBlocks(Space
const & 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)}
222 [[nodiscard]] JointSpace
const &
229 [[nodiscard]] Indices
const &
236 [[nodiscard]] DifferenceIndices
const &
237 differenceIndices()
const
239 return m_differenceIndices;
243 [[nodiscard]] Selection
246 return {m_indices, m_differenceIndices};
250 [[nodiscard]] BlockRows
const &
251 rows(std::size_t)
const
257 [[nodiscard]] BlockRows
const &
258 differenceRows(std::size_t)
const
260 return m_differenceRows;
264 [[nodiscard]] Eigen::Index
265 jointStart(std::size_t)
const
271 [[nodiscard]] Eigen::Index
272 jointDifferenceStart(std::size_t)
const
280 BlockRows m_differenceRows;
282 DifferenceIndices m_differenceIndices;
290template <
typename Space>
293 static constexpr std::size_t Count = 1;
296 using InputSpace = Space;
299 template <std::
size_t I>
300 using Item = ReadItem<WholeSpace, Space>;
304template <
typename Model>
305inline constexpr bool readsWholeState = !Model::template has<PolicyKind::reads>;
313template <
typename Model>
314struct WholeStateRefusal
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"
322 static constexpr bool value =
true;
328template <
typename Model>
329inline constexpr bool wholeStateRefused = WholeStateRefusal<Model>::value;
332template <
typename Model,
typename Space>
334 std::conditional_t<readsWholeState<Model>, ReadsWhole<Space>,
typename Model::template Policy<PolicyKind::reads>>;
337template <
typename Tuple>
338struct TagPathsOfTuple;
341template <
typename... Paths>
342struct TagPathsOfTuple<std::tuple<Paths...>>
344 using type = TagPaths<Paths...>;
350template <
typename Policy,
typename Name>
351inline constexpr bool affineNames =
false;
354template <
typename... Names,
typename Name>
355inline constexpr bool affineNames<AffineIn<Names...>, Name> = (std::is_same_v<Names, Name> || ...);
363template <
typename Name,
typename Block>
365nameOf(Block
const &
block)
367 if constexpr (std::is_same_v<Name, Block>)
371 else if constexpr (FixedSizeSpace<Name>)
393template <
typename Derivatives>
394struct PlainScalarOf<Eigen::AutoDiffScalar<Derivatives>>
396 using type = Eigen::AutoDiffScalar<typename std::remove_cvref_t<Derivatives>::PlainObject>;
408vectorReturned(R && returned)
410 using Plain = std::remove_cvref_t<R>;
411 if constexpr (!MatrixExpression<Plain> && !isWithJacobian<Plain>)
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 "
419 return Eigen::Matrix<Plain, 1, 1>{std::forward<R>(returned)};
423 return std::forward<R>(returned);
431template <
typename Model>
432[[nodiscard]]
consteval bool
435 if constexpr (readsWholeState<Model>)
437 return requires {
requires Model::FunctionType::IsAffine; };
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));
455template <
typename Model,
typename Arguments,
typename Space>
460 using ModelType = Model;
461 using SpaceType = Space;
464 static constexpr bool Whole = readsWholeState<Model>;
467 using ReadsPolicy = ReadsIn<Model, Space>;
469 static constexpr std::size_t ItemCount = ReadsPolicy::Count;
472 template <std::
size_t I>
473 using Item =
typename ReadsPolicy::template Item<I>;
476 using In =
typename ReadsPolicy::InputSpace;
479 using ArgumentsType = Arguments;
481 static constexpr std::size_t ArgumentCount = std::tuple_size_v<Arguments>;
484 template <std::
size_t J>
485 using Argument = std::tuple_element_t<J, Arguments>;
490 template <std::
size_t I>
491 [[nodiscard]]
static consteval bool
500 return []<
typename First,
typename... Rest>(TagPath<First, Rest...> *) {
501 return countTag<First, Space>() > 0;
502 }(
static_cast<typename Item<I>::PathType *
>(
nullptr));
509 template <std::
size_t I>
510 [[nodiscard]]
static consteval std::size_t
513 if constexpr (itemInState<I>())
515 return ArgumentCount;
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"
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)
535 return ArgumentCount;
544 [[nodiscard]]
static consteval bool
545 inState(std::size_t i)
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>{});
553 [[nodiscard]]
static consteval std::size_t
554 argumentOf(std::size_t i)
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), ...);
560 }(i, std::make_index_sequence<ItemCount>{});
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)"
572 template <std::
size_t J>
573 [[nodiscard]]
static consteval bool
576 if constexpr (std::is_void_v<InputTag<Argument<J>>>)
582 return []<std::size_t... I>(std::index_sequence<I...>) {
583 return ((argumentOfItem<I>() == J) || ... ||
false);
584 }(std::make_index_sequence<ItemCount>{});
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"
596 [[nodiscard]]
static consteval bool
597 uncertainArgument(std::size_t j)
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>{});
605 [[nodiscard]]
static consteval bool
606 argumentIsUncertain(std::size_t i)
608 return !inState(i) && uncertainArgument(argumentOf(i));
612 [[nodiscard]]
static consteval std::size_t
613 countItems(
bool state)
615 std::size_t count = 0;
616 for (std::size_t i = 0; i < ItemCount; ++i)
618 if (state ? inState(i) : argumentIsUncertain(i))
628 static constexpr std::size_t StateCount = countItems(
true);
629 static constexpr std::size_t InputCount = countItems(
false);
636 [[nodiscard]]
static consteval std::size_t
637 itemWhere(
bool state, std::size_t n)
639 std::size_t seen = 0;
640 for (std::size_t i = 0; i < ItemCount; ++i)
642 if (state ? inState(i) : argumentIsUncertain(i))
655 [[nodiscard]]
static consteval std::size_t
656 stateItems(std::size_t k)
658 return itemWhere(
true, k);
662 [[nodiscard]]
static consteval std::size_t
663 inputItems(std::size_t p)
665 return itemWhere(
false, p);
669 [[nodiscard]]
static consteval std::size_t
670 stateIndexOf(std::size_t i)
672 for (std::size_t k = 0; k < StateCount; ++k)
674 if (stateItems(k) == i)
683 [[nodiscard]]
static consteval std::size_t
684 inputIndexOf(std::size_t i)
686 for (std::size_t p = 0; p < InputCount; ++p)
688 if (inputItems(p) == i)
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;
704 using Reads = ReadBlocks<Space, StatePaths>;
707 template <
typename T>
713 ResolvedReads(Arguments
const & arguments, Space
const & space)
714 : m_arguments{arguments}
716 , m_in{makeIn(arguments, space)}
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)),
731 }(std::make_index_sequence<ItemCount>{});
736 [[nodiscard]] Arguments
const &
743 [[nodiscard]] Reads
const &
750 [[nodiscard]] In
const &
757 [[nodiscard]] Eigen::Index
758 stateDifferenceSize()
const
760 return m_stateDifferenceSize;
764 [[nodiscard]] BlockRows
const &
765 valueRows(std::size_t i)
const
767 return m_valueRows[i];
771 [[nodiscard]] BlockRows
const &
772 differenceRows(std::size_t i)
const
774 return m_differenceRows[i];
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)...
785 }(std::make_index_sequence<InputCount>{});
789 [[nodiscard]]
static consteval bool
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>{});
801 template <std::
size_t I>
802 [[nodiscard]]
static consteval bool
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));
814 [[nodiscard]]
static consteval int
817 return []<std::size_t... I>(std::index_sequence<I...>) {
819 (itemFactored<I>() ? valueDimensionAtCompileTime<DifferenceSpace<typename Item<I>::NameType>> : 0)...>;
820 }(std::make_index_sequence<ItemCount>{});
824 [[nodiscard]]
static consteval int
827 return []<std::size_t... I>(std::index_sequence<I...>) {
829 itemFactored<I>() ? maxValueDimensionAtCompileTime<DifferenceSpace<typename Item<I>::NameType>> : 0
831 }(std::make_index_sequence<ItemCount>{});
837 [[nodiscard]]
static consteval bool
840 return []<std::size_t... I>(std::index_sequence<I...>) {
841 return (itemFactored<I>() || ... ||
false);
842 }(std::make_index_sequence<ItemCount>{});
850 template <
bool WholeState>
851 [[nodiscard]] IndexVector<affineSize(), affineMaxSize()>
852 affineCoordinates()
const
854 std::array<Eigen::Index, InputCount + 1> inputStarts{};
855 inputStarts[0] = WholeState ? m_stateDifferenceSize : m_reads.differenceIndices().size();
857 [&](
auto const &... input) {
859 ((inputStarts[p + 1] = inputStarts[p] + inputOf(input).differenceDimension(), ++p), ...);
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...>) {
873 if constexpr (itemFactored<I>())
875 Eigen::Index start = 0;
876 if constexpr (inState(I))
878 start = WholeState ? m_reads.differenceRows(stateIndexOf(I)).start
879 : m_reads.jointDifferenceStart(stateIndexOf(I));
883 start = inputStarts[inputIndexOf(I)];
885 for (Eigen::Index r = 0; r < m_differenceRows[I].size; ++r)
887 result(next++) = start + r;
893 }(std::make_index_sequence<ItemCount>{});
901 template <
typename T,
typename Jo
int,
typename Inputs>
902 [[nodiscard]] InVector<T>
903 gather(Joint
const & joint, Inputs
const & inputs)
const
905 auto x = InVector<T>{};
907 [&]<std::size_t... I>(std::index_sequence<I...>) {
908 (gatherItem<I, T>(x, joint, inputs), ...);
909 }(std::make_index_sequence<ItemCount>{});
917 template <
typename T,
typename Rows,
typename Inputs>
918 [[nodiscard]] InVector<T>
919 gatherFromRows(Rows
const & rows, Eigen::Index start, Inputs
const & inputs)
const
921 auto x = InVector<T>{};
923 [&]<std::size_t... I>(std::index_sequence<I...>) {
924 (gatherItemFromRows<I, T>(x, rows, start, inputs), ...);
925 }(std::make_index_sequence<ItemCount>{});
934 template <
typename T,
typename X,
typename RowsOf>
936 gatherColumnsFromRows(X & x, RowsOf
const & rowsOf, Eigen::Index start)
const
939 x.rows() ==
valueDimension(m_in) &&
"the batch has a row per value coordinate of the input"
941 for (Eigen::Index j = 0; j < x.cols(); ++j)
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>{});
956 [[nodiscard]]
static In
957 makeIn([[maybe_unused]] Arguments
const & arguments, Space
const & space)
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>{});
972 template <std::
size_t I>
973 [[nodiscard]]
static auto
974 blockOf([[maybe_unused]] Arguments
const & arguments, [[maybe_unused]] Space
const & space)
976 if constexpr (inState(I))
978 return pathSubspace<typename Item<I>::PathType>(space);
982 auto const & argument = std::get<argumentOf(I)>(arguments);
983 if constexpr (isSure<std::remove_cvref_t<
decltype(argument)>>)
985 return argument.space;
989 return inputOf(argument).space();
997 template <std::
size_t I,
typename T,
typename Jo
int,
typename Inputs>
999 gatherItem(InVector<T> & x, Joint
const & joint, Inputs
const & inputs)
const
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))
1005 target = middleRowsOf<Rows>(joint, m_reads.jointStart(stateIndexOf(I)), m_valueRows[I].size);
1009 gatherArgument<I, T>(target, inputs);
1016 template <std::
size_t I,
typename T,
typename X,
typename Rows,
typename Inputs>
1018 gatherItemFromRows(X & x, Rows
const & rows, Eigen::Index start, Inputs
const & inputs)
const
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))
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"
1029 target = middleRowsOf<Size>(rows,
block.start - start,
block.size).template cast<T>();
1033 gatherArgument<I, T>(target, inputs);
1040 template <std::
size_t I,
typename T,
typename Target,
typename Inputs>
1042 gatherArgument(Target & target, [[maybe_unused]] Inputs
const & inputs)
const
1044 auto const & argument = std::get<argumentOf(I)>(m_arguments);
1045 if constexpr (!argumentIsUncertain(I))
1047 target = argument.value.template cast<T>();
1049 else if constexpr (std::tuple_size_v<Inputs> > 0)
1051 target = std::get<inputIndexOf(I)>(inputs);
1055 target = inputOf(argument).mean().template cast<T>();
1059 Arguments
const & m_arguments;
1062 Eigen::Index m_stateDifferenceSize;
1063 std::array<BlockRows, ItemCount> m_valueRows{};
1064 std::array<BlockRows, ItemCount> m_differenceRows{};
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