From 0f66ba178bcc89634d8b0bdb537e74adcbb5e170 Mon Sep 17 00:00:00 2001 From: Christopher Mauney Date: Fri, 30 Aug 2024 13:45:17 -0600 Subject: [PATCH] array and index algs --- ports-of-call/array.hpp | 7 ++ ports-of-call/portable_arrays.hpp | 155 ++++++++++++--------------- ports-of-call/utility/array_algo.hpp | 81 +++++++++----- ports-of-call/utility/index_algo.hpp | 61 +++++------ test/CMakeLists.txt | 3 +- test/test_mdidx.cpp | 144 +++++++++++++++++++++++++ test/test_utilities.hpp | 19 ++-- 7 files changed, 310 insertions(+), 160 deletions(-) create mode 100644 test/test_mdidx.cpp diff --git a/ports-of-call/array.hpp b/ports-of-call/array.hpp index 8eb90cc0..64569f01 100644 --- a/ports-of-call/array.hpp +++ b/ports-of-call/array.hpp @@ -3,6 +3,7 @@ #include "portability.hpp" #include "portable_errors.hpp" +#include "ports-of-call/utility/array_algo.hpp" #include #include @@ -192,6 +193,12 @@ struct array { } } + PORTABLE_FUNCTION constexpr bool operator==(const array &rhs) const { + for (size_type i = 0; i < N; ++i) + if (arr[i] != rhs.arr[i]) return false; + return true; + } + //! swap the array contents with another PORTABLE_FUNCTION constexpr void swap(array &other) { using std::swap; diff --git a/ports-of-call/portable_arrays.hpp b/ports-of-call/portable_arrays.hpp index d96393ac..72ef43f6 100644 --- a/ports-of-call/portable_arrays.hpp +++ b/ports-of-call/portable_arrays.hpp @@ -24,15 +24,15 @@ // [N4xN3xN2xN1] are accessed as: A(n,k,j,i) = A[i + N1*(j + N2*(k + N3*n))] // NOTE THE TRAILING INDEX INSIDE THE PARENTHESES IS INDEXED FASTEST +#include "array.hpp" #include "portability.hpp" -#include "utility/array.hpp" +#include "utility/array_algo.hpp" #include #include #include #include // size_t #include // memset() #include -#include #include #include #include // swap() @@ -47,12 +47,17 @@ constexpr std::size_t to_const = V; } // namespace detail -template +template +using Array = PortsOfCall::array; + +template +using IArray = Array; + +template class PortableMDArray { public: // explicit initialization of objects - PORTABLE_FUNCTION PortableMDArray(T *data, std::array extents, - std::array strides, + PORTABLE_FUNCTION PortableMDArray(T *data, IArray extents, IArray strides, std::size_t rank) noexcept : pdata_(data), nxs_(extents), strides_(strides), rank_(rank) {} @@ -69,8 +74,23 @@ class PortableMDArray { PortableMDArray() noexcept : pdata_(nullptr), nxs_{{0}}, rank_{0} {} // define copy constructor and overload assignment operator so both do deep // copies. - PortableMDArray(const PortableMDArray &t) noexcept; - PortableMDArray &operator=(const PortableMDArray &t) noexcept; + // PortableMDArray(const PortableMDArray &t) noexcept; + // PortableMDArray &operator=(const PortableMDArray &t) noexcept; + PortableMDArray(const PortableMDArray &src) noexcept { + nxs_ = src.nxs_; + rank_ = src.rank_; + strides_ = src.strides_; + if (src.pdata_) pdata_ = src.pdata_; + } + + PortableMDArray &operator=(const PortableMDArray &src) noexcept { + if (this != &src) { + nxs_ = src.nxs; + rank_ = src.rank_; + pdata_ = src.pdata_; + } + return *this; + } template PORTABLE_FUNCTION void NewPortableMDArray(T *data, NXs... nxs) noexcept { @@ -79,7 +99,12 @@ class PortableMDArray { } // public function to swap underlying data pointers of two equally-sized // arrays - void SwapPortableMDArray(PortableMDArray &array2); + // void SwapPortableMDArray(PortableMDArray &array2); + + void SwapPortableMDArray(PortableMDArray &array2) { + std::swap(pdata_, array2.pdata_); + return; + } // functions to get array dimensions template @@ -115,16 +140,16 @@ class PortableMDArray { } PORTABLE_FORCEINLINE_FUNCTION int GetSize() const { - return util::array_reduce(nxs_, std::multiplies{}); + return util::array_reduce(nxs_, 1, std::multiplies{}); } PORTABLE_FORCEINLINE_FUNCTION std::size_t GetSizeInBytes() const { return GetSize() * sizeof(T); } - PORTABLE_INLINE_FUNCTION size_t GetRank() const { return rank_; } + PORTABLE_INLINE_FUNCTION std::size_t GetRank() const { return rank_; } template PORTABLE_INLINE_FUNCTION void Reshape(NXs... nxs) { - assert(util::array_reduce(std::array{nxs...}, std::multiplies{}) == + assert(util::array_reduce(IArray{nxs...}, 1, std::multiplies{}) == GetSize()); update_layout(nxs...); } @@ -158,19 +183,19 @@ class PortableMDArray { return pdata_[compute_index(idxs...)]; } - PortableMDArray &operator*=(T scale) { + PortableMDArray &operator*=(T scale) { std::transform(pdata_, pdata_ + GetSize(), pdata_, [scale](T val) { return scale * val; }); return *this; } - PortableMDArray &operator+=(const PortableMDArray &other) { + PortableMDArray &operator+=(const PortableMDArray &other) { assert(GetSize() == other.GetSize()); std::transform(pdata_, pdata_ + GetSize(), other.pdata_, pdata_, std::plus()); return *this; } - PortableMDArray &operator-=(const PortableMDArray &other) { + PortableMDArray &operator-=(const PortableMDArray &other) { assert(GetSize() == other.GetSize()); std::transform(pdata_, pdata_ + GetSize(), other.pdata_, pdata_, std::minus()); return *this; @@ -178,23 +203,40 @@ class PortableMDArray { // Checks that arrays point to same data with same shape // note this POINTER equivalence, not data equivalence - bool operator==(const PortableMDArray &other) const; - bool operator!=(const PortableMDArray &other) const { return !(*this == other); } + bool operator==(const PortableMDArray &rhs) const { + return (pdata_ == rhs.pdata_ && nxs_ == rhs.nxs_); // NB rank is implied + } - // (deferred) initialize an array with slice from another array - PORTABLE_FUNCTION - void InitWithShallowSlice(const PortableMDArray &src, const int dim, const int indx, - const int nvar); + bool operator!=(const PortableMDArray &other) const { return !(*this == other); } + + PORTABLE_FUNCTION void InitWithShallowSlice(const PortableMDArray &src, + const int dim, const int indx, + const int nvar) { + pdata_ = src.pdata_; + std::size_t offs = indx; + nxs_[dim - 1] = nvar; + + for (std::size_t i = 0; i < dim - 1; ++i) { + nxs_[i] = src.nxs_[i]; + offs *= nxs_[i]; + } + for (std::size_t i = dim; i < MAXDIM; ++i) { + nxs_[i] = 1; + } + pdata_ += offs; + + return; + } private: template PORTABLE_FORCEINLINE_FUNCTION auto make_nxs_array(NX... nxs) { - std::array a; - std::array t{static_cast(nxs)...}; + IArray a; + IArray t{static_cast(nxs)...}; for (auto i = 0; i < N; ++i) { a[i] = t[N - i - 1]; } - for (auto i = N; i < MAXDIM; ++i) { + for (auto i = N; i < D; ++i) { a[i] = 1; } return a; @@ -202,12 +244,12 @@ class PortableMDArray { template PORTABLE_INLINE_FUNCTION auto make_strides_array() { - std::array a; + IArray a; a[0] = 1; for (auto i = 1; i < N; ++i) { a[i] = a[i - 1] * nxs_[i - 1]; } - for (auto i = N; i < MAXDIM; ++i) + for (auto i = N; i < D; ++i) a[i] = 0; return a; @@ -244,41 +286,12 @@ class PortableMDArray { } T *pdata_; - std::array nxs_; - std::array strides_; + IArray nxs_; + IArray strides_; int rank_; -}; - -// copy constructor (does a shallow copy) - -template -PortableMDArray::PortableMDArray(const PortableMDArray &src) noexcept { - nxs_ = src.nxs_; - rank_ = src.rank_; - strides_ = src.strides_; - if (src.pdata_) pdata_ = src.pdata_; -} - -// shallow copy assignment operator - -template -PortableMDArray & -PortableMDArray::operator=(const PortableMDArray &src) noexcept { - if (this != &src) { - nxs_ = src.nxs; - rank_ = src.rank_; - pdata_ = src.pdata_; - } - return *this; -} - -// Checks that arrays point to same data with same shape -// note this POINTER equivalence, not data equivalence -template -bool PortableMDArray::operator==(const PortableMDArray &rhs) const { - return (pdata_ == rhs.pdata_ && nxs_ == rhs.nxs_); // NB rank is implied -} + public: +}; //---------------------------------------------------------------------------------------- //! \fn PortableMDArray::InitWithShallowSlice() // \brief shallow copy of nvar elements in dimension dim of an array, @@ -288,36 +301,10 @@ bool PortableMDArray::operator==(const PortableMDArray &rhs) const { // entries of the src array for d -PORTABLE_FUNCTION void -PortableMDArray::InitWithShallowSlice(const PortableMDArray &src, const int dim, - const int indx, const int nvar) { - pdata_ = src.pdata_; - std::size_t offs = indx; - nxs_[dim - 1] = nvar; - - for (std::size_t i = 0; i < dim - 1; ++i) { - nxs_[i] = src.nxs_[i]; - offs *= nxs_[i]; - } - for (std::size_t i = dim; i < MAXDIM; ++i) { - nxs_[i] = 1; - } - pdata_ += offs; - - return; -} - //---------------------------------------------------------------------------------------- //! \fn PortableMDArray::SwapPortableMDArray() // \brief swap pdata_ pointers of two equally sized PortableMDArrays // (shallow swap) // Does not allocate memory for either array -template -void PortableMDArray::SwapPortableMDArray(PortableMDArray &array2) { - std::swap(pdata_, array2.pdata_); - return; -} - #endif // _PORTABLE_ARRAYS_HPP_ diff --git a/ports-of-call/utility/array_algo.hpp b/ports-of-call/utility/array_algo.hpp index e4c52944..f10d09c1 100644 --- a/ports-of-call/utility/array_algo.hpp +++ b/ports-of-call/utility/array_algo.hpp @@ -7,65 +7,88 @@ namespace util { +template +constexpr auto +is(std::integral_constant) { // = std::make_index_sequence; + return std::make_index_sequence{}; +} + +template +using value_t = typename A::value_type; + +template +using reduction_value_t = + decltype(std::declval()(std::declval>(), std::declval>())); + namespace detail { -template -PORTABLE_FORCEINLINE_FUNCTION constexpr auto -array_map_impl(std::array const &x, F f, std::index_sequence) { +template +PORTABLE_FORCEINLINE_FUNCTION constexpr auto array_map_impl(A const &x, F f, + std::index_sequence) { return std::array{f(x[Is])...}; } -template -PORTABLE_FORCEINLINE_FUNCTION constexpr auto -array_map_impl(std::array const &x, std::array const &y, F f, - std::index_sequence) { - return std::array{f(x[Is], y[Is])...}; +template +PORTABLE_FORCEINLINE_FUNCTION constexpr auto array_map_impl(A const &x, B const &y, F f, + std::index_sequence) { + return A{f(x[Is], y[Is])...}; } -template -PORTABLE_INLINE_FUNCTION constexpr T array_reduce_impl(std::array const &x, Op op) { +template +PORTABLE_INLINE_FUNCTION constexpr auto array_reduce_impl(A const &x, Op op) { if constexpr ((l - f) == 1) return x[f]; else { constexpr std::size_t n = l - f; - T left_sum = array_reduce_impl(x, op); - T right_sum = array_reduce_impl(x, op); + auto left_sum = array_reduce_impl(x, op); + auto right_sum = array_reduce_impl(x, op); return op(left_sum, right_sum); } } } // namespace detail -template -PORTABLE_FORCEINLINE_FUNCTION constexpr auto array_map(std::array const &x, F f) { - return detail::array_map_impl(x, f, std::make_index_sequence{}); +template +PORTABLE_FORCEINLINE_FUNCTION constexpr auto array_map(A const &x, F f) { + return detail::array_map_impl(x, f, is(x.size())); } -template -PORTABLE_FORCEINLINE_FUNCTION constexpr auto array_map(std::array const &x, - std::array const &y, F f) { - return detail::array_map_impl(x, y, f, std::make_index_sequence{}); +template +PORTABLE_FORCEINLINE_FUNCTION constexpr auto array_map(A const &x, B const &y, F f) { + return detail::array_map_impl(x, y, f, is(x.size())); } -template -PORTABLE_FORCEINLINE_FUNCTION constexpr T array_partial_reduce(std::array x, - T initial_value, Op op) { - static_assert(I <= N); +template > +PORTABLE_FORCEINLINE_FUNCTION constexpr T array_partial_reduce(A x, T initial_value, + Op op) { + static_assert(I <= x.size()); if constexpr (I == 0) return initial_value; else return detail::array_reduce_impl<0, I>(x, op); } -template -PORTABLE_FORCEINLINE_FUNCTION constexpr T array_reduce(std::array x, - T initial_value, Op op) { - return array_partial_reduce(x, initial_value, op); +template > + +PORTABLE_FORCEINLINE_FUNCTION constexpr T array_reduce(A x, T initial_value, Op op) { + return array_partial_reduce(x, initial_value, op); +} +/* +namespace detail { +template +PORTABLE_FORCEINLINE_FUNCTION constexpr bool +arrays_equal_impl(const A &x, const A &y, std::index_sequence) { + return (... && (x[I] == y[I])); } -template +} // namespace detail +template +PORTABLE_FORCEINLINE_FUNCTION constexpr bool arrays_equal(const A &x, const A &y) { + return detail::arrays_equal_impl(x, y, is(x.size())); +}*/ +/*template PORTABLE_FORCEINLINE_FUNCTION constexpr auto as_array(std::index_sequence) { return std::array{Is...}; -} +}*/ } // namespace util diff --git a/ports-of-call/utility/index_algo.hpp b/ports-of-call/utility/index_algo.hpp index 31a5d8e8..efc4b3b3 100644 --- a/ports-of-call/utility/index_algo.hpp +++ b/ports-of-call/utility/index_algo.hpp @@ -2,14 +2,15 @@ #define _PORTSOFCALL_UTILITY_INDEX_ALGO_HPP_ #include "../portability.hpp" -#include "array.hpp" +#include "array_algo.hpp" #include #include #include namespace util { -template +/* + template PORTABLE_FORCEINLINE_FUNCTION static constexpr auto get_stride(std::array const &dim) { static_assert(I < dim.size(), "Dim index is out of bounds"); @@ -48,48 +49,41 @@ PORTABLE_FORCEINLINE_FUNCTION static constexpr auto findex(std::array const &ijk, std::array const &dim) { return fast_findex(ijk, dim, get_strides(dim)); } - -namespace handroll { -template -PORTABLE_FORCEINLINE_FUNCTION static constexpr auto -get_stride(std::array const &dim) { +*/ +template +PORTABLE_FORCEINLINE_FUNCTION static constexpr auto get_stride(A const &dim) { // column major - return array_partial_reduce(dim, T{1}, std::multiplies{}); + return array_partial_reduce(dim, value_t{1}, std::multiplies{}); } namespace detail { -template +template PORTABLE_FORCEINLINE_FUNCTION static constexpr auto -get_strides_impl(std::array const &dim, std::index_sequence) { - return std::array{get_stride(dim)...}; +get_strides_impl(A const &dim, std::index_sequence) { + return A{get_stride(dim)...}; } -template -PORTABLE_FORCEINLINE_FUNCTION static constexpr auto -get_strides(std::array const &dim) { - return detail::get_strides_impl(dim, std::make_index_sequence{}); -} // namespace handroll::detail -template +template +PORTABLE_FORCEINLINE_FUNCTION static constexpr auto get_strides(A const &dim) { + return detail::get_strides_impl(dim, is(dim.size())); +} +} // namespace detail +template PORTABLE_FORCEINLINE_FUNCTION static constexpr auto -fast_findex(std::array const &ijk, std::array const &dim, - std::array const &stride) { +fast_findex(A const &ijk, A const &dim, A const &stride) { // TODO: assert ijk in bounds - return array_reduce( - array_map(ijk, stride, [](auto a, auto b) { return a * b; }), T{1}, - std::plus{}); + return array_reduce(array_map(ijk, stride, [](auto a, auto b) { return a * b; }), + value_t{1}, std::plus{}); } -template -PORTABLE_FORCEINLINE_FUNCTION static constexpr auto -findex(std::array const &ijk, std::array const &dim) { +template +PORTABLE_FORCEINLINE_FUNCTION static constexpr auto findex(A const &ijk, A const &dim) { return fast_findex(ijk, dim, get_strides(dim)); } -} // namespace handroll -template -PORTABLE_FORCEINLINE_FUNCTION static constexpr std::array -fast_mindices(std::size_t idx, std::array const &dim, - std::array const &stride) { - std::array mdidx; +template +PORTABLE_FORCEINLINE_FUNCTION static constexpr A +fast_mindices(std::size_t idx, A const &dim, A const &stride) { + A mdidx; for (std::int64_t i = dim.size() - 1; i >= 0; --i) { mdidx[i] = idx / std::size_t(stride[i]); idx -= mdidx[i] * std::size_t(stride[i]); @@ -97,9 +91,8 @@ fast_mindices(std::size_t idx, std::array const &dim, return mdidx; } -template -PORTABLE_FORCEINLINE_FUNCTION static constexpr auto mindices(std::size_t idx, - Array dim) { +template +PORTABLE_FORCEINLINE_FUNCTION static constexpr auto mindices(std::size_t idx, A dim) { return fast_mindices(idx, dim, get_strides(dim)); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 65d5d205..00e1ed3a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,4 +47,5 @@ target_link_libraries(test_portsofcall PRIVATE ports-of-call::ports-of-call include(Catch) catch_discover_tests(test_portsofcall) -target_sources(test_portsofcall PRIVATE test_portability.cpp test_array.cpp) +target_sources(test_portsofcall PRIVATE test_portability.cpp test_array.cpp + test_mdidx.cpp) diff --git a/test/test_mdidx.cpp b/test/test_mdidx.cpp new file mode 100644 index 00000000..dbf9b964 --- /dev/null +++ b/test/test_mdidx.cpp @@ -0,0 +1,144 @@ +// © (or copyright) 2019-2024. Triad National Security, LLC. All rights +// reserved. This program was produced under U.S. Government contract +// 89233218CNA000001 for Los Alamos National Laboratory (LANL), which is +// operated by Triad National Security, LLC for the U.S. Department of +// Energy/National Nuclear Security Administration. All rights in the +// program are reserved by Triad National Security, LLC, and the +// U.S. Department of Energy/National Nuclear Security +// Administration. The Government is granted for itself and others acting +// on its behalf a nonexclusive, paid-up, irrevocable worldwide license +// in this material to reproduce, prepare derivative works, distribute +// copies to the public, perform publicly and display publicly, and to +// permit others to do so. + +#include +#include +#include +#include + +#include "test_utilities.hpp" + +#ifndef CATCH_CONFIG_FAST_COMPILE +#define CATCH_CONFIG_FAST_COMPILE +#include +#include +#include +#include +#endif + +TEST_CASE("PortableMDArrays Sizes are sane", "[PortableMDArray]") { + using tape_t = std::vector; + + constexpr std::array nxs{2, 5, 10, 10, 5, 2}; + + std::vector subsz(MAXDIM); + std::vector dats; + + std::partial_sum(nxs.cbegin(), nxs.cend(), subsz.begin(), std::multiplies()); + for (auto i = 0; i < MAXDIM; ++i) { + dats.push_back(std::vector(subsz[i], nxs[i])); + } + + SECTION("Can construct correctly") { + auto pmd1 = PortableMDArray(dats[0].data(), nxs[0]); + + REQUIRE(pmd1.GetSize() == subsz[0]); + REQUIRE(pmd1.GetRank() == 1); + + auto pmd3 = PortableMDArray(dats[3].data(), nxs[0], nxs[1], nxs[2]); + + REQUIRE(pmd3.GetSize() == subsz[2]); + REQUIRE(pmd3.GetRank() == 3); + REQUIRE(pmd3.GetDim1() == nxs[2]); + REQUIRE(pmd3.GetDim2() == nxs[1]); + REQUIRE(pmd3.GetDim3() == nxs[0]); + } +} + +TEST_CASE("Correct portable indexing", "[PortableMDArray]") { + // layout + auto iflat = [](auto nx, auto nxny) { + return [=](auto k, auto j, auto i) { return i + nx * j + nxny * k; }; + }; + + constexpr std::size_t NX = 32, NY = 64, NZ = 4; + constexpr std::size_t NC = NX * NY * NZ; + constexpr Real scale = 0.1; + // size in bytes + constexpr const std::size_t NCb = NC * sizeof(Real); + + // vector length N on host of Real + std::vector tape_ref(NC), tape_buf(NC); + + for (auto n = 0; n < NC; ++n) { + tape_ref[n] = scale * static_cast(n); + } + + // device pointer + Real *tape_d = (Real *)PORTABLE_MALLOC(NCb); + + auto view_d = PortableMDArray(tape_d, NZ, NY, NX); + + // set device values + portableFor( + "set unique val", 0, NZ, 0, NY, 0, NX, + PORTABLE_LAMBDA(const int &k, const int &j, const int &i) { + view_d(k, j, i) = scale * iflat(NX, NX * NY)(k, j, i); + }); + + portableCopyToHost(tape_buf.data(), tape_d, NCb); + + for (auto n = 0; n < NC; ++n) { + INFO("REF=" << tape_ref[n] << " BUF=" << tape_buf[n] << " n=" << n); + REQUIRE_THAT(tape_buf[n], Catch::Matchers::WithinRel(tape_ref[n])); + } + + PORTABLE_FREE(tape_d); +} + +// runs benchmarks for indexing. +// note: to run, execute +// ./tests/test_portsofcall "[!benchmark]" +// (you may need to escape the `!` char depending +// on your shell) +TEST_CASE("Benchmark Indexing", "[!benchmark]") { + constexpr std::size_t NX = 32, NY = 64, NZ = 16; + constexpr std::size_t NU = 256, NV = 256, NW = 128; + + // construct a series of PortableMDArrays + // of different rank and sizes, and + // iterates through all contiguous indexing. + + // clang-format off + SECTION("small") { + BENCHMARK("index calc 1D") + { + return testing::idx_contiguous_bm(std::array{NX}); + }; + BENCHMARK("index calc 2D") + { + return testing::idx_contiguous_bm(std::array{NX, NY}); + }; + BENCHMARK("index calc 3D") + { + return testing::idx_contiguous_bm(std::array{NX, NY, NZ}); + }; + } + + SECTION("big") { + BENCHMARK("index calc 1D") + { + return testing::idx_contiguous_bm(std::array{NU}); + }; + BENCHMARK("index calc 2D") + { + return testing::idx_contiguous_bm(std::array{NU, NV}); + }; + BENCHMARK("index calc 3D") + { + return testing::idx_contiguous_bm(std::array{NU, NV, NW}); + }; + + } + // clang-format on +} diff --git a/test/test_utilities.hpp b/test/test_utilities.hpp index 2d5ad3fb..0cb2de41 100644 --- a/test/test_utilities.hpp +++ b/test/test_utilities.hpp @@ -1,9 +1,8 @@ #ifndef _TEST_PORTOFCALL_HPP_ #define _TEST_PORTOFCALL_HPP_ -#include <__utility/integer_sequence.h> -#include #include +#include #include #include #include @@ -27,10 +26,8 @@ constexpr auto array_fix_impl(const Array &a, std::index_sequence is) { // it into an array 2N {0, NX} contiguous pairs. // ex: // array{10,12,13} -> array{0,10,0,12,0,13} -template > -PORTABLE_FORCEINLINE_FUNCTION constexpr auto -array_fix(const std::array &a) { +template > +PORTABLE_FORCEINLINE_FUNCTION constexpr auto array_fix(const std::array &a) { return array_fix_impl(a, Indx{}); } @@ -50,13 +47,12 @@ PORTABLE_INLINE_FUNCTION constexpr auto pf_invoke(View v, const Array &ext_par, auto stud_arr = array_fix(ext_par); portableFor( - "set unique val", stud_arr[J]..., - PORTABLE_LAMBDA(auto... is) { v(is...) = 1.0; }); + "set unique val", stud_arr[J]..., PORTABLE_LAMBDA(auto... is) { v(is...) = 1.0; }); } template -PORTABLE_FORCEINLINE_FUNCTION constexpr decltype(auto) -mdview(Ptr *d, const Array &arr, std::index_sequence) { +PORTABLE_FORCEINLINE_FUNCTION constexpr decltype(auto) mdview(Ptr *d, const Array &arr, + std::index_sequence) { return PortableMDArray(d, arr[I]...); } @@ -65,8 +61,7 @@ mdview(Ptr *d, const Array &arr, std::index_sequence) { template , typename I2 = std::make_index_sequence<2 * N>> PORTABLE_FUNCTION auto idx_contiguous_bm(const std::array &nxa) { - auto nc = - std::accumulate(std::begin(nxa), std::end(nxa), 1, std::multiplies{}); + auto nc = std::accumulate(std::begin(nxa), std::end(nxa), 1, std::multiplies{}); Real *tape_d = (Real *)PORTABLE_MALLOC(nc * sizeof(Real));