initializer_list.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2015 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifndef TILEDARRAY_INITIALIZER_LIST_UTILS_H__INCLUDED
21 #define TILEDARRAY_INITIALIZER_LIST_UTILS_H__INCLUDED
22 #include <TiledArray/tiled_range.h>
24 #include <TiledArray/type_traits.h>
25 #include <algorithm> // copy
26 #include <array> // array
27 #include <initializer_list> // initializer_list
28 #include <type_traits> // decay, false_type, true_type
29 
36 namespace TiledArray {
37 
38 //------------------------------------------------------------------------------
39 // InitializerListRank Struct
40 //------------------------------------------------------------------------------
41 
55 template <typename T, typename SizeType = std::size_t>
56 struct InitializerListRank : std::integral_constant<SizeType, 0> {};
57 
70 template <typename T, typename SizeType = std::size_t>
71 constexpr auto initializer_list_rank_v =
73 
87 template <typename T, typename SizeType>
88 struct InitializerListRank<std::initializer_list<T>, SizeType>
89  : std::integral_constant<SizeType,
90  initializer_list_rank_v<T, SizeType> + 1> {};
91 
92 //------------------------------------------------------------------------------
93 // tiled_range_from_il free function
94 //------------------------------------------------------------------------------
95 
128 template <typename T,
129  typename U =
130  std::array<TiledRange1, initializer_list_rank_v<std::decay_t<T>>>>
131 auto tiled_range_from_il(T&& il, U shape = {}) {
132  using clean_type = std::decay_t<T>;
133  constexpr auto ranks_left = initializer_list_rank_v<clean_type>;
134 
135  if constexpr (ranks_left == 0) { // Scalar or end of recursion
136  return TiledRange(shape.begin(), shape.end());
137  } else {
138  // The length of this initializer_list
139  const auto length = il.size();
140  TA_ASSERT(length > 0);
141 
142  // This nesting level = (total-nestings) - (nestings-left)
143  const auto this_rank = shape.size() - ranks_left;
144  shape[this_rank] = TiledRange1(0, length);
145 
146  // verify that each sub-IL (if a list) has same length
147  const auto first_sub_il_it = il.begin();
148  if constexpr (detail::is_initializer_list_v<
149  std::decay_t<decltype(*first_sub_il_it)>>) {
150  auto sub_il_it = il.begin();
151  [[maybe_unused]] const size_t sub_il_length = sub_il_it->size();
152  for (++sub_il_it; sub_il_it != il.end(); ++sub_il_it) {
153  TA_ASSERT(sub_il_it->size() == sub_il_length);
154  }
155  }
156 
157  return tiled_range_from_il(*first_sub_il_it, std::move(shape));
158  }
159  abort(); // unreachable
160 }
161 
162 //------------------------------------------------------------------------------
163 // flatten_il free function
164 //------------------------------------------------------------------------------
165 
204 template <typename T, typename OutputItr>
205 auto flatten_il(T&& il, OutputItr out_itr) {
206  constexpr auto ranks_left = initializer_list_rank_v<std::decay_t<T>>;
207 
208  // We were given a scalar, just copy its value
209  // (input of std::initializer_list ends recursion on ranks_left == 1)
210  if constexpr (ranks_left == 0) {
211  *out_itr = il;
212  ++out_itr;
213  }
214  // We were given a vector or we have recursed to the most nested
215  // initializer_list, either way copy the contents to the buffer
216  else if constexpr (ranks_left == 1) {
217  out_itr = std::copy(il.begin(), il.end(), out_itr);
218  }
219  // The initializer list is at least a matrix, so recurse over sub-lists
220  else {
221  const auto length = il.begin()->size();
222  for (auto&& x : il) {
223  TA_ASSERT(x.size() == length); // sub-lists must be the same size
224  out_itr = flatten_il(x, out_itr);
225  }
226  }
227  return out_itr;
228 }
229 
230 //------------------------------------------------------------------------------
231 // get_elem_from_il free function
232 //------------------------------------------------------------------------------
233 
258 template <typename T, typename U>
259 auto get_elem_from_il(T idx, U&& il, std::size_t depth = 0) {
260  constexpr auto nestings_left = initializer_list_rank_v<std::decay_t<U>>;
261  TA_ASSERT(idx.size() == nestings_left + depth);
262  if constexpr (nestings_left == 0) { // Handle scalars
263  return il;
264  } else {
265  // Make sure the current nesting is long enough
266  TA_ASSERT(il.size() > static_cast<std::size_t>(idx[depth]));
267  auto itr = il.begin() + idx[depth];
268  if constexpr (nestings_left == 1) {
269  return *itr;
270  } else {
271  return get_elem_from_il(std::forward<T>(idx), *itr, depth + 1);
272  }
273  }
274  abort(); // unreachable
275 }
276 
277 //------------------------------------------------------------------------------
278 // array_from_il free function
279 //------------------------------------------------------------------------------
280 
314 template <typename ArrayType, typename T>
315 auto array_from_il(World& world, const TiledRange& trange, T&& il) {
316  using tile_type = typename ArrayType::value_type;
317 
318  static_assert(initializer_list_rank_v<std::decay_t<T>> > 0,
319  "value initializing rank 0 tensors is not supported");
320 
321  ArrayType rv(world, trange);
322 
323  for (auto itr = rv.begin(); itr != rv.end(); ++itr) {
324  auto range = rv.trange().make_tile_range(itr.index());
325  tile_type tile(range);
326  for (auto idx : range) {
327  tile(idx) = get_elem_from_il(idx, il);
328  }
329  *itr = tile;
330  }
331  return rv;
332 }
333 
366 template <typename ArrayType, typename T>
367 auto array_from_il(World& world, T&& il) {
368  auto trange = tiled_range_from_il(il);
369  return array_from_il<ArrayType, T>(world, std::move(trange),
370  std::forward<T>(il));
371 }
372 
373 namespace detail {
374 
375 // Typedef of an initializer list for a vector
376 template <typename T>
377 using vector_il = std::initializer_list<T>;
378 
379 // Typedef of an initializer list for a matrix
380 template <typename T>
381 using matrix_il = std::initializer_list<vector_il<T>>;
382 
383 // Typedef of an il for a rank 3 tensor
384 template <typename T>
385 using tensor3_il = std::initializer_list<matrix_il<T>>;
386 
387 // Typedef of an il for a rank 4 tensor
388 template <typename T>
389 using tensor4_il = std::initializer_list<tensor3_il<T>>;
390 
391 // Typedef of an il for a rank 5 tensor
392 template <typename T>
393 using tensor5_il = std::initializer_list<tensor4_il<T>>;
394 
395 // Typedef of an il for a rank 6 tensor
396 template <typename T>
397 using tensor6_il = std::initializer_list<tensor5_il<T>>;
398 
399 } // namespace detail
400 
401 } // namespace TiledArray
402 
403 #endif // TILEDARRAY_INITIALIZER_LIST_UTILS_H__INCLUDED
auto get_elem_from_il(T idx, U &&il, std::size_t depth=0)
Retrieves the specified element from an initializer_list.
std::initializer_list< T > vector_il
std::initializer_list< tensor4_il< T > > tensor5_il
auto array_from_il(World &world, const TiledRange &trange, T &&il)
Converts an std::initializer_list into a tiled array.
constexpr auto initializer_list_rank_v
Helper variable for retrieving the degree of nesting for an std::initializer_list.
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
auto flatten_il(T &&il, OutputItr out_itr)
Flattens the contents of a (possibly nested) initializer_list into the provided buffer.
Range data of a tiled array.
Definition: tiled_range.h:32
std::initializer_list< tensor5_il< T > > tensor6_il
std::initializer_list< matrix_il< T > > tensor3_il
auto tiled_range_from_il(T &&il, U shape={})
Creates a TiledRange for the provided initializer list.
std::initializer_list< vector_il< T > > matrix_il
std::initializer_list< tensor3_il< T > > tensor4_il
Primary template for determining how many nested std::initializer_list's are in a type.