OpenKalman
tile.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_TILE_HPP
17 #define OPENKALMAN_TILE_HPP
18 
19 namespace OpenKalman
20 {
21  // ====== //
22  // tile //
23  // ====== //
24 
25  namespace detail
26  {
27  template<std::size_t direction, typename...Index, std::size_t...dims, typename Arg>
28  constexpr void tile_impl(std::tuple<Index...>& current_position, std::tuple<Index...>& current_block_size,
29  std::index_sequence<dims...>, Arg& arg) {}
30 
31 
32  template<std::size_t direction, typename...Index, std::size_t...dims, typename Arg, typename Block, typename...Blocks>
33  constexpr void tile_impl(std::tuple<Index...>& current_position, std::tuple<Index...>& current_block_size,
34  std::index_sequence<dims...> seq, Arg& arg, Block&& block, Blocks&&...blocks)
35  {
36 
37  if constexpr (direction == 0) ((std::get<dims>(current_block_size) = get_index_dimension_of<dims>(block)),...);
38 
39  auto& cur_pos = std::get<direction>(current_position);
40  auto dim_direction = get_index_dimension_of<direction>(arg);
41 
42  if constexpr (direction == sizeof...(dims) - 1)
43  {
44  set_slice(arg, std::forward<Block>(block), std::get<dims>(current_position)...);
45 
46  if (cur_pos > 0 and ((dims != direction and get_index_dimension_of<dims>(block) != std::get<dims>(current_block_size)) or ...))
47  throw std::length_error {"Block argument to tile function is not the right tile size."};
48 
49  cur_pos += get_index_dimension_of<direction>(block);
50 
51  if (cur_pos < dim_direction)
52  {
53  tile_impl<direction>(current_position, current_block_size, seq, arg, std::forward<Blocks>(blocks)...);
54  }
55  else if (cur_pos == dim_direction)
56  {
57  constexpr std::size_t new_direction = direction - 1;
58  cur_pos = 0;
59  std::get<new_direction>(current_position) += get_index_dimension_of<new_direction>(block);
60  tile_impl<new_direction>(current_position, current_block_size, seq, arg, std::forward<Blocks>(blocks)...);
61  }
62  else // cur_pos > dim_direction
63  {
64  throw std::length_error {"Block argument to tile function is too large in dimension " + std::to_string(direction) + "."};
65  }
66  }
67  else
68  {
69  static_assert((direction < sizeof...(dims) - 1));
70  std::get<direction>(current_block_size) = get_index_dimension_of<direction>(block);
71 
72  if (cur_pos < dim_direction)
73  {
74  tile_impl<direction + 1>(current_position, current_block_size, seq, arg, std::forward<Block>(block), std::forward<Blocks>(blocks)...);
75  }
76  else
77  {
78  if constexpr (direction > 0)
79  {
80  if (cur_pos > dim_direction) throw std::length_error {
81  "Block argument to tile function is too large in dimension " + std::to_string(direction) + "."};
82  constexpr std::size_t new_direction = direction - 1;
83  cur_pos = 0;
84  std::get<new_direction>(current_position) += get_index_dimension_of<new_direction>(block);
85  tile_impl<new_direction>(current_position, current_block_size, seq, arg, std::forward<Block>(block), std::forward<Blocks>(blocks)...);
86  }
87  else
88  {
89  throw std::length_error {"Tile function has too many blocks to fit within specified vector space descriptors."};
90  }
91  }
92  }
93  }
94  } // namespace detail
95 
96 
103 #ifdef __cpp_concepts
104  template<coordinates::pattern...Ds, indexible Block, indexible...Blocks>
105  requires (sizeof...(Ds) >= std::max({index_count_v<Block>, index_count_v<Blocks>...}))
106 #else
107  template<typename...Ds, typename Block, typename...Blocks, std::enable_if_t<
108  (coordinates::pattern<Ds> and ...) and (indexible<Block> and ... and indexible<Blocks>) and
109  (sizeof...(Ds) >= std::max({index_count<Block>::value, index_count<Blocks>::value...})), int> = 0>
110 #endif
111  constexpr decltype(auto) tile(const std::tuple<Ds...>& ds_tuple, Block&& block, Blocks&&...blocks)
112  {
113  if constexpr (sizeof...(Blocks) == 0)
114  {
115  return std::forward<Block>(block);
116  }
117  else
118  {
119  auto m = make_dense_object<Block>(ds_tuple);
120  auto current_position = std::tuple{(coordinates::pattern<Ds> ? std::size_t(0) : std::size_t(-1))...};
121  decltype(current_position) current_block_size;
122 
123  detail::tile_impl<0>(current_position, current_block_size, std::index_sequence_for<Ds...> {}, m, block, blocks...);
124  return m;
125  }
126  }
127 
128 
129 } // namespace OpenKalman
130 
131 #endif //OPENKALMAN_TILE_HPP
decltype(auto) constexpr tile(const std::tuple< Ds... > &ds_tuple, Block &&block, Blocks &&...blocks)
Create a matrix or tensor by tiling individual blocks.
Definition: tile.hpp:111
constexpr bool indexible
T is a generalized tensor type.
Definition: indexible.hpp:32
Definition: tuple_reverse.hpp:103
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
The root namespace for OpenKalman.
Definition: basics.hpp:34
constexpr Arg && set_slice(Arg &&arg, Block &&block, const Begin &...begin)
Assign an object to a particular slice of a matrix or tensor.
Definition: set_slice.hpp:56