TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
idx_map.hpp
Go to the documentation of this file.
1// Copyright (c) 2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2018-2023 Simons Foundation
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0.txt
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17// Authors: Thomas Hahn, Dominik Kiese, Henri Menke, Olivier Parcollet, Nils Wentzell
18
19/**
20 * @file
21 * @brief Provides a class that maps multi-dimensional indices to a linear index and vice versa.
22 */
23
24#pragma once
25
26#include "./permutation.hpp"
27#include "./range.hpp"
28#include "./slice_static.hpp"
29#include "../macros.hpp"
30#include "../traits.hpp"
31
32#include <algorithm>
33#include <array>
34#include <concepts>
35#include <cstdint>
36#include <cstdlib>
37#include <functional>
38#include <numeric>
39#include <stdexcept>
40#include <type_traits>
41#include <utility>
42#include <vector>
43
44namespace nda {
45
46 /**
47 * @addtogroup layout_idx
48 * @{
49 */
50
51 /**
52 * @brief Fortran/Column-major stride order.
53 * @details The first dimension varies the fastest, the last dimension the slowest.
54 * @tparam Rank Number of dimensions.
55 */
56 template <int Rank>
58
59 /**
60 * @brief C/Row-major stride order.
61 * @details The last dimension varies the fastest, the first dimension the slowest.
62 * @tparam Rank Number of dimensions.
63 */
64 template <int Rank>
66
67 /**
68 * @brief Layout that specifies how to map multi-dimensional indices to a linear/flat index.
69 *
70 * @details It stores the shape of the array, i.e. the length of each dimension, and the strides of each dimension.
71 * The stride of dimension `i` is the number of elements to skip in memory when the index of dimension `i` is
72 * incremented by one. For example:
73 * - To iterate over every element of a 5x5x5 array in C-order use the strides `(25, 5, 1)`.
74 * - To iterate over every 2nd element of a 1D array use the stride `(2)`.
75 * - To iterate over every 2nd column of a 10x10 array in Fortran-order use the strides `(1, 20)`.
76 * - To iterate over every 2nd row of a 10x10 array in Fortran-order use the strides `(2, 10)`.
77 *
78 * The template parameters `StaticExtents` and `StrideOrder` are encoded as `uint64_t`. They can be decoded to a
79 * `std::array<int, Rank>` using the nda::decode function. The encoding limits the number of dimensions, i.e. the
80 * rank, to 16.
81 *
82 * The static extent array specifies the length of each dimension at compile-time. A zero value means that the length
83 * in this dimension is dynamic and will be specified at runtime. Note that static lengths cannot exceed 16 (due to
84 * the encoding). For example:
85 * - `StaticExtents = nda::encode(std::array<int, Rank>{0, 10, 0, 5})` corresponds to a 4D array with dynamic extents
86 * in dimension 0 and 2, and static extents of length 10 and 5 in dimension 1 and 3, respectively.
87 *
88 * The stride order specifies the order in which the dimensions are stored in memory. In its array form, it can be any
89 * permutation of the integer values from `0` to `Rank - 1`. The slowest varying dimension is the first element of the
90 * array and the fastest varying dimension is the last element of the array. For example:
91 * - C-order: `StrideOrder = nda::encode(std::array<int, Rank>{0, 1, ..., Rank - 2, Rank - 1})`.
92 * - Fortran-order: `StrideOrder = nda::encode(std::array<int, Rank>{Rank - 1, Rank - 2, ..., 1, 0})`.
93 *
94 * `LayoutProp` is an enum flag that can be used to make further compile-time guarantees about the layout of the data
95 * in memory (see nda::layout_prop_e).
96 *
97 * @tparam Rank Number of dimensions.
98 * @tparam StaticExtent Compile-time known shape (zero if fully dynamic).
99 * @tparam StrideOrder Order in which the dimensions are stored in memory.
100 * @tparam LayoutProp Compile-time guarantees about the layout of the data in memory.
101 */
102 template <int Rank, uint64_t StaticExtents, uint64_t StrideOrder, layout_prop_e LayoutProp>
103 class idx_map {
104 static_assert(Rank < 16, "Error in nda::idx_map: Rank must be < 16");
105 static_assert((StrideOrder != 0) or (Rank == 1), "Error in nda::idx_map: StrideOrder can only be zero for 1D arrays");
106
107 // Extents of all dimensions (the shape of the map).
108 std::array<long, Rank> len;
109
110 // Strides of all dimensions.
111 std::array<long, Rank> str;
112
113 public:
114 /// Encoded static extents.
115 static constexpr uint64_t static_extents_encoded = StaticExtents;
116
117 /// Decoded static extents.
118 static constexpr std::array<int, Rank> static_extents = decode<Rank>(StaticExtents);
119
120 /// Decoded stride order.
121 static constexpr std::array<int, Rank> stride_order = (StrideOrder == 0 ? permutations::identity<Rank>() : decode<Rank>(StrideOrder));
122
123 /// Encoded stride order.
124 static constexpr uint64_t stride_order_encoded = encode(stride_order);
125
126 /// Compile-time memory layout properties.
127 static constexpr layout_prop_e layout_prop = LayoutProp;
128
129 /// Compile-time information about the layout (stride order and layout properties).
131
132 /// Alias template to check if type `T` can be used to access a single element.
133 template <typename T>
134 static constexpr int argument_is_allowed_for_call = std::is_constructible_v<long, T>;
135
136 /// Alias template to check if type `T` can be used to either access a single element or a slice of elements.
137 template <typename T>
140
141 protected:
142 /// Number of dynamic dimensions/extents.
143 static constexpr int n_dynamic_extents = []() {
144 int r = 0;
145 for (int u = 0; u < Rank; ++u) r += (static_extents[u] == 0 ? 1 : 0);
146 return r;
147 }();
148
149 public:
150 /**
151 * @brief Get the rank of the map.
152 * @return Number of dimensions.
153 */
154 static constexpr int rank() noexcept { return Rank; }
155
156 /**
157 * @brief Get the total number of elements.
158 * @return Product of the extents of all dimensions.
159 */
160 [[nodiscard]] long size() const noexcept { return std::accumulate(len.cbegin(), len.cend(), 1L, std::multiplies<>{}); }
161
162 /**
163 * @brief Get the size known at compile-time.
164 * @return Zero if it has at least one dynamic dimension, otherwise the product of the static extents.
165 */
166 static constexpr long ce_size() noexcept {
167 if constexpr (n_dynamic_extents != 0) {
168 return 0;
169 } else {
170 return std::accumulate(static_extents.cbegin(), static_extents.cend(), 1L, std::multiplies<>{});
171 }
172 }
173
174 /**
175 * @brief Get the extents of all dimensions.
176 * @return `std::array<long, Rank>` containing the extent of each dimension.
177 */
178 [[nodiscard]] std::array<long, Rank> const &lengths() const noexcept { return len; }
179
180 /**
181 * @brief Get the strides of all dimensions.
182 * @return `std::array<long, Rank>` containing the stride of each dimension.
183 */
184 [[nodiscard]] std::array<long, Rank> const &strides() const noexcept { return str; }
185
186 /**
187 * @brief Get the value of the smallest stride.
188 * @return Stride of the fastest varying dimension.
189 */
190 [[nodiscard]] long min_stride() const noexcept { return str[stride_order[Rank - 1]]; }
191
192 /**
193 * @brief Is the data contiguous in memory?
194 *
195 * @details The data is contiguous in memory if the size of the map is equal to the number of memory locations
196 * spanned by the map, i.e. the product of the largest stride times the length of the corresponding dimension.
197 *
198 * @return True if the data is contiguous in memory, false otherwise.
199 */
200 [[nodiscard]] bool is_contiguous() const noexcept {
201 auto s = size();
202 if (s == 0) return true;
203 auto const str_x_len = str * len;
204 return (*std::max_element(str_x_len.cbegin(), str_x_len.cend()) == s);
205 }
206
207 /**
208 * @brief Is the data strided in memory with a constant stride?
209 *
210 * @details The data is strided in memory with a constant stride if the size of the map times the stride of the
211 * fastest dimension with an extent bigger than 1 is equal to the number of memory locations spanned by the map,
212 * i.e. the product of the largest stride times the length of the corresponding dimension.
213 *
214 * @return True if the data is strided in memory with a constant stride, false otherwise.
215 */
216 [[nodiscard]] bool is_strided_1d() const noexcept {
217 auto s = size();
218 if (s == 0) return true;
219 auto const str_x_len = str * len;
220 return (*std::max_element(str_x_len.cbegin(), str_x_len.cend()) == s * min_stride());
221 }
222
223 /**
224 * @brief Is the stride order equal to C-order?
225 * @return True if the stride order is the identity permutation.
226 */
227 static constexpr bool is_stride_order_C() { return (stride_order == permutations::identity<Rank>()); }
228
229 /**
230 * @brief Is the stride order equal to Fortran-order?
231 * @return True if the stride order is the reverse identity permutation.
232 */
233 static constexpr bool is_stride_order_Fortran() { return (stride_order == permutations::reverse_identity<Rank>()); }
234
235 /**
236 * @brief Check if a given shape and strides are compatible with the stride order.
237 *
238 * @tparam Int Integer type.
239 * @param lenptr Pointer to a shape array.
240 * @param strptr Pointer to a stride array.
241 * @return True if the given shape and strides are compatible with the stride order.
242 */
243 template <std::integral Int>
244 [[nodiscard]] static bool is_stride_order_valid(Int *lenptr, Int *strptr) {
245 auto dims_to_check = std::vector<int>{};
246 dims_to_check.reserve(Rank);
247 for (auto dim : stride_order)
248 if (lenptr[dim] > 1) dims_to_check.push_back(dim);
249 for (int n = 1; n < dims_to_check.size(); ++n)
250 if (std::abs(strptr[dims_to_check[n - 1]]) < std::abs(strptr[dims_to_check[n]])) return false;
251 return true;
252 }
253
254 /**
255 * @brief Check if the shape and strides of the current map are compatible with its stride order.
256 * @details See idx_map::is_stride_order_valid(Int *lenptr, Int *strptr)).
257 * @return True if the shape and strides are compatible with the stride order.
258 */
259 [[nodiscard]] bool is_stride_order_valid() const { return is_stride_order_valid(len.data(), str.data()); }
260
261 private:
262 // Compute contiguous strides from the shape.
263 void compute_strides_contiguous() {
264 long s = 1;
265 for (int v = rank() - 1; v >= 0; --v) {
266 int u = stride_order[v];
267 str[u] = s;
268 s *= len[u];
269 }
270 ENSURES(s == size());
271 }
272
273 // Check that the static extents and the shape are compatible.
274 void assert_static_extents_and_len_are_compatible() const {
275#ifdef NDA_ENFORCE_BOUNDCHECK
276 if constexpr (n_dynamic_extents != Rank) {
277#ifndef NDEBUG
278 for (int u = 0; u < Rank; ++u)
279 if (static_extents[u] != 0) EXPECTS(static_extents[u] == len[u]);
280#endif
281 }
282#endif
283 }
284
285 // Should we check the stride order when constructing an idx_map from a shape and strides?
286#ifdef NDA_DEBUG
287 static constexpr bool check_stride_order = true;
288#else
289 static constexpr bool check_stride_order = false;
290#endif
291
292 // Combine static and dynamic extents.
293 static std::array<long, Rank> merge_static_and_dynamic_extents(std::array<long, n_dynamic_extents> const &dynamic_extents) {
294 std::array<long, Rank> extents;
295 for (int u = 0, v = 0; u < Rank; ++u) extents[u] = (static_extents[u] == 0 ? dynamic_extents[v++] : static_extents[u]);
296 return extents;
297 }
298
299 // FIXME ADD A CHECK layout_prop_e ... compare to stride and
300
301 public:
302 /**
303 * @brief Default constructor.
304 *
305 * @details For purely static maps, the shape is set to the static extents and the strides are assumed to be
306 * contiguous.
307 *
308 * For all other maps, the shape is set to zero and the strides are not initialized.
309 */
311 if constexpr (n_dynamic_extents == 0) {
312 for (int u = 0; u < Rank; ++u) len[u] = static_extents[u];
313 compute_strides_contiguous();
314 } else {
315 for (int u = 0; u < Rank; ++u)
316 len[u] = 0; // FIXME. Needed ? To have the proper invariant of the array : shape = (0,0,...) and pointer is null
317 }
318 }
319
320 /**
321 * @brief Construct a new map from an existing map with different layout properties.
322 *
323 * @tparam LP Layout properties of the other nda::idx_map.
324 * @param idxm Other nda::idx_map object.
325 */
326 template <layout_prop_e LP>
327 idx_map(idx_map<Rank, StaticExtents, StrideOrder, LP> const &idxm) noexcept : len(idxm.lengths()), str(idxm.strides()) {
328 // check strides and stride order of the constructed map
329 EXPECTS(is_stride_order_valid());
330
331 // check that the layout properties are compatible
332 if constexpr (not layout_property_compatible(LP, layout_prop)) {
333 if constexpr (has_contiguous(layout_prop)) {
334 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(), "Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
335 }
336 if constexpr (has_strided_1d(layout_prop)) {
337 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(), "Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
338 }
339 }
340 }
341
342 /**
343 * @brief Construct a new map from an existing map with different layout properties and different static extents.
344 *
345 * @tparam SE Static extents of the other nda::idx_map.
346 * @tparam LP Layout properties of the other nda::idx_map.
347 * @param idxm Other nda::idx_map object.
348 */
349 template <uint64_t SE, layout_prop_e LP>
350 idx_map(idx_map<Rank, SE, StrideOrder, LP> const &idxm) noexcept(false) : len(idxm.lengths()), str(idxm.strides()) {
351 // check strides and stride order
352 EXPECTS(is_stride_order_valid());
353
354 // check that the layout properties are compatible
355 if constexpr (not layout_property_compatible(LP, LayoutProp)) {
356 if constexpr (has_contiguous(LayoutProp)) {
357 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(), "Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
358 }
359 if constexpr (has_strided_1d(LayoutProp)) {
360 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(), "Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
361 }
362 }
363
364 // check that the static extents and the shape are compatible
365 assert_static_extents_and_len_are_compatible();
366 }
367
368 /**
369 * @brief Construct a new map from a given shape and strides.
370 *
371 * @param shape Shape of the new map.
372 * @param strides Strides of the new map.
373 */
374 idx_map(std::array<long, Rank> const &shape, // NOLINT (only throws if check_stride_order is true)
375 std::array<long, Rank> const &strides) noexcept(!check_stride_order)
376 : len(shape), str(strides) {
377 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](auto const &i) { return i >= 0; }));
378 if constexpr (check_stride_order) {
379 if (not is_stride_order_valid()) throw std::runtime_error("Error in nda::idx_map: Incompatible strides, shape and stride order");
380 }
381 }
382
383 /**
384 * @brief Construct a new map from a given shape and with contiguous strides.
385 *
386 * @tparam Int Integer type.
387 * @param shape Shape of the new map.
388 */
389 template <std::integral Int = long>
390 idx_map(std::array<Int, Rank> const &shape) noexcept : len(stdutil::make_std_array<long>(shape)) {
391 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](auto const &i) { return i >= 0; }));
392 assert_static_extents_and_len_are_compatible();
393 compute_strides_contiguous();
394 }
395
396 /**
397 * @brief Construct a new map from an array with its dynamic extents.
398 *
399 * @details The missing extents are taken from the static extents, i.e. if a static extent is zero, it is replaced
400 * by the corresponding dynamic extent.
401 *
402 * @param shape std::array with the dynamic extents only.
403 */
404 idx_map(std::array<long, n_dynamic_extents> const &shape) noexcept
405 requires((n_dynamic_extents != Rank) and (n_dynamic_extents != 0))
406 : idx_map(merge_static_and_dynamic_extents(shape)) {}
407
408 /**
409 * @brief Construct a new map from an existing map with a different stride order.
410 *
411 * @warning This constructor is deleted.
412 *
413 * @tparam SE Static extents of the other nda::idx_map.
414 * @tparam SO Stride order of the other nda::idx_map.
415 * @tparam LP Layout properties of the other nda::idx_map.
416 */
417 template <uint64_t SE, uint64_t SO, layout_prop_e LP>
418 idx_map(idx_map<Rank, SE, SO, LP> const &)
419 requires(stride_order_encoded != SO)
420 {
421 static_assert((stride_order_encoded == SO), "Error in nda::idx_map: Incompatible stride orders");
422 }
423
424 /**
425 * @brief Construct a new map with a shape of a different rank.
426 * @warning This constructor is deleted.
427 * @tparam R Rank of the given shape.
428 */
429 template <int R>
430 idx_map(std::array<long, R> const &)
431 requires(R != Rank)
432 {
433 static_assert(R == Rank, "Error in nda::idx_map: Incompatible ranks");
434 }
435
436 /// Default copy constructor.
437 idx_map(idx_map const &) = default;
438
439 /// Default move constructor.
440 idx_map(idx_map &&) = default;
441
442 /// Default copy assignment operator.
443 idx_map &operator=(idx_map const &) = default;
444
445 /// Default move assignment operator.
446 idx_map &operator=(idx_map &&) = default;
447
448 private:
449 // Get the contribution to the linear index in case of an nda::ellipsis argument.
450 template <bool skip_stride, auto I>
451 [[nodiscard]] FORCEINLINE long myget(ellipsis) const noexcept {
452 // nda::ellipsis are skipped and do not contribute to the linear index
453 return 0;
454 }
455
456 // Get the contribution to the linear index in case of a long argument.
457 template <bool skip_stride, auto I>
458 [[nodiscard]] FORCEINLINE long myget(long arg) const noexcept {
459 if constexpr (skip_stride and (I == stride_order[Rank - 1])) {
460 // optimize for the case when the fastest varying dimension is contiguous in memory
461 return arg;
462 } else {
463 // otherwise multiply the argument by the stride of the current dimension
464 return arg * std::get<I>(str);
465 }
466 }
467
468 // Is the smallest stride equal to one, i.e. is the fastest varying dimension contiguous in memory?
469 static constexpr bool smallest_stride_is_one = has_smallest_stride_is_one(layout_prop);
470
471 // Implementation of the function call operator that takes a multi-dimensional index and maps it to a linear index.
472 template <typename... Args, size_t... Is>
473 [[nodiscard]] FORCEINLINE long call_impl(std::index_sequence<Is...>, Args... args) const noexcept {
474 // set e_pos to the position of the ellipsis, otherwise to -1
475 static constexpr int e_pos = ((std::is_same_v<Args, ellipsis> ? int(Is) + 1 : 0) + ...) - 1;
476
477 if constexpr (e_pos == -1) {
478 // no ellipsis present
479 if constexpr (smallest_stride_is_one) {
480 // optimize for the case that the fastest varying dimension is contiguous in memory
481 return (myget<true, Is>(static_cast<long>(args)) + ...);
482 } else {
483 // arbitrary layouts
484 return ((args * std::get<Is>(str)) + ...);
485 }
486 } else {
487 // empty ellipsis is present and needs to be skipped
488 return (myget<smallest_stride_is_one, (Is < e_pos ? Is : Is - 1)>(args) + ...);
489 }
490 }
491
492 public:
493 /**
494 * @brief Function call operator to map a given multi-dimensional index to a linear index.
495 *
496 * @details All arguments are either convertible to type `long` or are of type nda::ellipsis. The number of
497 * non-ellipsis arguments must be equal to the rank of the map and there must be at most one nda::ellipsis. If an
498 * nda::ellipsis is present, it is skipped and does not influence the result.
499 *
500 * Let \f$ (a_0, ..., a_{n-1}) \f$ be the given multi-dimensional index and let \f$ (s_0, ..., s_{n-1}) \f$ be the
501 * strides of the index map. Then the equation that maps the multi-dimensional index to the corresponding linear
502 * index \f$ f \f$ is as follows:
503 * \f[
504 * f = \sum_{i=0}^{n-1} a_i * s_i \; .
505 * \f]
506 *
507 * @tparam Args Types of the arguments.
508 * @param args Multi-dimensional index.
509 * @return Linear/Flat index.
510 */
511 template <typename... Args>
512 FORCEINLINE long operator()(Args const &...args) const
513#ifdef NDA_ENFORCE_BOUNDCHECK
514 noexcept(false) {
516#else
517 noexcept(true) {
518#endif
519 return call_impl(std::make_index_sequence<sizeof...(Args)>{}, args...);
520 }
521
522 /**
523 * @brief Calculate the multi-dimensional index from a given linear index.
524 *
525 * @details Let \f$ f \f$ be the given linear index and let \f$ (s_0, ..., s_{n-1}) \f$ be the strides of the index
526 * map. Then the corresponding multi-dimensional index \f$ (a_0, ..., a_{n-1}) \f$ satisfies the following equation:
527 * \f[
528 * f = \sum_{i=0}^{n-1} a_i * s_i \; .
529 * \f]
530 *
531 * Furthermore, if \f$ (p_0, ..., p_{n-1}) \f$ is the stride order of the map, let us define the residues
532 * \f$ r_{p_i} \f$ as
533 * \f[
534 * r_{p_i} = \sum_{j=i}^{n-1} s_{p_j} * a_{p_j} \; ,
535 * \f]
536 * with the property that \f$ s_{p_i} \leq r_{p_i} < s_{p_{i-1}} \f$ for \f$ i = 1, ..., n-1 \f$ and \f$ s_{p_0}
537 * \leq r_{p_0} = f \f$. We can use this property to first calculate the residues and then recover the
538 * multi-dimensional index.
539 *
540 * @param lin_idx Linear/Flat index.
541 * @return Multi-dimensional index.
542 */
543 std::array<long, Rank> to_idx(long lin_idx) const {
544 // compute residues starting from slowest index
545 std::array<long, Rank> residues;
546 residues[0] = lin_idx;
547 for (auto i : range(1, Rank)) { residues[i] = residues[i - 1] % str[stride_order[i - 1]]; }
548
549 // convert residues to indices, ordered from slowest to fastest
550 std::array<long, Rank> idx;
551 idx[Rank - 1] = residues[Rank - 1] / str[stride_order[Rank - 1]];
552 for (auto i : range(Rank - 2, -1, -1)) { idx[i] = (residues[i] - residues[i + 1]) / str[stride_order[i]]; }
553
554 // reorder indices according to stride order
555 return permutations::apply_inverse(stride_order, idx);
556 }
557
558 /**
559 * @brief Get a new nda::idx_map by taking a slice of the current one.
560 *
561 * @details See nda::slice_static::slice_idx_map for more information.
562 *
563 * @tparam Args Types of the arguments.
564 * @param args Multi-dimensional index consisting of `long`, `nda::range`, `nda::range::all_t` or nda::ellipsis
565 * objects.
566 * @return A std::pair containing the offset in memory, i.e. the flat index of the first element of the slice and
567 * the new nda::idx_map.
568 */
569 template <typename... Args>
570 auto slice(Args const &...args) const {
571 return slice_static::slice_idx_map(*this, args...);
572 }
573
574 /**
575 * @brief Equal-to operator for two nda::idx_map objects.
576 *
577 * @tparam R Rank of the other nda::idx_map.
578 * @tparam SE Static extents of the other nda::idx_map.
579 * @tparam SO Stride order of the other nda::idx_map.
580 * @tparam LP Layout properties of the other nda::idx_map.
581 * @param rhs Right hand side nda::idx_map operand.
582 * @return True if their ranks, shapes and strides are equal.
583 */
584 template <int R, uint64_t SE, uint64_t SO, layout_prop_e LP>
585 bool operator==(idx_map<R, SE, SO, LP> const &rhs) const {
586 return (Rank == R and len == rhs.lengths() and str == rhs.strides());
587 }
588
589 /**
590 * @brief Create a new map by permuting the indices/dimensions of the current map with a given permutation.
591 *
592 * @details Let `A` be the current and ``A'`` the new, permuted index map. `P` is the given permutation. We define
593 * the permuted nda::idx_map ``A'`` to be the one with the following properties:
594 * - ``A'(i_0,...,i_{n-1}) = A(i_{P[0]},...,i_{P[n-1]})``
595 * - ``A'.lengths()[k] == A.lengths()[P^{-1}[k]]``
596 * - ``A'.strides()[k] == A.strides()[P^{-1}[k]]``
597 * - The stride order of ``A'`` is the composition of `P` and the stride order of `A` (note that the stride order
598 * itself is a permutation).
599 *
600 * @tparam Permutation Permutation to apply.
601 * @return New nda::idx_map with permuted indices.
602 */
603 template <uint64_t Permutation>
604 auto transpose() const {
605 // Makes a new transposed idx_map with permutation P such that
606 // denoting here A = this, A' = P A = returned_value
607 // A'(i_k) = A(i_{P[k]})
608 //
609 // Note that this convention is the correct one to have a (left) action of the symmetric group on
610 // a array and it may not be completely obvious.
611 // Proof
612 // let's operate with P then Q, and denote A'' = Q A'. We want to show that A'' = (QP) A
613 // A'(i_k) = A(i_{P[k]})
614 // A''(j_k) = A'(j_{Q[k]})
615 // then i_k = j_{Q[k]} and A''(j_k) = A(i_{P[k]}) = A(j_{Q[P[k]]}) = A(j_{(QP)[k]}), q.e.d
616 //
617 // NB test will test this composition
618 // Denoting this as A, an indexmap, calling it returns the linear index given by
619 //
620 // A(i_k) = sum_k i_k * S[k] (1)
621 //
622 // where S[k] denotes the strides.
623 //
624 // 1- S' : strides of A'
625 // A'(i_k) = sum_k i_{P[k]} * S[k] = sum_k i_k * S[P{^-1}[k]]
626 // so
627 // S'[k] = S[P{^-1}[k]] (2)
628 // i.e. apply (inverse(P), S) or apply_inverse directly.
629 //
630 // 2- L' : lengths of A'
631 // if L[k] is the k-th length, then because of the definition of A', i.e. A'(i_k) = A(i_{P[k]})
632 // i_q in the lhs A is at position q' such that P[q'] = q (A'(i0 i1 i2...) = A( i_P0 i_P1 i_P2....)
633 // hence L'[q] = L[q'] = L[P^{-1}[q]]
634 // same for static length
635 //
636 // 3- stride_order: denoted in this paragraph as Q (and Q' for A').
637 // by definition Q is a permutation such that Q[0] is the slowest index, Q[Rank -1] the fastest
638 // hence S[Q[k]] is a strictly decreasing sequence (as checked by strides_compatible_to_stride_order)
639 // we want therefore Q' the permutation that will sort the S', i.e.
640 // S'[Q'[k]] = S[Q[k]]
641 // using (2), we have S[P{^-1}[Q'[k]]] = S[Q[k]]
642 // so the permutation Q' is such that P{^-1}Q' = Q or Q' = PQ (as permutation product/composition).
643 // NB : Q and P are permutations, so the operation must be a composition, not an apply (apply applies
644 // a P to any set, like L, S, not only a permutation) even though they are all std::array in the code ...
645 //
646 static constexpr std::array<int, Rank> permu = decode<Rank>(Permutation);
647 static constexpr std::array<int, Rank> new_stride_order = permutations::compose(permu, stride_order);
648 static constexpr std::array<int, Rank> new_static_extents = permutations::apply_inverse(permu, static_extents);
649
650 return idx_map<Rank, encode(new_static_extents), encode(new_stride_order), LayoutProp>{permutations::apply_inverse(permu, lengths()),
651 permutations::apply_inverse(permu, strides())};
652 }
653 };
654
655 /** @} */
656
657} // namespace nda
void swap(nda::basic_array_view< V1, R1, LP1, A1, AP1, OP1 > &a, nda::basic_array_view< V2, R2, LP2, A2, AP2, OP2 > &b)=delete
std::swap is deleted for nda::basic_array_view.
Iterator for nda::basic_array and nda::basic_array_view types.
A generic view of a multi-dimensional array.
basic_array_view(A &&a) noexcept
Generic constructor from any nda::MemoryArray type.
const_iterator end() const noexcept
Get a const iterator to the end of the view/array.
ValueType const * data() const noexcept
Get a pointer to the actual data (in general this is not the beginning of the memory block for a view...
static constexpr bool is_stride_order_C() noexcept
Is the stride order of the view/array in C-order?
iterator begin() noexcept
Get an iterator to the beginning of the view/array.
ValueType * data() noexcept
Get a pointer to the actual data (in general this is not the beginning of thr memory block for a view...
basic_array_view & operator=(RHS const &rhs) noexcept
Assignment operator makes a deep copy of the contents of an nda::ArrayOfRank object.
auto & operator/=(RHS const &rhs) noexcept
Division assignment operator.
static constexpr int rank
Number of dimensions of the view.
decltype(auto) operator[](T const &idx) const &noexcept(has_no_boundcheck)
Subscript operator to access the 1-dimensional view/array.
auto const & shape() const noexcept
Get the shape of the view/array.
static __inline__ decltype(auto) call(Self &&self, Ts const &...idxs) noexcept(has_no_boundcheck)
Implementation of the function call operator.
basic_array_view(layout_t const &idxm, ValueType *p) noexcept
Construct a view from a bare pointer to some contiguous data and a memory layout.
__inline__ decltype(auto) operator()(Ts const &...idxs) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator()(Ts const &...) const &.
decltype(auto) operator[](T const &x) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator[](T const &) const &.
basic_array_view(R &rg) noexcept
Construct a 1-dimensional view of a general contiguous range.
basic_array_view & operator=(basic_array_view const &rhs) noexcept
Copy assignment operator makes a deep copy of the contents of the view.
basic_array_view(std::array< ValueType, N > &a) noexcept
Construct a 1-dimensional view of a std::array.
auto const & strides() const noexcept
Get the strides of the view/array (see nda::idx_map for more details on how we define strides).
long shape(int i) const noexcept
storage_t storage() &&noexcept
Get the data storage of the view/array.
decltype(auto) operator[](T const &x) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator[](T const &) const &.
decltype(auto) operator()(_linear_index_t idx) noexcept
Non-const overload of nda::basic_array_view::operator()(_linear_index_t) const.
auto & operator+=(RHS const &rhs) noexcept
Addition assignment operator.
auto indices() const noexcept
Get a range that generates all valid index tuples.
basic_array_view()=default
Default constructor constructs an empty view with a default constructed memory handle and layout.
long is_contiguous() const noexcept
Is the memory layout of the view/array contiguous?
auto & operator=(R const &rhs) noexcept
Assignment operator makes a deep copy of a general contiguous range and assigns it to the 1-dimension...
storage_t & storage() &noexcept
Get the data storage of the view/array.
static constexpr bool is_stride_order_Fortran() noexcept
Is the stride order of the view/array in Fortran-order?
decltype(auto) operator()(_linear_index_t idx) const noexcept
Access the element of the view/array at the given nda::_linear_index_t.
__inline__ decltype(auto) operator()(Ts const &...idxs) const &noexcept(has_no_boundcheck)
Function call operator to access the view/array.
auto & operator*=(RHS const &rhs) noexcept
Multiplication assignment operator.
basic_array_view(std::array< std::remove_const_t< ValueType >, N > const &a) noexcept
Construct a 1-dimensional view of a std::array.
friend void deep_swap(basic_array_view a, basic_array_view b) noexcept
Swap two views by swapping their data.
iterator end() noexcept
Get an iterator to the end of the view/array.
long size() const noexcept
Get the total size of the view/array.
auto & operator-=(RHS const &rhs) noexcept
Subtraction assignment operator.
bool empty() const
Is the view/array empty?
basic_array_view(std::array< long, Rank > const &shape, ValueType *p) noexcept
Construct a view from a bare pointer to some contiguous data and a shape.
bool is_empty() const noexcept
friend void swap(basic_array_view &a, basic_array_view &b) noexcept
Swap two views by swapping their memory handles and layouts.
constexpr auto stride_order() const noexcept
Get the stride order of the memory layout of the view/array (see nda::idx_map for more details on how...
const_iterator cbegin() const noexcept
Get a const iterator to the beginning of the view/array.
basic_array_view(layout_t const &idxm, storage_t st)
Construct a view from a given layout and memory handle.
static constexpr int iterator_rank
Rank of the nda::array_iterator for the view/array.
basic_array_view(basic_array_view &&)=default
Default move constructor moves the memory handle and layout.
void rebind(basic_array_view< T, R, LP, A, AP, OP > v) noexcept
Rebind the current view to another view.
basic_array_view(basic_array_view const &)=default
Default copy constructor copies the memory handle and layout.
__inline__ decltype(auto) operator()(Ts const &...idxs) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator()(Ts const &...) const &.
long extent(int i) const noexcept
Get the extent of the ith dimension.
constexpr auto const & indexmap() const noexcept
Get the memory layout of the view/array.
const_iterator begin() const noexcept
Get a const iterator to the beginning of the view/array.
const_iterator cend() const noexcept
Get a const iterator to the end of the view/array.
storage_t const & storage() const &noexcept
Get the data storage of the view/array.
A generic multi-dimensional array.
auto & operator+=(RHS const &rhs) noexcept
Addition assignment operator.
decltype(auto) operator[](T const &idx) const &noexcept(has_no_boundcheck)
Subscript operator to access the 1-dimensional view/array.
basic_array(basic_array< ValueType, 2, LayoutPolicy, A2, ContainerPolicy > &&a) noexcept
Construct a 2-dimensional array from another 2-dimensional array with a different algebra.
basic_array & operator=(RHS const &rhs)
Assignment operator makes a deep copy of an nda::ArrayOfRank object.
static constexpr bool is_stride_order_Fortran() noexcept
Is the stride order of the view/array in Fortran-order?
ValueType const * data() const noexcept
Get a pointer to the actual data (in general this is not the beginning of the memory block for a view...
ValueType * data() noexcept
Get a pointer to the actual data (in general this is not the beginning of thr memory block for a view...
long shape(int i) const noexcept
const_iterator cbegin() const noexcept
Get a const iterator to the beginning of the view/array.
static constexpr int rank
Number of dimensions of the array.
static constexpr bool is_stride_order_C() noexcept
Is the stride order of the view/array in C-order?
storage_t & storage() &noexcept
Get the data storage of the view/array.
basic_array(basic_array< ValueType, Rank, LayoutPolicy, A, CP > a) noexcept
Construct an array from another array with a different algebra and/or container policy.
auto const & strides() const noexcept
Get the strides of the view/array (see nda::idx_map for more details on how we define strides).
basic_array(Ints... is)
Construct an array with the given dimensions.
static basic_array ones(Ints... is)
Make a one-initialized array with the given dimensions.
const_iterator begin() const noexcept
Get a const iterator to the beginning of the view/array.
auto as_array_view() const
Convert the current array to a view with an 'A' (array) algebra.
long extent(int i) const noexcept
Get the extent of the ith dimension.
basic_array(std::initializer_list< ValueType > const &l)
Construct a 1-dimensional array from an initializer list.
decltype(auto) operator[](T const &x) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator[](T const &) const &.
long is_contiguous() const noexcept
Is the memory layout of the view/array contiguous?
basic_array(std::initializer_list< std::initializer_list< ValueType > > const &l2)
Construct a 2-dimensional array from a double nested initializer list.
decltype(auto) operator()(_linear_index_t idx) noexcept
Non-const overload of nda::basic_array_view::operator()(_linear_index_t) const.
__inline__ decltype(auto) operator()(Ts const &...idxs) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator()(Ts const &...) const &.
bool empty() const
Is the view/array empty?
void resize(std::array< long, Rank > const &shape)
Resize the array to a new shape.
basic_array(Int sz, RHS const &val)
Construct a 1-dimensional array with the given size and initialize each element to the given scalar v...
static basic_array ones(std::array< Int, Rank > const &shape)
Make a one-initialized array with the given shape.
constexpr auto stride_order() const noexcept
Get the stride order of the memory layout of the view/array (see nda::idx_map for more details on how...
auto & operator/=(RHS const &rhs) noexcept
Division assignment operator.
auto as_array_view()
Convert the current array to a view with an 'A' (array) algebra.
basic_array(A const &a)
Construct an array from an nda::ArrayOfRank object with the same rank by copying each element.
static basic_array zeros(Ints... is)
Make a zero-initialized array with the given dimensions.
auto indices() const noexcept
Get a range that generates all valid index tuples.
static __inline__ decltype(auto) call(Self &&self, Ts const &...idxs) noexcept(has_no_boundcheck)
Implementation of the function call operator.
void resize(Ints const &...is)
Resize the array to a new shape.
storage_t storage() &&noexcept
Get the data storage of the view/array.
basic_array()
Default constructor constructs an empty array with a default constructed memory handle and layout.
bool is_empty() const noexcept
auto & operator=(R const &rhs) noexcept
Assignment operator makes a deep copy of a general contiguous range and assigns it to the 1-dimension...
storage_t const & storage() const &noexcept
Get the data storage of the view/array.
basic_array & operator=(basic_array const &)=default
Default copy assignment copies the memory handle and layout from the right hand side array.
basic_array & operator=(basic_array< ValueType, Rank, LayoutPolicy, A, CP > const &rhs)
Assignment operator makes a deep copy of another array with a different algebra and/or container poli...
basic_array(basic_array const &a)=default
Default copy constructor copies the memory handle and layout.
basic_array(std::initializer_list< std::initializer_list< std::initializer_list< ValueType > > > const &l3)
Construct a 3-dimensional array from a triple nested initializer list.
iterator begin() noexcept
Get an iterator to the beginning of the view/array.
basic_array(layout_t const &layout)
Construct an array with the given memory layout.
static basic_array rand(Ints... is)
Make a random-initialized array with the given dimensions.
basic_array(layout_t const &layout, storage_t &&storage) noexcept
Construct an array with the given memory layout and with an existing memory handle/storage.
static constexpr int iterator_rank
Rank of the nda::array_iterator for the view/array.
auto & operator-=(RHS const &rhs) noexcept
Subtraction assignment operator.
const_iterator end() const noexcept
Get a const iterator to the end of the view/array.
basic_array(basic_array &&)=default
Default move constructor moves the memory handle and layout.
__inline__ decltype(auto) operator()(Ts const &...idxs) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator()(Ts const &...) const &.
basic_array(std::array< Int, Rank > const &shape)
Construct an array with the given shape.
const_iterator cend() const noexcept
Get a const iterator to the end of the view/array.
auto const & shape() const noexcept
Get the shape of the view/array.
long size() const noexcept
Get the total size of the view/array.
decltype(auto) operator[](T const &x) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator[](T const &) const &.
auto & operator*=(RHS const &rhs) noexcept
Multiplication assignment operator.
basic_array & operator=(basic_array &&)=default
Default move assignment moves the memory handle and layout from the right hand side array.
static basic_array zeros(std::array< Int, Rank > const &shape)
Make a zero-initialized array with the given shape.
__inline__ decltype(auto) operator()(Ts const &...idxs) const &noexcept(has_no_boundcheck)
Function call operator to access the view/array.
constexpr auto const & indexmap() const noexcept
Get the memory layout of the view/array.
iterator end() noexcept
Get an iterator to the end of the view/array.
decltype(auto) operator()(_linear_index_t idx) const noexcept
Access the element of the view/array at the given nda::_linear_index_t.
static basic_array rand(std::array< Int, Rank > const &shape)
Make a random-initialized array with the given shape.
Layout that specifies how to map multi-dimensional indices to a linear/flat index.
Definition idx_map.hpp:103
__inline__ long operator()(Args const &...args) const noexcept(true)
Function call operator to map a given multi-dimensional index to a linear index.
Definition idx_map.hpp:512
static constexpr std::array< int, Rank > stride_order
Decoded stride order.
Definition idx_map.hpp:121
idx_map(idx_map< Rank, StaticExtents, StrideOrder, LP > const &idxm) noexcept
Construct a new map from an existing map with different layout properties.
Definition idx_map.hpp:327
static bool is_stride_order_valid(Int *lenptr, Int *strptr)
Check if a given shape and strides are compatible with the stride order.
Definition idx_map.hpp:244
static constexpr layout_info_t layout_info
Compile-time information about the layout (stride order and layout properties).
Definition idx_map.hpp:130
idx_map(idx_map &&)=default
Default move constructor.
long size() const noexcept
Get the total number of elements.
Definition idx_map.hpp:160
long min_stride() const noexcept
Get the value of the smallest stride.
Definition idx_map.hpp:190
idx_map(std::array< long, n_dynamic_extents > const &shape) noexcept
Construct a new map from an array with its dynamic extents.
Definition idx_map.hpp:404
auto transpose() const
Create a new map by permuting the indices/dimensions of the current map with a given permutation.
Definition idx_map.hpp:604
std::array< long, Rank > to_idx(long lin_idx) const
Calculate the multi-dimensional index from a given linear index.
Definition idx_map.hpp:543
bool is_stride_order_valid() const
Check if the shape and strides of the current map are compatible with its stride order.
Definition idx_map.hpp:259
idx_map(idx_map< Rank, SE, SO, LP > const &)
Construct a new map from an existing map with a different stride order.
Definition idx_map.hpp:418
bool operator==(idx_map< R, SE, SO, LP > const &rhs) const
Equal-to operator for two nda::idx_map objects.
Definition idx_map.hpp:585
static constexpr bool is_stride_order_C()
Is the stride order equal to C-order?
Definition idx_map.hpp:227
static constexpr int n_dynamic_extents
Number of dynamic dimensions/extents.
Definition idx_map.hpp:143
static constexpr uint64_t stride_order_encoded
Encoded stride order.
Definition idx_map.hpp:124
static constexpr int rank() noexcept
Get the rank of the map.
Definition idx_map.hpp:154
static constexpr std::array< int, Rank > static_extents
Decoded static extents.
Definition idx_map.hpp:118
bool is_strided_1d() const noexcept
Is the data strided in memory with a constant stride?
Definition idx_map.hpp:216
static constexpr int argument_is_allowed_for_call_or_slice
Alias template to check if type T can be used to either access a single element or a slice of element...
Definition idx_map.hpp:138
idx_map(std::array< Int, Rank > const &shape) noexcept
Construct a new map from a given shape and with contiguous strides.
Definition idx_map.hpp:390
std::array< long, Rank > const & lengths() const noexcept
Get the extents of all dimensions.
Definition idx_map.hpp:178
auto slice(Args const &...args) const
Get a new nda::idx_map by taking a slice of the current one.
Definition idx_map.hpp:570
static constexpr bool is_stride_order_Fortran()
Is the stride order equal to Fortran-order?
Definition idx_map.hpp:233
idx_map(idx_map const &)=default
Default copy constructor.
static constexpr int argument_is_allowed_for_call
Alias template to check if type T can be used to access a single element.
Definition idx_map.hpp:134
static constexpr long ce_size() noexcept
Get the size known at compile-time.
Definition idx_map.hpp:166
bool is_contiguous() const noexcept
Is the data contiguous in memory?
Definition idx_map.hpp:200
idx_map(idx_map< Rank, SE, StrideOrder, LP > const &idxm) noexcept(false)
Construct a new map from an existing map with different layout properties and different static extent...
Definition idx_map.hpp:350
idx_map(std::array< long, Rank > const &shape, std::array< long, Rank > const &strides) noexcept(!check_stride_order)
Construct a new map from a given shape and strides.
Definition idx_map.hpp:374
idx_map()
Default constructor.
Definition idx_map.hpp:310
std::array< long, Rank > const & strides() const noexcept
Get the strides of all dimensions.
Definition idx_map.hpp:184
idx_map & operator=(idx_map const &)=default
Default copy assignment operator.
static constexpr layout_prop_e layout_prop
Compile-time memory layout properties.
Definition idx_map.hpp:127
static constexpr uint64_t static_extents_encoded
Encoded static extents.
Definition idx_map.hpp:115
idx_map & operator=(idx_map &&)=default
Default move assignment operator.
idx_map(std::array< long, R > const &)
Construct a new map with a shape of a different rank.
Definition idx_map.hpp:430
#define CUSOLVER_CHECK(X, info,...)
#define NDA_RUNTIME_ERROR
auto rand(std::array< Int, Rank > const &shape)
Make an array of the given shape and initialize it with random values from the uniform distribution o...
decltype(auto) make_regular(A &&a)
Make a given object regular.
void resize_or_check_if_view(A &a, std::array< long, A::rank > const &sha)
Resize a given regular array to the given shape or check if a given view as the correct shape.
decltype(auto) to_unified(A &&a)
Convert an nda::MemoryArray to its regular type on unified memory.
auto make_const_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::basic_array_view with a const value type from a given nda::basic_array.
auto zeros(Ints... is)
Make an array of the given shape on the given address space and zero-initialize it.
auto zeros(std::array< Int, Rank > const &shape)
Make an array of the given shape on the given address space and zero-initialize it.
auto rand(Ints... is)
Make an array of the given dimensions and initialize it with random values from the uniform distribut...
auto arange(long first, long last, long step=1)
Make a 1-dimensional integer array and initialize it with values of a given nda::range.
decltype(auto) to_host(A &&a)
Convert an nda::MemoryArray to its regular type on host memory.
auto make_matrix_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::matrix_view of a given nda::basic_array_view.
auto arange(long last)
Make a 1-dimensional integer array and initialize it with values of a given nda::range with a step si...
auto make_matrix_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::matrix_view of a given nda::basic_array.
auto ones(Ints... is)
Make an array with the given dimensions and one-initialize it.
auto make_const_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::basic_array_view with a const value type from a given nda::basic_array_view.
decltype(auto) to_device(A &&a)
Convert an nda::MemoryArray to its regular type on device memory.
auto make_array_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::array_view of a given nda::basic_array.
auto make_array_const_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::array_const_view of a given nda::basic_array.
auto ones(std::array< Int, Rank > const &shape)
Make an array of the given shape and one-initialize it.
auto make_array_const_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::array_const_view of a given nda::basic_array_view.
auto make_array_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::array_view of a given nda::basic_array_view.
auto concatenate(A0 const &a0, As const &...as)
Join a sequence of nda::Array types along an existing axis.
long first_dim(A const &a)
Get the extent of the first dimension of the array.
constexpr bool is_view_v< basic_array_view< ValueType, Rank, Layout, Algebra, AccessorPolicy, OwningPolicy > >
Specialization of nda::is_view_v for nda::basic_array_view.
constexpr bool is_regular_v< basic_array< ValueType, Rank, Layout, Algebra, ContainerPolicy > >
Specialization of nda::is_regular_v for nda::basic_array.
constexpr char get_algebra< basic_array_view< ValueType, Rank, Layout, Algebra, AccessorPolicy, OwningPolicy > >
Specialization of nda::get_algebra for nda::basic_array_view types.
constexpr char get_algebra< basic_array< ValueType, Rank, Layout, Algebra, ContainerPolicy > >
Specialization of nda::get_algebra for nda::basic_array types.
constexpr uint64_t static_extents(int i0, Is... is)
Encode the given shape into a single integer using the nda::encode function.
constexpr char get_algebra< expr_unary< OP, A > >
Specialization of nda::get_algebra for nda::expr_unary types.
bool operator==(LHS const &lhs, RHS const &rhs)
Equal-to comparison operator for two nda::Array objects.
long second_dim(A const &a)
Get the extent of the second dimension of the array.
constexpr char get_algebra< expr< OP, L, R > >
Specialization of nda::get_algebra for nda::expr types.
__inline__ void clef_auto_assign(expr< tags::terminal, T > const &ex, RHS &&rhs)
Overload of clef_auto_assign function for terminal expressions.
__inline__ void clef_auto_assign(std::reference_wrapper< T > wrapper, RHS &&rhs)
Overload of clef_auto_assign function for std::reference_wrapper objects.
__inline__ void operator<<(expr< tags::function, F, placeholder< Is >... > const &ex, RHS &&rhs)
Assign values to the underlying object of a lazy function call expression.
__inline__ void clef_auto_assign_subscript(std::reference_wrapper< T > wrapper, RHS &&rhs)
Overload of clef_auto_assign_subscript function for std::reference_wrapper objects.
__inline__ void clef_auto_assign_subscript(expr< Tag, Childs... > const &ex, RHS const &rhs)
Overload of clef_auto_assign_subscript function for generic expressions.
__inline__ void clef_auto_assign_subscript(expr< tags::terminal, T > const &ex, RHS &&rhs)
Overload of clef_auto_assign_subscript function for terminal expressions.
__inline__ void clef_auto_assign(expr< Tag, Childs... > const &ex, RHS const &rhs)
Overload of clef_auto_assign function for generic expressions.
void clef_auto_assign(A &&a, F &&f)
Overload of nda::clef::clef_auto_assign function for nda::Array objects.
__inline__ void operator<<(expr< tags::subscript, T, placeholder< Is >... > const &ex, RHS &&rhs)
Assign values to the underlying object of a lazy subscript expression.
__inline__ decltype(auto) eval(T const &obj, Pairs &&...pairs)
Generic function to evaluate expressions and other types.
Definition eval.hpp:197
__inline__ auto make_function(T &&obj, Phs...)
Factory function for nda::clef::make_fun_impl objects.
Definition function.hpp:100
__inline__ auto if_else(C &&c, A &&a, B &&b)
Create a lazy ternary (if-else) expression.
#define CLEF_OPERATION(TAG, OP)
auto make_expr(T &&t)
Create a terminal expression node of an object.
Definition make_lazy.hpp:45
__inline__ auto op_dispatch(std::true_type, Args &&...args)
Dispatch operations containing at least one lazy operand.
__inline__ decltype(auto) op_dispatch(std::false_type, Args &&...args)
Dispatch operations containing only non-lazy operands.
auto make_expr_subscript(T &&t, Args &&...args)
Create a subscript expression from an object and a list of arguments.
Definition make_lazy.hpp:93
auto make_expr_call(F &&f, Args &&...args)
Create a function call expression from a callable object and a list of arguments.
Definition make_lazy.hpp:74
auto make_expr_from_clone(T &&t)
Create a terminal expression node of an object.
Definition make_lazy.hpp:57
constexpr bool is_clef_expression
Alias template for nda::clef::is_any_lazy.
Definition utils.hpp:161
constexpr bool is_lazy
Constexpr variable that is true if the type T is a lazy type.
Definition utils.hpp:153
constexpr bool force_copy_in_expr
Constexpr variable that is true if objects of type T should be forced to be copied into an expression...
Definition utils.hpp:137
constexpr bool is_function
Constexpr variable that is true if the type T is an nda::clef::make_fun_impl type.
Definition utils.hpp:165
constexpr bool is_any_lazy
Constexpr variable that is true if any of the given types is lazy.
Definition utils.hpp:157
constexpr uint64_t C_stride_order
C/Row-major stride order.
Definition idx_map.hpp:65
constexpr uint64_t Fortran_stride_order
Fortran/Column-major stride order.
Definition idx_map.hpp:57
constexpr bool layout_property_compatible(layout_prop_e from, layout_prop_e to)
Checks if two layout properties are compatible with each other.
Definition traits.hpp:237
constexpr bool has_contiguous(layout_prop_e lp)
Checks if a layout property has the contiguous property.
Definition traits.hpp:282
constexpr bool has_strided_1d(layout_prop_e lp)
Checks if a layout property has the strided_1d property.
Definition traits.hpp:266
auto get_block_layout(A const &a)
Check if a given nda::MemoryArray has a block-strided layout.
constexpr bool has_smallest_stride_is_one(layout_prop_e lp)
Checks if a layout property has the smallest_stride_is_one property.
Definition traits.hpp:274
layout_prop_e
Compile-time guarantees of the memory layout of an array/view.
Definition traits.hpp:222
AddressSpace
Enum providing identifiers for the different memory address spaces.
static constexpr do_not_initialize_t do_not_initialize
Instance of nda::mem::do_not_initialize_t.
Definition handle.hpp:69
static constexpr init_zero_t init_zero
Instance of nda::mem::init_zero_t.
Definition handle.hpp:75
constexpr uint64_t encode(std::array< int, N > const &a)
Encode a std::array<int, N> in a uint64_t.
#define EXPECTS(X)
Definition macros.hpp:59
#define FORCEINLINE
Definition macros.hpp:41
#define EXPECTS_WITH_MESSAGE(X,...)
Definition macros.hpp:75
#define ENSURES(X)
Definition macros.hpp:69
#define AS_STRING(...)
Definition macros.hpp:31
#define ASSERT(X)
Definition macros.hpp:64
Contiguous layout policy with C-order (row-major order).
Definition policies.hpp:47
Strided (non-contiguous) layout policy with C-order (row-major order).
Definition policies.hpp:79
A small wrapper around a single long integer to be used as a linear index.
Definition traits.hpp:343
long value
Linear index.
Definition traits.hpp:345
Generic layout policy with arbitrary order.
Definition policies.hpp:115
Memory policy using an nda::mem::handle_borrowed.
Definition policies.hpp:108
static constexpr bool is_lazy
Constexpr variable that is true if any of the evaluators of the child nodes is lazy.
Definition eval.hpp:150
__inline__ decltype(auto) operator()(expr< Tag, Childs... > const &ex, Pairs &...pairs) const
Evaluate the given expression by applying the given nda::clef::pair objects.
Definition eval.hpp:170
__inline__ decltype(auto) operator()(make_fun_impl< T, Is... > const &f, Pairs &...pairs) const
Evaluate the nda::clef::make_fun_impl object.
Definition function.hpp:133
static constexpr bool is_lazy
Constexpr variable that is true if all the placeholders are assigned a value.
Definition function.hpp:120
static constexpr bool is_lazy
Constexpr variable that is true if the there is no nda::clef::pair containing an nda::clef::placehold...
Definition eval.hpp:92
__inline__ decltype(auto) operator()(placeholder< N >, pair< Is, Ts > &...pairs) const
Evaluate the placeholder.
Definition eval.hpp:101
static constexpr bool is_lazy
Constexpr variable that is always false.
Definition eval.hpp:126
__inline__ decltype(auto) operator()(std::reference_wrapper< T > const &wrapper, Pairs const &...pairs) const
Evaluate the std::reference_wrapper by redirecting the evaluation to the object contained in the wrap...
Definition eval.hpp:135
Generic evaluator for types which do not have a specialized evaluator.
Definition eval.hpp:55
__inline__ T const & operator()(T const &t, Pairs &...) const
Evaluate the object and ignore all given nda::clef::pair objects.
Definition eval.hpp:65
static constexpr bool is_lazy
Constexpr variable that is true if the type T is lazy.
Definition eval.hpp:57
Single node of the expression tree.
expr & operator=(expr const &)=delete
Copy assignment operator is deleted.
expr(expr &&ex) noexcept
Move constructor simply moves the child nodes from the source expression.
auto operator[](Args &&...args) const
Subscript operator.
expr & operator=(expr &&)=default
Default move assignment operator.
expr(expr const &)=default
Default copy constructor.
expr(Tag, Us &&...us)
Construct an expression node with a given tag and child nodes.
childs_t childs
Child nodes of the current expression node.
auto operator()(Args &&...args) const
Function call operator.
Helper struct to simplify calls to nda::clef::eval.
Definition function.hpp:52
T obj
Object to be evaluated.
Definition function.hpp:54
__inline__ decltype(auto) operator()(Args &&...args) const
Function call operator.
Definition function.hpp:68
__inline__ decltype(auto) operator()(F &&f, Args &&...args) const
Perform a function call operation.
Definition operation.hpp:95
__inline__ A operator()(C const &c, A const &a, B const &b) const
Perform a ternary (if-else) operation.
__inline__ decltype(auto) operator()(F &&f, Args &&...args) const
Perform a subscript operation.
__inline__ L operator()(L &&l) const
Perform a terminal operation.
Definition operation.hpp:77
A pair consisting of a placeholder and its assigned value.
T rhs
Value assigned to the placeholder (can be an lvalue reference).
static constexpr int p
Integer label of the placeholder.
A placeholder is an empty struct, labelled by an int.
static constexpr int index
Integer label.
auto operator[](T &&t) const
Subscript operator.
pair< N, RHS > operator=(RHS &&rhs) const
Assign a value to the placeholder.
auto operator()(Args &&...args) const
Function call operator.
Tag for binary operator expressions.
Tag for function call expressions.
Tag for conditional expressions.
Tag for subscript expressions.
Tag to indicate a terminal node in the expression tree.
Tag for unary operator expressions.
Accessor type of the nda::default_accessor.
Definition accessors.hpp:42
static __inline__ T * offset(pointer p, std::ptrdiff_t i) noexcept
Offset the pointer by a certain number of elements.
Definition accessors.hpp:71
static __inline__ reference access(pointer p, std::ptrdiff_t i) noexcept
Access a specific element of the data.
Definition accessors.hpp:59
Default accessor for various array and view types.
Definition accessors.hpp:36
Mimics Python's ... syntax.
Definition range.hpp:49
Lazy unary expression for nda::Array types.
Lazy binary expression for nda::ArrayOrScalar types.
Stores information about the memory layout and the stride order of an array/view.
Definition traits.hpp:295
Tag used in constructors to indicate that the memory should be initialized to zero.
Definition handle.hpp:72
Accessor type of the nda::no_alias_accessor.
Definition accessors.hpp:82
static __inline__ reference access(pointer p, std::ptrdiff_t i) noexcept
Access a specific element of the data.
Definition accessors.hpp:99
static __inline__ T * offset(pointer p, std::ptrdiff_t i) noexcept
Offset the pointer by a certain number of elements.
Accessor for array and view types with no aliasing.
Definition accessors.hpp:76
Memory policy using an nda::mem::handle_stack.
Definition policies.hpp:84