EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Subspace.h
Go to the documentation of this file.
1#pragma once
2
9
10#include <array>
11#include <cstddef>
12#include <tuple>
13#include <type_traits>
14#include <utility>
15
20
21namespace Emrys
22{
23
24namespace internal
25{
26
28template <typename P>
29struct PathTagOf
30{
32 using type = P;
33};
34
36template <typename... Tags>
37struct PathTagOf<TagPath<Tags...>>
38{
40 using type = std::tuple_element_t<sizeof...(Tags) - 1, std::tuple<Tags...>>;
41};
42
44template <typename P>
45using PathTag = typename PathTagOf<P>::type;
46
51template <typename P>
52inline constexpr bool RunsThroughRepeated = false;
54template <typename... Tags>
55inline constexpr bool RunsThroughRepeated<TagPath<Tags...>> = [] {
56 constexpr bool repeated[] = {IsRepeated<Tags>...};
57 for (std::size_t i = 0; i + 1 < sizeof...(Tags); ++i)
58 {
59 if (repeated[i])
60 {
61 return true;
62 }
63 }
64 return false;
65}();
66
68
70template <typename P, typename Space>
71[[nodiscard]] PathTag<P> const &
72pathBlock(Space const & space)
73{
74 return withPathTags<P>([&]<typename... Tags>() -> PathTag<P> const & {
75 auto const * block = locatePath<Tags...>(space).second;
76 return *block;
77 });
78}
79
81template <typename Tag, typename Space>
82[[nodiscard]] Tag const &
83findTag(Space const & space)
84{
85 Tag const * block = locate<Tag>(space).second;
86 return *block;
87}
88
93template <typename Space, typename Tag, typename... Rest>
94[[nodiscard]] auto
95subspace(Space const & space)
96{
97 Tag const & tag = findTag<Tag>(space);
98 if constexpr (sizeof...(Rest) == 0)
99 {
100 return tag;
101 }
102 else if constexpr (IsRepeated<Tag>)
103 {
104 auto inner = subspace<RepeatedBlock<Tag>, Rest...>(tag.block());
105 return Repeated<decltype(inner), Tag::MaxCount>{std::move(inner), tag.count()};
106 }
107 else
108 {
109 return subspace<Tag, Rest...>(tag);
110 }
111}
112
114template <typename Space, typename... Path>
115using SubspaceType = decltype(subspace<Space, Path...>(std::declval<Space const &>()));
116
120template <typename RepeatedTag, typename... Inner, typename Space>
121[[nodiscard]] auto
122elementSubspace(Space const & space)
123{
124 static_assert(IsRepeated<RepeatedTag>, "this takes a repeated block");
125 auto const & block = findTag<RepeatedTag>(space).block();
126 if constexpr (sizeof...(Inner) == 0)
127 {
128 return block;
129 }
130 else
131 {
132 return subspace<RepeatedBlock<RepeatedTag>, Inner...>(block);
133 }
134}
135
139template <typename... Blocks>
140[[nodiscard]] auto
141joinBlocks(std::tuple<Blocks...> blocks)
142{
143 if constexpr (sizeof...(Blocks) == 0)
144 {
145 return Linear<0>{};
146 }
147 else if constexpr (sizeof...(Blocks) == 1)
148 {
149 return std::get<0>(std::move(blocks));
150 }
151 else
152 {
153 return std::apply(
154 [](Blocks &... b) {
155 return Composite<Blocks...>{std::move(b)...};
156 },
157 blocks
158 );
159 }
160}
161
162template <typename Tag, typename... Rest, typename Space>
163[[nodiscard]] auto
164blocksWithout(Space const & space); // defined below; blockWithout() recurses into it
165
169template <typename Tag, typename... Rest, typename Block>
170[[nodiscard]] auto
171blockWithout(Block const & block)
172{
173 if constexpr (countTag<Tag, Block>() > 0)
174 {
175 return blocksWithout<Tag, Rest...>(block);
176 }
177 else
178 {
179 return std::tuple<Block>{block};
180 }
181}
182
190template <typename Tag, typename... Rest, typename Space>
191[[nodiscard]] auto
192blocksWithout(Space const & space)
193{
194 if constexpr (std::is_same_v<Tag, Space>)
195 {
196 if constexpr (sizeof...(Rest) == 0)
197 {
198 return std::tuple<>{};
199 }
200 else if constexpr (IsRepeated<Tag>)
201 {
202 auto rest = blocksWithout<Rest...>(space.block());
203 if constexpr (std::tuple_size_v<decltype(rest)> == 0)
204 {
205 return std::tuple<>{};
206 }
207 else
208 {
209 auto block = joinBlocks(std::move(rest));
210 return std::tuple<Repeated<decltype(block), Tag::MaxCount>>{
211 Repeated<decltype(block), Tag::MaxCount>{std::move(block), space.count()}
212 };
213 }
214 }
215 else
216 {
217 return blocksWithout<Rest...>(space);
218 }
219 }
220 else
221 {
222 static_assert(
223 !IsUntagged<Tag>,
224 "a path names blocks by tag; derive one, such as struct Heading : RadiansPi<> {}"
225 );
226 static_assert(IsComposite<Space>, "the space does not contain this tag");
227 return [&]<std::size_t... I>(std::index_sequence<I...>) {
228 return std::tuple_cat(blockWithout<Tag, Rest...>(space.template block<I>())...);
229 }(std::make_index_sequence<std::tuple_size_v<CompositeBlocks<Space>>>{});
230 }
231}
232
236template <typename... Given, typename Space>
237[[nodiscard]] auto
238complementSubspace(Space const & space)
239{
240 return joinBlocks(blocksWithout<Given...>(space));
241}
242
244template <typename P, typename Space>
245[[nodiscard]] auto
246pathSubspace(Space const & space)
247{
248 return withPathTags<P>([&]<typename... Tags>() {
249 return subspace<Space, Tags...>(space);
250 });
251}
252
254template <typename Space, typename P>
255using PathSubspaceType = decltype(pathSubspace<P>(std::declval<Space const &>()));
256
258template <typename P, typename Space>
259[[nodiscard]] auto
260pathElementSubspace(Space const & space)
261{
262 return withPathTags<P>([&]<typename... Tags>() {
263 return elementSubspace<Tags...>(space);
264 });
265}
266
268template <typename P, typename Space>
269[[nodiscard]] auto
270pathComplement(Space const & space)
271{
272 return withPathTags<P>([&]<typename... Tags>() {
273 return complementSubspace<Tags...>(space);
274 });
275}
276
281template <typename Block>
282concept IsElementwise = IsRepeated<Block> || (IsUniformLeaf<Block> && Block::ValueDimensionStep != 0);
283
285template <IsElementwise Block>
286[[nodiscard]] Eigen::Index
287elementCount(Block const & block)
288{
289 if constexpr (IsRepeated<Block>)
290 {
291 return block.count();
292 }
293 else
294 {
295 return block.valueDimension();
296 }
297}
298
300template <IsElementwise Block>
301void
302setElementCount(Block & block, Eigen::Index count)
303{
304 if constexpr (IsRepeated<Block>)
305 {
306 block.setCount(count);
307 }
308 else
309 {
310 block.resize(count);
311 }
312}
313
315struct ElementRows
316{
317 Eigen::Index start;
318 Eigen::Index count;
319 Eigen::Index differenceStart;
320 Eigen::Index differenceCount;
321};
322
326template <typename Path, typename Space>
327[[nodiscard]] auto
328locateElementwise(Space & space)
329{
330 auto [offset, block] = withPathTags<Path>([&]<typename... Tags>() {
331 return locatePathIn<false, Tags...>(space);
332 });
333 Eigen::Index const differenceOffset = withPathTags<Path>([&]<typename... Tags>() {
334 return locatePathIn<true, Tags...>(space).first;
335 });
336 using Block = std::remove_pointer_t<decltype(block)>;
337 static_assert(
338 IsElementwise<Block>,
339 "insert() and erase() take a Repeated block or a resizable Linear or Periodic block"
340 );
341 return std::tuple{offset, differenceOffset, block};
342}
343
347template <typename Path, typename Space>
348[[nodiscard]] ElementRows
349growBlock(Space & space, Eigen::Index element, Eigen::Index rows)
350{
351 auto [offset, differenceOffset, block] = locateElementwise<Path>(space);
352 using Block = std::remove_pointer_t<decltype(block)>;
353 constexpr Eigen::Index elementSize = Block::ValueDimensionStep;
354 constexpr Eigen::Index differenceElementSize = SizedAs<true, Block>::ValueDimensionStep;
355 Eigen::Index const count = elementCount(*block);
356 EMRYS_FILTER_ASSERT(element >= 0 && element <= count && "insertion point out of range");
357 EMRYS_FILTER_ASSERT(rows % elementSize == 0 && "insert whole elements");
358 setElementCount(*block, count + rows / elementSize);
359 return {
360 offset + element * elementSize,
361 rows,
362 differenceOffset + element * differenceElementSize,
363 rows / elementSize * differenceElementSize
364 };
365}
366
370template <typename Path, typename Space>
371[[nodiscard]] ElementRows
372shrinkBlock(Space & space, Eigen::Index element, Eigen::Index elements)
373{
374 auto [offset, differenceOffset, block] = locateElementwise<Path>(space);
375 using Block = std::remove_pointer_t<decltype(block)>;
376 constexpr Eigen::Index elementSize = Block::ValueDimensionStep;
377 constexpr Eigen::Index differenceElementSize = SizedAs<true, Block>::ValueDimensionStep;
378 Eigen::Index const count = elementCount(*block);
379 EMRYS_FILTER_ASSERT(element >= 0 && elements >= 0 && element + elements <= count && "erased elements out of range");
380 setElementCount(*block, count - elements);
381 return {
382 offset + element * elementSize,
383 elements * elementSize,
384 differenceOffset + element * differenceElementSize,
385 elements * differenceElementSize
386 };
387}
388
390template <typename Indices>
391[[nodiscard]] auto
392asIndexSet(Indices const & indices)
393{
394 if constexpr (std::is_integral_v<Indices>)
395 {
396 return std::array<Eigen::Index, 1>{indices};
397 }
398 else
399 {
400 return indices;
401 }
402}
403
404} // namespace internal
405
406} // namespace Emrys
Spaces built from other spaces (decisions.md [sizes-and-dimensions], [several-resizable-blocks]): Com...
The macros every header includes first.
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
Tag paths and the index utilities (decisions.md [tag-addressing], [index-names]): TagPath and TagPath...
auto block(Space auto const &space, X &&x)
Definition TagPath.h:979