TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
group_indices.hpp
Go to the documentation of this file.
1// Copyright (c) 2019--present, The Simons Foundation
2// This file is part of TRIQS/nda and is licensed under the Apache License, Version 2.0.
3// SPDX-License-Identifier: Apache-2.0
4// See LICENSE in the root of this distribution for details.
5
10
11#pragma once
12
13#include "./layout/idx_map.hpp"
15#include "./stdutil/array.hpp"
16#include "./traits.hpp"
17
18#include <algorithm>
19#include <array>
20#include <cstddef>
21#include <cstdint>
22#include <numeric>
23#include <stdexcept>
24
25namespace nda {
26
27 namespace detail {
28
29 // Check if given integer arrays correspond to a partition of the set `J = {0, 1, ..., R-1}`.
30 template <size_t R, size_t... Rs>
31 constexpr bool is_partition_of_indices(std::array<int, Rs> const &...grps) {
32 // check that the total number of array elements is equal to R
33 constexpr auto Rstot = (Rs + ...);
34 static_assert(Rstot == R, "Error in nda::detail::is_partition_of_indices: Number of indices has to be equal to the rank");
35
36 // check that every element of J is in one and only one group
37 auto count = stdutil::make_initialized_array<R>(0); // FIXME : not necessary in C++20
38 auto l = [&](auto &&grp) mutable -> void {
39 for (int u = 0; u < grp.size(); ++u) {
40 if (grp[u] < 0) throw std::runtime_error("Error in nda::detail::is_partition_of_indices: Negative indices are not allowed");
41 if (grp[u] >= R) throw std::runtime_error("Error in nda::detail::is_partition_of_indices: Indices larger than the rank are not allowed");
42 count[grp[u]]++;
43 }
44 };
45 (l(grps), ...);
46
47 return (count == stdutil::make_initialized_array<R>(1));
48 }
49
50 // Given an original stride order and a partition of the indices, determine the new stride order of the grouped
51 // nda::idx_map.
52 template <size_t R, size_t... Rs>
53 constexpr std::array<int, sizeof...(Rs)> stride_order_of_grouped_idx_map(std::array<int, R> const &stride_order,
54 std::array<int, Rs> const &...grps) {
55 // inverse permutation of the stride order
56 auto mem_pos = permutations::inverse(stride_order);
57
58 // check if the indices/dimensions in a group are consecutive in memory and find the slowest varying index within
59 // the group
60 auto min_mem_pos = [&mem_pos](auto &&grp) {
61 int min = R, max = 0;
62 for (int idx : grp) {
63 int v = mem_pos[idx];
64 if (v > max) max = v;
65 if (v < min) min = v;
66 }
67 bool idx_are_consecutive_in_memory = (max - min + 1 == grp.size());
68 if (!idx_are_consecutive_in_memory)
69 throw std::runtime_error("Error in nda::detail::stride_order_of_grouped_idx_map: Indices are not consecutive in memory");
70 return min;
71 };
72
73 // number of groups in the partition
74 constexpr int Ngrps = sizeof...(Rs);
75
76 // array containing the slowest varying index within each group
77 std::array<int, Ngrps> min_mem_positions{min_mem_pos(grps)...};
78
79 // rank each group by its slowest varying index, i.e. the slowest group gets rank 0 and the fastest rank Ngrps-1
80 std::array<int, Ngrps> mem_pos_out = stdutil::make_initialized_array<Ngrps>(0); // FIXME : not necessary in C++20
81 for (int u = 0; u < Ngrps; ++u) {
82 for (int i = 0; i < Ngrps; ++i) {
83 if (min_mem_positions[i] < min_mem_positions[u]) ++mem_pos_out[u];
84 }
85 }
86
87 // the new stride order is the inverse of mem_pos_out
88 return permutations::inverse(mem_pos_out);
89 }
90
91 } // namespace detail
92
97
102 template <int... Is>
103 struct idx_group_t {
105 static constexpr std::array<int, sizeof...(Is)> as_std_array{Is...};
106 };
107
112 template <int... Is>
113 inline idx_group_t<Is...> idx_group = {}; // NOLINT (global variable template is what we want here)
114
145 template <int Rank, uint64_t StaticExtents, uint64_t StrideOrder, layout_prop_e LayoutProp, typename... IdxGrps>
147 // compile-time checks
148 static_assert(LayoutProp == layout_prop_e::contiguous, "Error in nda::group_indices_layout: Only contiguous layouts are supported");
149 static_assert(detail::is_partition_of_indices<Rank>(IdxGrps::as_std_array...),
150 "Error in nda::group_indices_layout: Given index groups are not a valid partition");
151
152 // decoded original stride order
154
155 // number of elements in a group
156 auto total_len_of_a_grp = [&idxm](auto &&grp) {
157 return std::accumulate(grp.begin(), grp.end(), 1L, [&idxm](long l, long u) { return l * idxm.lengths()[u]; });
158 };
159
160 // minimum stride of a group
161 auto min_stride_of_a_grp = [&idxm](auto &&grp) {
162 return std::accumulate(grp.begin(), grp.end(), idxm.size(), [&idxm](long s, long u) { return std::min(s, idxm.strides()[u]); });
163 };
164
165 // new rank, shape, strides and stride order
166 static constexpr int new_rank = sizeof...(IdxGrps);
167 std::array<long, new_rank> new_extents{total_len_of_a_grp(IdxGrps::as_std_array)...};
168 std::array<long, new_rank> new_strides{min_stride_of_a_grp(IdxGrps::as_std_array)...};
169 constexpr auto new_stride_order = encode(detail::stride_order_of_grouped_idx_map(stride_order, IdxGrps::as_std_array...));
170
172 }
173
175
176} // namespace nda
Provides utility functions for std::array.
Layout that specifies how to map multi-dimensional indices to a linear/flat index.
Definition idx_map.hpp:90
static constexpr std::array< int, Rank > stride_order
Decoded stride order.
Definition idx_map.hpp:108
long size() const noexcept
Get the total number of elements.
Definition idx_map.hpp:147
idx_group_t< Is... > idx_group
Variable template for an nda::idx_group_t.
layout_prop_e
Compile-time guarantees of the memory layout of an array/view.
Definition traits.hpp:211
auto group_indices_layout(idx_map< Rank, StaticExtents, StrideOrder, LayoutProp > const &idxm, IdxGrps...)
Given an nda::idx_map and a partition of its indices, return a new nda::idx_map with the grouped indi...
constexpr std::array< Int, N > inverse(std::array< Int, N > const &p)
Inverse of a permutation.
constexpr uint64_t encode(std::array< int, N > const &a)
Encode a std::array<int, N> in a uint64_t.
constexpr std::array< T, R > make_initialized_array(T v)
Create a new std::array object initialized with a specific value.
Definition array.hpp:155
Provides a class that maps multi-dimensional indices to a linear index and vice versa.
Provides utilities to work with permutations and to compactly encode/decode std::array objects.
A group of indices.
static constexpr std::array< int, sizeof...(Is)> as_std_array
std::array containing the indices.
Provides type traits for the nda library.