TRIQS/nda 2.0.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
basic_array_view.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 "./clef.hpp"
15#include "./concepts.hpp"
16#include "./declarations.hpp"
17#include "./device.hpp"
18#include "./iterators.hpp"
19#include "./layout/for_each.hpp"
20#include "./layout/idx_map.hpp"
22#include "./layout/range.hpp"
24#include "./macros.hpp"
27#include "./mem/fill.hpp"
28#include "./mem/memcpy.hpp"
29#include "./mem/memset.hpp"
30#include "./mem/policies.hpp"
31#include "./traits.hpp"
32
33#include <itertools/itertools.hpp>
34
35#include <algorithm>
36#include <array>
37#include <cstring>
38#include <exception>
39#include <iostream>
40#include <memory>
41#include <ranges>
42#include <type_traits>
43#include <utility>
44
45namespace std {
46
52 template <typename V1, int R1, typename LP1, char A1, typename AP1, typename OP1, typename V2, int R2, typename LP2, char A2, typename AP2,
53 typename OP2>
55
56} // namespace std
57
58namespace nda {
59
108 template <typename ValueType, int Rank, typename LayoutPolicy, char Algebra, typename AccessorPolicy, typename OwningPolicy>
109 class basic_array_view {
110 // Compile-time checks.
111 static_assert((Algebra != 'N'), "Internal error in nda::basic_array_view: Algebra 'N' not supported");
112 static_assert((Algebra != 'M') or (Rank == 2), "Internal error in nda::basic_array_view: Algebra 'M' requires a rank 2 view");
113 static_assert((Algebra != 'V') or (Rank == 1), "Internal error in nda::basic_array_view: Algebra 'V' requires a rank 1 view");
114
115 public:
117 using value_type = ValueType;
118
120 using layout_policy_t = LayoutPolicy;
121
123 using layout_t = typename LayoutPolicy::template mapping<Rank>;
124
126 using accessor_policy_t = AccessorPolicy;
127
129 using owning_policy_t = OwningPolicy;
130
132 using storage_t = typename OwningPolicy::template handle<ValueType>;
133
135 using regular_type = basic_array<std::remove_const_t<ValueType>, Rank, C_layout, Algebra, heap<mem::get_addr_space<storage_t>>>;
136
138 static constexpr int rank = Rank;
139
140 // Compile-time check.
142 "Error in nda::basic_array_view: Device compatible address space requires compiling with device support.");
143
144 private:
145 // Type of the view itself.
146 using self_t = basic_array_view;
147
148 // Constexpr variable that is true if the view is a view (always for basic_array_view).
149 static constexpr bool is_view = true;
150
151 // Constexpr variable that is true if the value_type is const.
152 static constexpr bool is_const = std::is_const_v<ValueType>;
153
154 // Memory layout of the view, i.e. the nda::idx_map.
155 layout_t lay;
156
157 // Memory handle of the view.
158 storage_t sto;
159
160 // Declare any nda::basic_array as a friend.
161 template <typename T, int R, typename L, char A, typename CP>
162 friend class basic_array;
163
164 // Declare any other nda::basic_array_view as a friend.
165 template <typename T, int R, typename L, char A, typename AP, typename OP>
166 friend class basic_array_view;
167
168 // Check the layout compatibility of this view with another layout.
169 template <typename L>
170 static constexpr bool requires_runtime_check = not layout_property_compatible(L::template mapping<Rank>::layout_prop, layout_t::layout_prop);
171
172 public:
173 // FIXME : TRIQS PORTING
174 // private constructor for the previous friend
183 basic_array_view(layout_t const &idxm, storage_t st) : lay(idxm), sto(std::move(st)) {}
184
185 public:
186 // backward : FIXME : temporary to be removed
188 [[deprecated]] auto as_array_view() { return basic_array_view<ValueType, Rank, LayoutPolicy, 'A', AccessorPolicy, OwningPolicy>{*this}; };
189
191 [[deprecated]] auto as_array_view() const {
192 return basic_array_view<const ValueType, Rank, LayoutPolicy, 'A', AccessorPolicy, OwningPolicy>{*this};
193 };
194
196 basic_array_view() = default;
197
199 basic_array_view(basic_array_view &&) = default;
200
202 basic_array_view(basic_array_view const &) = default;
203
213 template <MemoryArrayOfRank<Rank> A>
214 requires((get_layout_info<A>.stride_order == layout_t::stride_order_encoded)
215 and (std::is_same_v<std::remove_const_t<ValueType>, get_value_t<A>>)
216 and (std::is_const_v<ValueType> or !std::is_const_v<typename std::decay_t<A>::value_type>))
217 explicit(requires_runtime_check<typename std::decay_t<A>::layout_policy_t>)
218 basic_array_view(A &&a) noexcept // NOLINT (should we forward the reference?)
219 : lay(a.indexmap()), sto(a.storage()) {}
220
230 basic_array_view(std::array<long, Rank> const &shape, ValueType *p) noexcept : basic_array_view(layout_t{shape}, p) {}
231
241 basic_array_view(layout_t const &idxm, ValueType *p) noexcept : lay(idxm), sto{p} {}
242
249 template <size_t N>
250 requires(Rank == 1)
251 explicit basic_array_view(std::array<ValueType, N> &a) noexcept : basic_array_view{{long(N)}, a.data()} {}
252
259 template <size_t N>
260 requires(Rank == 1 and std::is_const_v<ValueType>)
261 explicit basic_array_view(std::array<std::remove_const_t<ValueType>, N> const &a) noexcept : basic_array_view{{long(N)}, a.data()} {}
262
269 template <std::ranges::contiguous_range R>
270 requires(Rank == 1 and not MemoryArray<R>
271 and (std::is_same_v<std::ranges::range_value_t<R>, ValueType> or std::is_same_v<const std::ranges::range_value_t<R>, ValueType>))
272 explicit basic_array_view(R &rg) noexcept : basic_array_view{{long(std::ranges::size(rg))}, std::to_address(std::begin(rg))} {}
273
282 basic_array_view &operator=(basic_array_view const &rhs) noexcept {
283 assign_from_ndarray(rhs);
284 return *this;
285 }
286
296 template <ArrayOfRank<Rank> RHS>
297 basic_array_view &operator=(RHS const &rhs) noexcept {
298 static_assert(!is_const, "Cannot assign to an nda::basic_array_view with const value_type");
299 assign_from_ndarray(rhs);
300 return *this;
301 }
302
313 template <typename RHS>
314 basic_array_view &operator=(RHS const &rhs) noexcept
316 {
317 static_assert(!is_const, "Cannot assign to an nda::basic_array_view with const value_type");
318 assign_from_scalar(rhs);
319 return *this;
320 }
321
330 template <ArrayInitializer<basic_array_view> Initializer>
331 basic_array_view &operator=(Initializer const &initializer) noexcept {
332 EXPECTS(shape() == initializer.shape());
333 initializer.invoke(*this);
334 return *this;
335 }
336
351 template <typename T, int R, typename LP, char A, typename AP, typename OP>
352 void rebind(basic_array_view<T, R, LP, A, AP, OP> v) noexcept {
353 static_assert(R == Rank, "Cannot rebind a view to another view of a different rank");
354 static_assert(std::is_same_v<std::remove_const_t<T>, std::remove_const_t<ValueType>>,
355 "Cannot rebind a view to another view with a different value_type (except for const)");
356 static constexpr bool same_type = std::is_same_v<T, ValueType>;
357 static_assert(same_type or is_const, "Cannot rebind a view with non-const value_type to another view with const value_type");
358 if constexpr (same_type) {
359 // FIXME Error message in layout error !
360 lay = v.lay;
361 sto = v.sto;
362 } else if constexpr (is_const) {
363 // the last if is always trivially true but in case of an error in the static_assert above,
364 // it improves the error message by not compiling the = afterwards
365 lay = layout_t{v.indexmap()};
366 sto = storage_t{v.storage()};
367 }
368 }
369
378 friend void swap(basic_array_view &a, basic_array_view &b) noexcept {
379 std::swap(a.lay, b.lay);
380 std::swap(a.sto, b.sto);
381 }
382
391 friend void deep_swap(basic_array_view a, basic_array_view b) noexcept {
392 auto tmp = make_regular(a);
393 a = b;
394 b = tmp;
395 }
396
397// include common functionality of arrays and views
398// Copyright (c) 2019--present, The Simons Foundation
399// This file is part of TRIQS/nda and is licensed under the Apache License, Version 2.0.
400// SPDX-License-Identifier: Apache-2.0
401// See LICENSE in the root of this distribution for details.
402
407[[nodiscard]] constexpr auto const &indexmap() const noexcept { return lay; }
408
413[[nodiscard]] storage_t const &storage() const & noexcept { return sto; }
414
419[[nodiscard]] storage_t &storage() & noexcept { return sto; }
420
425[[nodiscard]] storage_t storage() && noexcept { return std::move(sto); }
426
433[[nodiscard]] constexpr auto stride_order() const noexcept { return lay.stride_order; }
434
439[[nodiscard]] ValueType const *data() const noexcept { return sto.data(); }
440
445[[nodiscard]] ValueType *data() noexcept { return sto.data(); }
446
451[[nodiscard]] auto const &shape() const noexcept { return lay.lengths(); }
452
457[[nodiscard]] auto const &strides() const noexcept { return lay.strides(); }
458
463[[nodiscard]] long size() const noexcept { return lay.size(); }
464
469[[nodiscard]] long is_contiguous() const noexcept { return lay.is_contiguous(); }
470
475[[nodiscard]] long has_positive_strides() const noexcept { return lay.has_positive_strides(); }
476
481[[nodiscard]] bool empty() const { return sto.is_null(); }
482
484[[nodiscard]] bool is_empty() const noexcept { return sto.is_null(); }
485
490[[nodiscard]] long extent(int i) const noexcept {
491#ifdef NDA_ENFORCE_BOUNDCHECK
492 if (i < 0 || i >= rank) {
493 std::cerr << "Error in extent: Dimension " << i << " is incompatible with array of rank " << rank << std::endl;
494 std::terminate();
495 }
496#endif
497 return lay.lengths()[i];
498}
499
501[[nodiscard]] long shape(int i) const noexcept { return extent(i); }
502
507[[nodiscard]] auto indices() const noexcept { return itertools::product_range(shape()); }
508
513static constexpr bool is_stride_order_C() noexcept { return layout_t::is_stride_order_C(); }
514
519static constexpr bool is_stride_order_Fortran() noexcept { return layout_t::is_stride_order_Fortran(); }
520
530decltype(auto) operator()(_linear_index_t idx) const noexcept {
531 if constexpr (layout_t::layout_prop == layout_prop_e::strided_1d)
532 return sto[idx.value * lay.min_stride()];
533 else if constexpr (layout_t::layout_prop == layout_prop_e::contiguous)
534 return sto[idx.value];
535 else
536 static_assert(always_false<layout_t>, "Internal error in array/view: Calling this type with a _linear_index_t is not allowed");
537}
538
540decltype(auto) operator()(_linear_index_t idx) noexcept {
541 if constexpr (layout_t::layout_prop == layout_prop_e::strided_1d)
542 return sto[idx.value * lay.min_stride()];
543 else if constexpr (layout_t::layout_prop == layout_prop_e::contiguous)
544 return sto[idx.value];
545 else
546 static_assert(always_false<layout_t>, "Internal error in array/view: Calling this type with a _linear_index_t is not allowed");
547}
548
549private:
550// Constexpr variable that is true if bounds checking is disabled.
551#ifdef NDA_ENFORCE_BOUNDCHECK
552static constexpr bool has_no_boundcheck = false;
553#else
554static constexpr bool has_no_boundcheck = true;
555#endif
556
557public:
574template <char ResultAlgebra, bool SelfIsRvalue, typename Self, typename... Ts>
575FORCEINLINE static decltype(auto) call(Self &&self, Ts const &...idxs) noexcept(has_no_boundcheck) {
576 // resulting value type
577 using r_v_t = std::conditional_t<std::is_const_v<std::remove_reference_t<Self>>, ValueType const, ValueType>;
578
579 // behavior depends on the given arguments
580 if constexpr (clef::is_any_lazy<Ts...>) {
581 // if there are lazy arguments, e.g. as in A(i_) << i_, a lazy expression is returned
582 return clef::make_expr_call(std::forward<Self>(self), idxs...);
583 } else if constexpr (sizeof...(Ts) == 0) {
584 // if no arguments are given, a full view is returned
585 return basic_array_view<r_v_t, Rank, LayoutPolicy, Algebra, AccessorPolicy, OwningPolicy>{self.lay, self.sto};
586 } else {
587 // otherwise we check the arguments and either access a single element or make a slice
588 static_assert(((layout_t::template argument_is_allowed_for_call_or_slice<Ts> + ...) > 0),
589 "Error in array/view: Slice arguments must be convertible to range, ellipsis, or long (or string if the layout permits it)");
590
591 // number of arguments convertible to long
592 static constexpr int n_args_long = (layout_t::template argument_is_allowed_for_call<Ts> + ...);
593
594 if constexpr (n_args_long == rank) {
595 // access a single element
596 long offset = self.lay(idxs...);
597 if constexpr (is_view or not SelfIsRvalue) {
598 // if the calling object is a view or an lvalue, we return a reference
599 return AccessorPolicy::template accessor<r_v_t>::access(self.sto.data(), offset);
600 } else {
601 // otherwise, we return a copy of the value
602 return ValueType{self.sto[offset]};
603 }
604 } else {
605 // access a slice of the view/array
606 auto const [offset, idxm] = self.lay.slice(idxs...);
607 static constexpr auto res_rank = decltype(idxm)::rank();
608 // resulting algebra
609 static constexpr char newAlgebra = (ResultAlgebra == 'M' and (res_rank == 1) ? 'V' : ResultAlgebra);
610 // resulting layout policy
611 using r_layout_p = typename detail::layout_to_policy<std::decay_t<decltype(idxm)>>::type;
612 return basic_array_view<r_v_t, res_rank, r_layout_p, newAlgebra, AccessorPolicy, OwningPolicy>{std::move(idxm), {self.sto, offset}};
613 }
614 }
615}
616
617public:
639template <typename... Ts>
640FORCEINLINE decltype(auto) operator()(Ts const &...idxs) const & noexcept(has_no_boundcheck) {
641 static_assert((rank == -1) or (sizeof...(Ts) == rank) or (sizeof...(Ts) == 0) or (ellipsis_is_present<Ts...> and (sizeof...(Ts) <= rank + 1)),
642 "Error in array/view: Incorrect number of parameters in call operator");
643 return call<Algebra, false>(*this, idxs...);
644}
645
647template <typename... Ts>
648FORCEINLINE decltype(auto) operator()(Ts const &...idxs) & noexcept(has_no_boundcheck) {
649 static_assert((rank == -1) or (sizeof...(Ts) == rank) or (sizeof...(Ts) == 0) or (ellipsis_is_present<Ts...> and (sizeof...(Ts) <= rank + 1)),
650 "Error in array/view: Incorrect number of parameters in call operator");
651 return call<Algebra, false>(*this, idxs...);
652}
653
655template <typename... Ts>
656FORCEINLINE decltype(auto) operator()(Ts const &...idxs) && noexcept(has_no_boundcheck) {
657 static_assert((rank == -1) or (sizeof...(Ts) == rank) or (sizeof...(Ts) == 0) or (ellipsis_is_present<Ts...> and (sizeof...(Ts) <= rank + 1)),
658 "Error in array/view: Incorrect number of parameters in call operator");
659 return call<Algebra, true>(*this, idxs...);
660}
661
679template <typename T>
680decltype(auto) operator[](T const &idx) const & noexcept(has_no_boundcheck) {
681 static_assert((rank == 1), "Error in array/view: Subscript operator is only available for rank 1 views/arrays in C++17/20");
682 return call<Algebra, false>(*this, idx);
683}
684
686template <typename T>
687decltype(auto) operator[](T const &x) & noexcept(has_no_boundcheck) {
688 static_assert((rank == 1), "Error in array/view: Subscript operator is only available for rank 1 views/arrays in C++17/20");
689 return call<Algebra, false>(*this, x);
690}
691
693template <typename T>
694decltype(auto) operator[](T const &x) && noexcept(has_no_boundcheck) {
695 static_assert((rank == 1), "Error in array/view: Subscript operator is only available for rank 1 views/arrays in C++17/20");
696 return call<Algebra, true>(*this, x);
697}
698
700static constexpr int iterator_rank = (has_strided_1d(layout_t::layout_prop) ? 1 : Rank);
701
704
707
708private:
709// Make an iterator for the view/array depending on its type.
710template <typename Iterator>
711[[nodiscard]] auto make_iterator(bool at_end) const noexcept {
712 if constexpr (iterator_rank == Rank) {
713 // multi-dimensional iterator
714 if constexpr (layout_t::is_stride_order_C()) {
715 // C-order case (array_iterator already traverses the data in C-order)
716 return Iterator{indexmap().lengths(), indexmap().strides(), sto.data(), at_end};
717 } else {
718 // general case (we need to permute the shape and the strides according to the stride order of the layout)
719 return Iterator{nda::permutations::apply(layout_t::stride_order, indexmap().lengths()),
720 nda::permutations::apply(layout_t::stride_order, indexmap().strides()), sto.data(), at_end};
721 }
722 } else {
723 // 1-dimensional iterator
724 return Iterator{std::array<long, 1>{size()}, std::array<long, 1>{indexmap().min_stride()}, sto.data(), at_end};
725 }
726}
727
728public:
730[[nodiscard]] const_iterator begin() const noexcept { return make_iterator<const_iterator>(false); }
731
733[[nodiscard]] const_iterator cbegin() const noexcept { return make_iterator<const_iterator>(false); }
734
736iterator begin() noexcept { return make_iterator<iterator>(false); }
737
739[[nodiscard]] const_iterator end() const noexcept { return make_iterator<const_iterator>(true); }
740
742[[nodiscard]] const_iterator cend() const noexcept { return make_iterator<const_iterator>(true); }
743
745iterator end() noexcept { return make_iterator<iterator>(true); }
746
759template <typename RHS>
760auto &operator+=(RHS const &rhs) noexcept {
761 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
762 return operator=(*this + rhs);
763}
764
777template <typename RHS>
778auto &operator-=(RHS const &rhs) noexcept {
779 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
780 return operator=(*this - rhs);
781}
782
795template <typename RHS>
796auto &operator*=(RHS const &rhs) noexcept {
797 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
798 return operator=((*this) * rhs);
799}
800
813template <typename RHS>
814auto &operator/=(RHS const &rhs) noexcept {
815 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
816 return operator=(*this / rhs);
817}
818
827template <std::ranges::contiguous_range R>
828auto &operator=(R const &rhs) noexcept
829 requires(Rank == 1 and not MemoryArray<R> and not is_scalar_for_v<R, self_t>)
830{
832 return *this;
833}
834
835private:
836// Implementation of the assignment from an n-dimensional array type.
837template <typename RHS>
838void assign_from_ndarray(RHS const &rhs) {
839#ifdef NDA_ENFORCE_BOUNDCHECK
840 if (this->shape() != rhs.shape()) {
841 NDA_RUNTIME_ERROR << "Error in assign_from_ndarray: Size mismatch:"
842 << "\n LHS.shape() = " << this->shape() << "\n RHS.shape() = " << rhs.shape();
843 }
844#endif
845 // compile-time check if assignment is possible
846 static_assert(std::is_assignable_v<value_type &, get_value_t<RHS>>, "Error in assign_from_ndarray: Incompatible value types");
847
848 // are both operands nda::MemoryArray types?
849 static constexpr bool both_in_memory = MemoryArray<self_t> and MemoryArray<RHS>;
850
851 // do both operands have the same stride order?
852 static constexpr bool same_stride_order = get_layout_info<self_t>.stride_order == get_layout_info<RHS>.stride_order;
853
854 // compile-time check for device arrays to avoid runtime errors
855 static_assert(!(mem::on_device<self_t> or mem::on_device<RHS>) or (both_in_memory and same_stride_order and have_same_value_type_v<self_t, RHS>),
856 "Error in assign_from_ndarray: Assignment to/from device arrays is not supported for the given types.");
857
858 // prefer optimized options if possible
859 if constexpr (both_in_memory and same_stride_order) {
860 if (rhs.empty()) return;
861 // are both operands strided in 1d?
862 static constexpr bool both_1d_strided = has_layout_strided_1d<self_t> and has_layout_strided_1d<RHS>;
863 if constexpr (mem::on_host<self_t, RHS> and both_1d_strided) {
864 // vectorizable copy on host
865 for (long i = 0; i < size(); ++i) (*this)(_linear_index_t{i}) = rhs(_linear_index_t{i});
866 return;
868 // check for block-layout and use mem::memcpy2D if possible
869 auto bl_layout_dst = get_block_layout(*this);
870 auto bl_layout_src = get_block_layout(rhs);
871 if (bl_layout_dst && bl_layout_src) {
872 auto [n_bl_dst, bl_size_dst, bl_str_dst] = *bl_layout_dst;
873 auto [n_bl_src, bl_size_src, bl_str_src] = *bl_layout_src;
874 // check that the total memory size is the same
875 if (n_bl_dst * bl_size_dst != n_bl_src * bl_size_src) NDA_RUNTIME_ERROR << "Error in assign_from_ndarray: Incompatible block sizes";
876 // if either destination or source consists of a single block, we can chunk it up to make the layouts compatible
877 if (n_bl_dst == 1 && n_bl_src > 1) {
878 n_bl_dst = n_bl_src;
879 bl_size_dst /= n_bl_src;
880 bl_str_dst = bl_size_dst;
881 }
882 if (n_bl_src == 1 && n_bl_dst > 1) {
883 n_bl_src = n_bl_dst;
884 bl_size_src /= n_bl_dst;
885 bl_str_src = bl_size_src;
886 }
887 // copy only if block-layouts are compatible, otherwise continue to fallback
888 if (n_bl_dst == n_bl_src && bl_size_dst == bl_size_src) {
889 mem::memcpy2D<mem::get_addr_space<self_t>, mem::get_addr_space<RHS>>((void *)data(), bl_str_dst * sizeof(value_type), (void *)rhs.data(),
890 bl_str_src * sizeof(value_type), bl_size_src * sizeof(value_type),
891 n_bl_src);
892 return;
893 }
894 }
895 }
896 }
897 // otherwise fallback to elementwise assignment
899 NDA_RUNTIME_ERROR << "Error in assign_from_ndarray: Fallback to elementwise assignment not implemented for arrays/views on the GPU";
900 }
901 nda::for_each(shape(), [this, &rhs](auto const &...args) { (*this)(args...) = rhs(args...); });
902}
903
904// Implementation to fill a view/array with a constant scalar value.
905template <typename Scalar>
906void fill_with_scalar(Scalar const &scalar) {
907 if constexpr (mem::on_host<self_t>) {
908 if constexpr (has_layout_strided_1d<self_t>) {
909 const long L = size();
910 auto *__restrict const p = data(); // no alias possible here!
911 if constexpr (has_contiguous_layout<self_t>) {
912 for (long i = 0; i < L; ++i) p[i] = scalar;
913 } else {
914 const long stri = indexmap().min_stride();
915 const long Lstri = L * stri;
916 for (long i = 0; i != Lstri; i += stri) p[i] = scalar;
917 }
918 } else {
919 for (auto &x : *this) x = scalar;
920 }
921 } else if constexpr (mem::on_device<self_t> or mem::on_unified<self_t>) {
922 if constexpr (has_layout_strided_1d<self_t>) {
923 if constexpr (has_contiguous_layout<self_t>) {
924 mem::fill_n<mem::get_addr_space<self_t>>(data(), size(), value_type(scalar));
925 } else {
926 const long stri = indexmap().min_stride();
927 mem::fill2D_n<mem::get_addr_space<self_t>>(data(), stri, 1, size(), value_type(scalar));
928 }
929 } else {
930 auto bl_layout = get_block_layout(*this);
931 if (bl_layout) {
932 auto [n_bl, bl_size, bl_str] = *bl_layout;
933 mem::fill2D_n<mem::get_addr_space<self_t>>(data(), bl_str, bl_size, n_bl, value_type(scalar));
934 } else {
935 // MAM: implement recursive call to fill_with_scalar on (i,nda::ellipsis{})
936 NDA_RUNTIME_ERROR << "fill_with_scalar: Not implemented on device for generic (non-blocked) layout.";
937 }
938 }
939 }
940}
941
942// Implementation of the assignment from a scalar value.
943template <typename Scalar>
944void assign_from_scalar(Scalar const &scalar) noexcept {
945 static_assert(!is_const, "Error in assign_from_ndarray: Cannot assign to a const view");
946 if constexpr (Algebra != 'M') {
947 // element-wise assignment for non-matrix algebras
948 fill_with_scalar(scalar);
949 } else {
950 // a scalar has to be interpreted as a unit matrix for matrix algebras (the scalar in the shortest diagonal)
951 // FIXME : A priori faster to put 0 everywhere and then change the diag to avoid the if.
952 // FIXME : Benchmark and confirm.
954 fill_with_scalar(0);
955 else
956 fill_with_scalar(Scalar{0 * scalar}); // FIXME : improve this
957 diagonal(*this).fill_with_scalar(scalar);
958 }
959}
960 };
961
962 // Class template argument deduction guides.
963 template <MemoryArray A>
964 basic_array_view(A &&a)
965 -> basic_array_view<std::conditional_t<std::is_const_v<std::remove_reference_t<A>>, const typename std::decay_t<A>::value_type,
966 typename std::decay_t<A>::value_type>,
967 get_rank<A>, typename std::decay_t<A>::layout_policy_t, get_algebra<A>, default_accessor, borrowed<mem::get_addr_space<A>>>;
968
969 template <typename V, size_t R>
970 basic_array_view(std::array<V, R> &a)
971 -> basic_array_view<V, 1, nda::basic_layout<nda::static_extents(R), nda::C_stride_order<1>, nda::layout_prop_e::contiguous>, 'V',
973
974 template <typename V, size_t R>
975 basic_array_view(std::array<V, R> const &a)
976 -> basic_array_view<const V, 1, nda::basic_layout<nda::static_extents(R), nda::C_stride_order<1>, nda::layout_prop_e::contiguous>, 'V',
978
979 template <std::ranges::contiguous_range R>
980 basic_array_view(R &r) -> basic_array_view<std::conditional_t<std::is_const_v<R>, const typename R::value_type, typename R::value_type>, 1,
982
983} // namespace nda
Provides definitions and type traits involving the different memory address spaces supported by 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.
Provides basic functions to create and manipulate arrays and views.
Iterator for nda::basic_array and nda::basic_array_view types.
A generic view of a multi-dimensional array.
auto & operator=(R const &rhs) noexcept
Assignment operator makes a deep copy of a general contiguous range and assigns it to the 1-dimension...
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 the 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.
long has_positive_strides() const noexcept
Are all the strides of the memory layout of the view/array positive?
typename OwningPolicy::template handle< ValueType > storage_t
Type of the memory handle (see Handles).
auto & operator/=(RHS const &rhs) noexcept
Division assignment operator.
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.
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.
basic_array_view & operator=(Initializer const &initializer) noexcept
Assignment operator uses an nda::ArrayInitializer to assign to the view.
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.
typename LayoutPolicy::template mapping< Rank > layout_t
Type of the memory layout (an nda::idx_map).
basic_array< std::remove_const_t< ValueType >, Rank, C_layout, Algebra, heap< mem::get_addr_space< storage_t > > > regular_type
The associated regular (nda::basic_array) type.
array_iterator< iterator_rank, ValueType, typename AccessorPolicy::template accessor< ValueType >::pointer > iterator
Iterator type of the view/array.
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?
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?
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.
ValueType value_type
Type of the values in the view (might be const).
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 & operator=(RHS const &rhs) noexcept
Assignment operator assigns a scalar to the view.
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.
OwningPolicy owning_policy_t
Type of the owning policy (see Memory policies).
LayoutPolicy layout_policy_t
Type of the memory layout policy (see Layout policies).
array_iterator< iterator_rank, ValueType const, typename AccessorPolicy::template accessor< ValueType >::pointer > const_iterator
Const iterator type of the view/array.
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.
AccessorPolicy accessor_policy_t
Type of the accessor policy (see e.g. nda::default_accessor).
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.
long extent(int i) const noexcept
Get the extent of the ith dimension.
constexpr auto const & indexmap() const noexcept
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
Includes all clef relevant headers.
Check if a given type satisfies the memory array concept.
Definition concepts.hpp:230
Provides concepts for the nda library.
Provides various convenient aliases and helper functions for nda::basic_array and nda::basic_array_vi...
Provides GPU and non-GPU specific functionality.
Provides for_each functions for multi-dimensional arrays/views.
decltype(auto) make_regular(A &&a)
Make a given object regular.
ArrayOfRank< 1 > auto diagonal(M &&m)
Get a view of the diagonal of a 2-dimensional array/view.
basic_array_view< ValueType const, Rank, Layout, 'A', default_accessor, borrowed<> > array_const_view
Same as nda::array_view except for const value types.
constexpr char get_algebra
Constexpr variable that specifies the algebra of a type.
Definition traits.hpp:137
constexpr uint64_t static_extents(int i0, Is... is)
Encode the given shape into a single integer using the nda::encode function.
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:225
constexpr int get_rank
Constexpr variable that specifies the rank of an nda::Array or of a contiguous 1-dimensional range.
Definition traits.hpp:147
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:212
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:63
constexpr bool is_any_lazy
Constexpr variable that is true if any of the given types is lazy.
Definition utils.hpp:144
constexpr uint64_t C_stride_order
C/Row-major stride order.
Definition idx_map.hpp:52
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:266
constexpr bool ellipsis_is_present
Constexpr variable that is true if the parameter pack Args contains an nda::ellipsis.
Definition range.hpp:56
constexpr bool has_strided_1d(layout_prop_e lp)
Checks if a layout property has the strided_1d property.
Definition traits.hpp:295
__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
constexpr bool has_layout_strided_1d
Constexpr variable that is true if type A has the strided_1d nda::layout_prop_e guarantee.
Definition traits.hpp:363
auto get_block_layout(A const &a)
Check if a given nda::MemoryArray has a block-strided layout.
constexpr layout_info_t get_layout_info
Constexpr variable that specifies the nda::layout_info_t of type A.
Definition traits.hpp:350
constexpr bool has_contiguous_layout
Constexpr variable that is true if type A has the contiguous nda::layout_prop_e guarantee.
Definition traits.hpp:359
static constexpr bool have_device_compatible_addr_space
Constexpr variable that is true if all given types have an address space compatible with Device.
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 AddressSpace get_addr_space
Variable template providing the address space for different types.
static constexpr bool on_host
Constexpr variable that is true if all given types have a Host address space.
heap_basic< mem::mallocator< AdrSp > > heap
Alias template of the nda::heap_basic policy using an nda::mem::mallocator.
Definition policies.hpp:52
void memcpy2D(void *dest, size_t dpitch, const void *src, size_t spitch, size_t width, size_t height)
Call CUDA's cudaMemcpy2D function or simulate its behavior on the Host based on the given address spa...
Definition memcpy.hpp:73
static constexpr bool have_device
Constexpr variable that is true if the project is configured with GPU support.
Definition device.hpp:199
constexpr std::array< T, N > apply(std::array< Int, N > const &p, std::array< T, N > const &a)
Apply a permutation to a std::array.
static constexpr bool always_false
Constexpr variable that is always false regardless of the types in Ts (used to trigger static_assert)...
Definition traits.hpp:61
constexpr bool is_scalar_for_v
Constexpr variable used to check requirements when initializing an nda::basic_array or nda::basic_arr...
Definition traits.hpp:83
constexpr bool is_scalar_or_convertible_v
Constexpr variable that is true if type S is a scalar type (see nda::is_scalar_v) or if a std::comple...
Definition traits.hpp:76
Provides a class that maps multi-dimensional indices to a linear index and vice versa.
Provides an iterator for nda::basic_array and nda::basic_array_view types.
Macros used in the nda library.
Provides functions to create and manipulate matrices, i.e. arrays/view with 'M' algebra.
Defines various memory handling policies.
Provides a generic memcpy and memcpy2D function for different address spaces.
Provides a generic memset and memset2D function for different address spaces.
Provides utilities to work with permutations and to compactly encode/decode std::array objects.
Includes the itertools header and provides some additional utilities.
Provides utilities that determine the resulting nda::idx_map when taking a slice of an nda::idx_map.
A small wrapper around a single long integer to be used as a linear index.
Definition traits.hpp:372
Contiguous layout policy with C-order (row-major order).
Definition policies.hpp:36
Memory policy using an nda::mem::handle_borrowed.
Definition policies.hpp:97
Default accessor for various array and view types.
Definition accessors.hpp:25
uint64_t stride_order
Stride order of the array/view.
Definition traits.hpp:326
Provides type traits for the nda library.