TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
algorithms.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 "./basic_functions.hpp"
14#include "./concepts.hpp"
15#include "./layout/for_each.hpp"
16#include "./layout/range.hpp"
17#include "./macros.hpp"
18#include "./map.hpp"
19#include "./traits.hpp"
20
21#include <algorithm>
22#include <array>
23#include <cmath>
24#include <concepts>
25#include <cstdlib>
26#include <functional>
27#include <type_traits>
28#include <utility>
29#include <vector>
30
31namespace nda {
32
37
38 // FIXME : CHECK ORDER of the LOOP !
58 template <Array A, typename F, typename R>
59 auto fold(F f, A const &a, R r) {
60 // cast the initial value to the return type of f to avoid narrowing
61 using res_t = std::decay_t<decltype(make_regular(f(r, get_value_t<A>{})))>;
62 auto res = res_t{r};
63 nda::for_each(a.shape(), [&a, &res, &f](auto &&...args) { res = f(res, a(args...)); });
64 return res;
65 }
66
68 template <Array A, typename F>
69 auto fold(F f, A const &a) {
70 return fold(std::move(f), a, get_value_t<A>{});
71 }
72
88 template <Array A>
89 bool any(A const &a) {
90 static_assert(std::is_same_v<get_value_t<A>, bool>, "Error in nda::any: Value type of the array must be bool");
91 return fold([](bool r, auto const &x) -> bool { return r or bool(x); }, a, false);
92 }
93
109 template <Array A>
110 bool all(A const &a) {
111 static_assert(std::is_same_v<get_value_t<A>, bool>, "Error in nda::all: Value type of the array must be bool");
112 return fold([](bool r, auto const &x) -> bool { return r and bool(x); }, a, true);
113 }
114
124 template <Array A>
125 auto max_element(A const &a) {
126 return fold(
127 [](auto const &x, auto const &y) {
128 using std::max;
129 return max(x, y);
130 },
131 a, get_first_element(a));
132 }
133
143 template <Array A>
144 auto min_element(A const &a) {
145 return fold(
146 [](auto const &x, auto const &y) {
147 using std::min;
148 return min(x, y);
149 },
150 a, get_first_element(a));
151 }
152
161 template <ArrayOfRank<2> A>
162 double frobenius_norm(A const &a) {
163 return std::sqrt(fold(
164 [](double r, auto const &x) -> double {
165 auto ab = std::abs(x);
166 return r + ab * ab;
167 },
168 a, double(0)));
169 }
170
178 template <Array A, typename Value = get_value_t<A>>
179 auto sum(A const &a)
181 {
182 if constexpr (nda::Scalar<Value>) {
183 return fold(std::plus<>{}, a);
184 } else { // Array<Value>
185 return fold(std::plus<>{}, a, Value::zeros(get_first_element(a).shape()));
186 }
187 }
188
208 template <Array A, std::integral I, size_t N>
209 requires(get_rank<A> >= N and nda::Scalar<get_value_t<A>>)
210 auto sum(A const &a, std::array<I, N> axes) {
211 // if no axes are specified, return a copy of the input
212 if constexpr (N == 0) {
213 return make_regular(a);
214 } else {
215 // sort axes and check validity
216 std::ranges::sort(axes);
217 EXPECTS(std::ranges::adjacent_find(axes) == axes.end());
218 EXPECTS(axes.front() >= 0 and axes.back() < get_rank<A>);
219
220 constexpr int res_rank = get_rank<A> - static_cast<int>(N);
221
222 if constexpr (res_rank == 0) {
223 return sum(a);
224 } else {
225 // get the result shape and the axes that we keep (are not summed over)
226 std::array<long, res_rank> keep_axes, res_shape;
227 for (int i = 0; auto ax : nda::range(get_rank<A>)) {
228 if (!std::ranges::binary_search(axes, ax)) {
229 keep_axes[i] = ax;
230 res_shape[i++] = a.shape()[ax];
231 }
232 }
233
234 // create the result array initialized to zero
235 auto res = array<get_value_t<A>, res_rank>::zeros(res_shape);
236
237 // loop over all indices of the input array and sum over the specified axes
238 nda::for_each(a.shape(), [&](auto... idxs) {
239 auto idx_arr = std::array{idxs...};
240 std::apply([&](auto... keep) { res(idx_arr[keep]...) += a(idxs...); }, keep_axes);
241 });
242
243 return res;
244 }
245 }
246 }
247
258 template <Array A>
259 requires(get_rank<A> >= 1 and nda::Scalar<get_value_t<A>>)
260 auto sum(A const &a, int axis) {
261 return sum(a, std::array{axis});
262 }
263
271 template <Array A, typename Value = get_value_t<A>>
272 auto product(A const &a)
274 {
275 if constexpr (nda::Scalar<Value>) {
276 return fold(std::multiplies<>{}, a, get_value_t<A>{1});
277 } else { // Array<Value>
278 return fold(std::multiplies<>{}, a, Value::ones(get_first_element(a).shape()));
279 }
280 }
281
291 template <Array A, Array B>
293 [[nodiscard]] constexpr auto hadamard(A &&a, B &&b) {
294 return nda::map([](auto const &x, auto const &y) { return x * y; })(std::forward<A>(a), std::forward<B>(b));
295 }
296
307 template <typename T, typename U, size_t R>
308 [[nodiscard]] constexpr auto hadamard(std::array<T, R> const &a, std::array<U, R> const &b) {
309 return a * b;
310 }
311
321 template <typename T, typename U>
322 [[nodiscard]] constexpr auto hadamard(std::vector<T> const &a, std::vector<U> const &b) {
323 using TU = decltype(std::declval<T>() * std::declval<U>());
324 EXPECTS(a.size() == b.size());
325
326 std::vector<TU> c(a.size());
327 for (auto i : range(c.size())) c[i] = a[i] * b[i];
328 return c;
329 }
330
340 constexpr auto hadamard(nda::Scalar auto a, nda::Scalar auto b) { return a * b; }
341
343
344} // namespace nda
Provides basic functions to create and manipulate arrays and views.
Check if a given type satisfies the array concept.
Definition concepts.hpp:205
Check if a given type is either an arithmetic or complex type.
Definition concepts.hpp:83
Provides concepts for the nda library.
Provides for_each functions for multi-dimensional arrays/views.
auto max_element(A const &a)
Find the maximum element of an array.
auto fold(F f, A const &a, R r)
Perform a fold operation on the given nda::Array object.
auto sum(A const &a)
Sum all the elements of an nda::Array object.
bool any(A const &a)
Does any of the elements of the array evaluate to true?
auto product(A const &a)
Multiply all the elements of an nda::Array object.
auto min_element(A const &a)
Find the minimum element of an array.
constexpr auto hadamard(A &&a, B &&b)
Hadamard product of two nda::Array objects.
bool all(A const &a)
Do all elements of the array evaluate to true?
decltype(auto) make_regular(A &&a)
Make a given object regular.
auto zeros(std::array< Int, Rank > const &shape)
Make an array of the given shape on the given address space and zero-initialize it.
double frobenius_norm(A const &a)
Calculate the Frobenius norm of a 2-dimensional array.
mapped< F > map(F f)
Create a lazy function call expression on arrays/views.
Definition map.hpp:206
basic_array< ValueType, Rank, Layout, 'A', ContainerPolicy > array
Alias template of an nda::basic_array with an 'A' algebra.
decltype(auto) get_first_element(A &&a)
Get the first element of an array/view or simply return the scalar if a scalar is given.
Definition traits.hpp:176
constexpr int get_rank
Constexpr variable that specifies the rank of an nda::Array or of a contiguous 1-dimensional range.
Definition traits.hpp:126
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:191
__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:116
Macros used in the nda library.
Provides lazy function calls on arrays/views.
Includes the itertools header and provides some additional utilities.
Provides type traits for the nda library.