TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
basic_functions.hpp
Go to the documentation of this file.
1// Copyright (c) 2019-2024 Simons Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0.txt
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Authors: Dominik Kiese, Miguel Morales, Olivier Parcollet, Nils Wentzell
16
22#pragma once
23
24#include "./clef/clef.hpp"
25#include "./declarations.hpp"
26#include "./exceptions.hpp"
27#include "./layout/for_each.hpp"
29#include "./traits.hpp"
30
31#include <itertools/itertools.hpp>
32
33#include <array>
34#include <concepts>
35#include <optional>
36#include <random>
37#include <tuple>
38#include <type_traits>
39#include <utility>
40
41namespace nda {
42
60 template <typename T, mem::AddressSpace AdrSp = mem::Host, std::integral Int, auto Rank>
61 auto zeros(std::array<Int, Rank> const &shape) {
62 static_assert(AdrSp != mem::None);
63 if constexpr (Rank == 0)
64 return T{};
65 else if constexpr (AdrSp == mem::Host)
66 return array<T, Rank>::zeros(shape);
67 else
68 return cuarray<T, Rank>::zeros(shape);
69 }
70
82 template <typename T, mem::AddressSpace AdrSp = mem::Host, std::integral... Ints>
83 auto zeros(Ints... is) {
84 return zeros<T, AdrSp>(std::array<long, sizeof...(Ints)>{static_cast<long>(is)...});
85 }
86
98 template <typename T, std::integral Int, auto Rank>
99 auto ones(std::array<Int, Rank> const &shape)
100 requires(nda::is_scalar_v<T>)
101 {
102 if constexpr (Rank == 0)
103 return T{1};
104 else { return array<T, Rank>::ones(shape); }
105 }
106
117 template <typename T, std::integral... Ints>
118 auto ones(Ints... is) {
119 return ones<T>(std::array<long, sizeof...(Ints)>{is...});
120 }
121
131 template <std::integral Int = long>
132 auto arange(long first, long last, long step = 1) {
133 auto r = range(first, last, step);
134 auto a = array<Int, 1>(r.size());
135 for (auto [x, v] : itertools::zip(a, r)) x = v;
136 return a;
137 }
138
147 template <std::integral Int = long>
148 auto arange(long last) {
149 return arange<Int>(0, last);
150 }
151
164 template <typename RealType = double, std::integral Int, auto Rank>
165 auto rand(std::array<Int, Rank> const &shape)
166 requires(std::is_floating_point_v<RealType>)
167 {
168 if constexpr (Rank == 0) {
169 auto static gen = std::mt19937{};
170 auto static dist = std::uniform_real_distribution<>{0.0, 1.0};
171 return dist(gen);
172 } else {
173 return array<RealType, Rank>::rand(shape);
174 }
175 }
176
188 template <typename RealType = double, std::integral... Ints>
189 auto rand(Ints... is) {
190 return rand<RealType>(std::array<long, sizeof...(Ints)>{is...});
191 }
192
203 template <Array A>
204 long first_dim(A const &a) {
205 return a.extent(0);
206 }
207
218 template <Array A>
219 long second_dim(A const &a) {
220 return a.extent(1);
221 }
222
237 template <typename A, typename A_t = std::decay_t<A>>
238 decltype(auto) make_regular(A &&a) {
239 if constexpr (Array<A> and not is_regular_v<A>) {
240 return basic_array{std::forward<A>(a)};
241 } else if constexpr (requires { typename A_t::regular_t; }) {
242 if constexpr (not std::is_same_v<A_t, typename A_t::regular_t>)
243 return typename A_t::regular_t{std::forward<A>(a)};
244 else
245 return std::forward<A>(a);
246 } else {
247 return std::forward<A>(a);
248 }
249 }
250
260 template <MemoryArray A>
261 decltype(auto) to_host(A &&a) {
262 if constexpr (not mem::on_host<A>) {
263 return get_regular_host_t<A>{std::forward<A>(a)};
264 } else {
265 return std::forward<A>(a);
266 }
267 }
268
278 template <MemoryArray A>
279 decltype(auto) to_device(A &&a) {
280 if constexpr (not mem::on_device<A>) {
281 return get_regular_device_t<A>{std::forward<A>(a)};
282 } else {
283 return std::forward<A>(a);
284 }
285 }
286
296 template <MemoryArray A>
297 decltype(auto) to_unified(A &&a) {
298 if constexpr (not mem::on_unified<A>) {
299 return get_regular_unified_t<A>{std::forward<A>(a)};
300 } else {
301 return std::forward<A>(a);
302 }
303 }
304
317 template <typename A>
318 void resize_or_check_if_view(A &a, std::array<long, A::rank> const &sha)
320 {
321 if (a.shape() == sha) return;
322 if constexpr (is_regular_v<A>) {
323 a.resize(sha);
324 } else {
325 NDA_RUNTIME_ERROR << "Error in nda::resize_or_check_if_view: Size mismatch: " << a.shape() << " != " << sha;
326 }
327 }
328
341 template <typename T, int R, typename LP, char A, typename CP>
345
359 template <typename T, int R, typename LP, char A, typename AP, typename OP>
363
376 template <typename T, int R, typename LP, char A, typename CP>
378 return array_view<T, R>{a};
379 }
380
394 template <typename T, int R, typename LP, char A, typename AP, typename OP>
398
411 template <typename T, int R, typename LP, char A, typename CP>
415
429 template <typename T, int R, typename LP, char A, typename AP, typename OP>
433
446 template <typename T, int R, typename LP, char A, typename CP>
450
464 template <typename T, int R, typename LP, char A, typename AP, typename OP>
468
479 template <Array LHS, Array RHS>
480 bool operator==(LHS const &lhs, RHS const &rhs) {
481 // FIXME not implemented in clang
482#ifndef __clang__
483 static_assert(std::equality_comparable_with<get_value_t<LHS>, get_value_t<RHS>>,
484 "Error in nda::operator==: Only defined when elements are comparable");
485#endif
486 if (lhs.shape() != rhs.shape()) return false;
487 bool r = true;
488 nda::for_each(lhs.shape(), [&](auto &&...x) { r &= (lhs(x...) == rhs(x...)); });
489 return r;
490 }
491
502 template <ArrayOfRank<1> A, std::ranges::contiguous_range R>
503 bool operator==(A const &a, R const &rg) {
504 return a == basic_array_view{rg};
505 }
506
517 template <std::ranges::contiguous_range R, ArrayOfRank<1> A>
518 bool operator==(R const &rg, A const &a) {
519 return a == rg;
520 }
521
531 template <Array A, typename F>
532 void clef_auto_assign(A &&a, F &&f) { // NOLINT (Should we forward the references?)
533 nda::for_each(a.shape(), [&a, &f](auto &&...x) {
534 if constexpr (clef::is_function<std::decay_t<decltype(f(x...))>>) {
535 clef_auto_assign(a(x...), f(x...));
536 } else {
537 a(x...) = f(x...);
538 }
539 });
540 }
541
559 template <MemoryArray A>
560 auto get_block_layout(A const &a) {
561 EXPECTS(!a.empty());
562 using opt_t = std::optional<std::tuple<int, int, int>>;
563
564 auto const &shape = a.indexmap().lengths();
565 auto const &strides = a.indexmap().strides();
566 auto const &order = a.indexmap().stride_order;
567
568 int data_size = shape[order[0]] * strides[order[0]];
569 int block_size = data_size;
570 int block_str = data_size;
571 int n_blocks = 1;
572
573 for (auto n : range(A::rank)) {
574 auto inner_size = (n == A::rank - 1) ? 1 : strides[order[n + 1]] * shape[order[n + 1]];
575 if (strides[order[n]] != inner_size) {
576 if (block_size < data_size) // second strided dimension
577 return opt_t{};
578 // found a strided dimension with (assumed) contiguous inner blocks
579 n_blocks = a.size() / inner_size;
580 block_size = inner_size;
581 block_str = strides[order[n]];
582 }
583 }
584 ASSERT(n_blocks * block_size == a.size());
585 ASSERT(n_blocks * block_str == shape[order[0]] * strides[order[0]]);
586 return opt_t{std::make_tuple(n_blocks, block_size, block_str)};
587 }
588
602 template <size_t Axis = 0, Array A0, Array... As>
603 auto concatenate(A0 const &a0, As const &...as) {
604 // sanity checks
605 auto constexpr rank = A0::rank;
606 static_assert(Axis < rank);
607 static_assert(have_same_rank_v<A0, As...>);
608 static_assert(have_same_value_type_v<A0, As...>);
609 for (auto ax [[maybe_unused]] : range(rank)) { EXPECTS(ax == Axis or ((a0.extent(ax) == as.extent(ax)) and ... and true)); }
610
611 // construct concatenated array
612 auto new_shape = a0.shape();
613 new_shape[Axis] = (as.extent(Axis) + ... + new_shape[Axis]);
614 auto new_array = array<get_value_t<A0>, rank>(new_shape);
615
616 // slicing helper function
617 auto slice_Axis = [](Array auto &a, range r) {
618 auto all_or_range = std::make_tuple(range::all, r);
619 return [&]<auto... Is>(std::index_sequence<Is...>) { return a(std::get<Is == Axis>(all_or_range)...); }(std::make_index_sequence<rank>{});
620 };
621
622 // initialize concatenated array
623 long offset = 0;
624 for (auto const &a_view : {basic_array_view(a0), basic_array_view(as)...}) {
625 slice_Axis(new_array, range(offset, offset + a_view.extent(Axis))) = a_view;
626 offset += a_view.extent(Axis);
627 }
628
629 return new_array;
630 };
631
634} // namespace nda
Provides definitions and type traits involving the different memory address spaces supported by nda.
A generic view of a multi-dimensional array.
A generic multi-dimensional array.
long extent(int i) const noexcept
Get the extent of the ith dimension.
static basic_array ones(std::array< Int, Rank > const &shape)
Make a one-initialized array with the given shape.
static basic_array zeros(std::array< Int, Rank > const &shape)
Make a zero-initialized array with the given shape.
static basic_array rand(std::array< Int, Rank > const &shape)
Make a random-initialized array with the given shape.
Includes all relevant headers for the core clef library.
Check if a given type satisfies the array concept.
Definition concepts.hpp:230
Provides various convenient aliases and helper functions for nda::basic_array and nda::basic_array_vi...
Provides a custom runtime error class and macros to assert conditions and throw exceptions.
Provides for_each functions for multi-dimensional arrays/views.
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(std::array< Int, Rank > const &shape)
Make an array of the given shape on the given address space and zero-initialize it.
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< T, R, LP, A, CP > const &a)
Make an nda::matrix_view of a given nda::basic_array.
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 concatenate(A0 const &a0, As const &...as)
Join a sequence of nda::Array types along an existing axis.
basic_array< ValueType, Rank, Layout, 'A', ContainerPolicy > array
Alias template of an nda::basic_array with an 'A' algebra.
std::conditional_t< mem::on_device< RT >, RT, basic_array< get_value_t< RT >, get_rank< RT >, get_contiguous_layout_policy< get_rank< RT >, get_layout_info< RT >.stride_order >, get_algebra< RT >, heap< mem::Device > > > get_regular_device_t
Get the type of the nda::basic_array that would be obtained by constructing an array on device memory...
std::conditional_t< mem::on_unified< RT >, RT, basic_array< get_value_t< RT >, get_rank< RT >, get_contiguous_layout_policy< get_rank< RT >, get_layout_info< RT >.stride_order >, get_algebra< RT >, heap< mem::Unified > > > get_regular_unified_t
Get the type of the nda::basic_array that would be obtained by constructing an array on unified memor...
long first_dim(A const &a)
Get the extent of the first dimension of the array.
std::conditional_t< mem::on_host< RT >, RT, basic_array< get_value_t< RT >, get_rank< RT >, get_contiguous_layout_policy< get_rank< RT >, get_layout_info< RT >.stride_order >, get_algebra< RT >, heap< mem::Host > > > get_regular_host_t
Get the type of the nda::basic_array that would be obtained by constructing an array on host memory f...
constexpr bool have_same_value_type_v
Constexpr variable that is true if all types in As have the same value type as A0.
Definition traits.hpp:196
std::decay_t< decltype(get_first_element(std::declval< A const >()))> get_value_t
Get the value type of an array/view or a scalar type.
Definition traits.hpp:192
constexpr bool have_same_rank_v
Constexpr variable that is true if all types in As have the same rank as A0.
Definition traits.hpp:200
constexpr bool is_regular_or_view_v
Constexpr variable that is true if type A is either a regular array or a view.
Definition traits.hpp:163
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.
void clef_auto_assign(A &&a, F &&f)
Overload of nda::clef::clef_auto_assign function for nda::Array objects.
__inline__ void for_each(std::array< Int, R > const &shape, F &&f)
Loop over all possible index values of a given shape and apply a function to them.
Definition for_each.hpp:129
auto get_block_layout(A const &a)
Check if a given nda::MemoryArray has a block-strided layout.
AddressSpace
Enum providing identifiers for the different memory address spaces.
static constexpr bool on_device
Constexpr variable that is true if all given types have a Device address space.
static constexpr bool on_unified
Constexpr variable that is true if all given types have a Unified address space.
static constexpr bool on_host
Constexpr variable that is true if all given types have a Host address space.
constexpr bool is_scalar_v
Constexpr variable that is true if type S is a scalar type, i.e. arithmetic or complex.
Definition traits.hpp:79
Provides type traits for the nda library.