OpenKalman
split.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2022 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
16 #ifndef OPENKALMAN_SPLIT_HPP
17 #define OPENKALMAN_SPLIT_HPP
18 
19 namespace OpenKalman
20 {
21  // ======= //
22  // split //
23  // ======= //
24 
25  namespace detail
26  {
27  template<std::size_t index, typename Arg, typename...Ds>
28  constexpr void check_split_vector_space_descriptor(Arg&& arg, Ds&&...ds)
29  {
30  if constexpr ((dynamic_pattern<Ds> or ... or dynamic_dimension<Arg, index>))
31  {
32  if (not ((get_dimension(ds) + ... + std::size_t{0}) <= get_vector_space_descriptor<index>(arg)))
33  throw std::logic_error {"When concatenated, the vector space descriptors provided to split function are not a "
34  "prefix of the argument's vector space descriptor along at least index " + std::to_string(index)};
35  }
36  else
37  {
38  static_assert(coordinates::compares_with<std::tuple<std::decay_t<Ds>...>, vector_space_descriptor_of_t<Arg, index>, less_equal<>>,
39  "Concatenated vector space descriptors provided to split function must be a prefix of the argument's vector space descriptor");
40  }
41  }
42 
43 
44  template<std::size_t index>
45  constexpr auto split_dummy(std::size_t x) { return x; };
46 
47  template<std::size_t...indices, typename Arg, typename Blocks_tup>
48  auto split_symmetric(Arg&& arg, std::size_t begin, Blocks_tup&& blocks_tup)
49  {
50  return std::forward<Blocks_tup>(blocks_tup);
51  }
52 
53  template<std::size_t...indices, typename Arg, typename Blocks_tup, typename D, typename...Ds>
54  auto split_symmetric(Arg&& arg, std::size_t begin, Blocks_tup&& blocks_tup, D&& d, Ds&&...ds)
55  {
56  auto block_size = get_dimension(d);
57  auto begin_tup = std::tuple{split_dummy<indices>(begin)...};
58  auto size_tup = std::tuple{split_dummy<indices>(block_size)...};
59  auto block = get_slice<indices...>(std::forward<Arg>(arg), begin_tup, size_tup);
60  auto new_blocks_tup = std::tuple_cat(blocks_tup, std::tuple {std::move(block)});
61  return split_symmetric<indices...>(std::forward<Arg>(arg), begin + block_size, std::move(new_blocks_tup), std::forward<Ds>(ds)...);
62  }
63 
64  } // namespace detail
65 
66 
78 #ifdef __cpp_concepts
79  template<std::size_t...indices, indexible Arg, coordinates::pattern...Ds> requires (sizeof...(indices) > 0)
80 #else
81  template<std::size_t...indices, typename Arg, typename...Ds, std::enable_if_t<indexible<Arg> and
82  (coordinates::pattern<Ds> and ...) and (sizeof...(indices) > 0), int> = 0>
83 #endif
84  inline auto
85  split(Arg&& arg, Ds&&...ds)
86  {
87  (detail::check_split_vector_space_descriptor<indices>(arg, ds...),...);
88  return detail::split_symmetric<indices...>(arg, 0, std::tuple{}, std::forward<Ds>(ds)...);
89  }
90 
91 
92  namespace detail
93  {
94  template<std::size_t index, std::size_t index_ix, typename Arg, typename...Ds_tups>
95  constexpr void check_split_vector_space_descriptor_tup_impl(Arg&& arg, Ds_tups&&...ds_tups)
96  {
97  check_split_vector_space_descriptor<index>(arg, std::get<index_ix>(ds_tups)...);
98  }
99 
100  template<std::size_t...indices, typename Arg, typename...Ds_tups, std::size_t...indices_ix>
101  constexpr void check_split_vector_space_descriptor_tup(Arg&& arg, std::index_sequence<indices_ix...>, Ds_tups&&...ds_tups)
102  {
103  (check_split_vector_space_descriptor_tup_impl<indices, indices_ix>(arg, ds_tups...),...);
104  }
105 
106 
107  template<std::size_t...indices, typename Arg, typename Begin_tup, typename Blocks_tup, std::size_t...indices_ix>
108  auto split_impl(Arg&& arg, Begin_tup begin_tup, Blocks_tup&& blocks_tup, std::index_sequence<indices_ix...>)
109  {
110  return std::forward<Blocks_tup>(blocks_tup);
111  }
112 
113  template<std::size_t...indices, typename Arg, typename Begin_tup, typename Blocks_tup, std::size_t...indices_ix,
114  typename Ds_tup, typename...Ds_tups>
115  auto split_impl(Arg&& arg, Begin_tup begin_tup, Blocks_tup&& blocks_tup, std::index_sequence<indices_ix...> seq,
116  Ds_tup&& ds_tup, Ds_tups&&...ds_tups)
117  {
118  auto size_tup = std::tuple{get_dimension(std::get<indices_ix>(ds_tup))...};
119  auto block = get_slice<indices...>(std::forward<Arg>(arg), begin_tup, size_tup);
120  auto new_blocks_tup = std::tuple_cat(blocks_tup, std::tuple {std::move(block)});
121  auto new_begin_tup = std::tuple{std::get<indices_ix>(begin_tup) + std::get<indices_ix>(size_tup)...};
122  return split_impl<indices...>(std::forward<Arg>(arg), new_begin_tup, std::move(new_blocks_tup), seq, std::forward<Ds_tups>(ds_tups)...);
123  }
124 
125  } // namespace detail
126 
127 
140 #ifdef __cpp_concepts
141  template<std::size_t...indices, indexible Arg, typename...Ds_tups> requires
142  (sizeof...(indices) > 0) and (sizeof...(Ds_tups) > 0) and
143  ((sizeof...(indices) == std::tuple_size<Ds_tups>::value) and ...)
144 #else
145  template<std::size_t...indices, typename Arg, typename...Ds_tups, std::enable_if_t<indexible<Arg> and
146  (sizeof...(indices) > 0) and (sizeof...(Ds_tups) > 0) and
147  ((sizeof...(indices) == std::tuple_size<Ds_tups>::value) and ...), int> = 0>
148 #endif
149  inline auto
150  split(Arg&& arg, const Ds_tups&...ds_tups)
151  {
152  std::make_index_sequence<sizeof...(indices)> seq;
153  detail::check_split_vector_space_descriptor_tup<indices...>(arg, seq, ds_tups...);
154 
155  if constexpr (sizeof...(indices) == 1)
156  {
157  return detail::split_symmetric<indices...>(arg, 0, std::tuple{}, std::get<0>(ds_tups)...);
158  }
159  else
160  {
161  auto init_begin = std::tuple {detail::split_dummy<indices>(0)...};
162  return detail::split_impl<indices...>(arg, init_begin, std::tuple{}, seq, ds_tups...);
163  }
164  }
165 
166 
167 } // namespace OpenKalman
168 
169 #endif //OPENKALMAN_SPLIT_HPP
decltype(auto) constexpr get_slice(Arg &&arg, const std::tuple< Offset... > &offsets, const std::tuple< Extent... > &extents)
Extract a slice from a matrix or tensor.
Definition: get_slice.hpp:101
constexpr bool indexible
T is a generalized tensor type.
Definition: indexible.hpp:32
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
constexpr auto get_dimension(const Arg &arg)
Get the vector dimension of coordinates::pattern Arg.
Definition: get_dimension.hpp:55
The root namespace for OpenKalman.
Definition: basics.hpp:34
auto split(D &&d)
Split distribution.
Definition: GaussianDistribution.hpp:918
constexpr bool index
An object describing a collection of /ref values::index objects.
Definition: index.hpp:75