#ifndef included_ArrayClass_hpp #define included_ArrayClass_hpp #include "common/Array.h" #include "common/Utilities.h" #include #include #include #include /******************************************************** * Constructors * ********************************************************/ template Array::Array() { d_ndim = 1; d_length = 0; for ( size_t i = 0; i < ARRAY_NDIM_MAX; i++ ) d_N[i] = 1; d_N[0] = 0; d_data = nullptr; } template Array::Array( size_t N ) { allocate( std::vector( 1, N ) ); } template Array::Array( size_t N_rows, size_t N_columns ) { std::vector N( 2 ); N[0] = N_rows; N[1] = N_columns; allocate( N ); } template Array::Array( size_t N1, size_t N2, size_t N3 ) { std::vector N( 3 ); N[0] = N1; N[1] = N2; N[2] = N3; allocate( N ); } template Array::Array( const std::vector &N, const TYPE *data ) { allocate( N ); if ( data != NULL ) { for ( size_t i = 0; i < d_length; i++ ) d_data[i] = data[i]; } } template void Array::allocate( const std::vector &N ) { d_ndim = static_cast( N.size() ); d_length = 1; for ( size_t i = 0; i < ARRAY_NDIM_MAX; i++ ) d_N[i] = 1; for ( size_t i = 0; i < N.size(); i++ ) { d_N[i] = N[i]; d_length *= N[i]; } if ( N.empty() ) { d_N[0] = 0; d_length = 0; } if ( d_length == 0 ) d_ptr.reset(); else d_ptr.reset( new ( std::nothrow ) TYPE[d_length], []( TYPE *p ) { delete[] p; } ); d_data = d_ptr.get(); if ( d_length > 0 && d_data == nullptr ) throw std::logic_error( "Failed to allocate array" ); } template Array::Array( const Array &rhs ) : d_ndim( rhs.d_ndim ), d_length( rhs.d_length ), d_data( nullptr ) { allocate( rhs.size() ); for ( size_t i = 0; i < d_length; i++ ) d_data[i] = rhs.d_data[i]; } template Array::Array( Array &&rhs ) : d_ndim( rhs.d_ndim ), d_length( rhs.d_length ), d_data( rhs.d_data ) { rhs.d_ndim = 0; memcpy( d_N, rhs.d_N, sizeof( rhs.d_N ) ); memset( rhs.d_N, 0, sizeof( rhs.d_N ) ); rhs.d_length = 0; rhs.d_data = nullptr; d_ptr = std::move( rhs.d_ptr ); } template Array &Array::operator=( const Array &rhs ) { if ( this == &rhs ) return *this; this->allocate( rhs.size() ); for ( size_t i = 0; i < d_length; i++ ) this->d_data[i] = rhs.d_data[i]; return *this; } template Array &Array::operator=( Array &&rhs ) { if ( this == &rhs ) return *this; d_ndim = rhs.d_ndim; rhs.d_ndim = 0; memcpy( d_N, rhs.d_N, sizeof( rhs.d_N ) ); memset( rhs.d_N, 0, sizeof( rhs.d_N ) ); d_length = rhs.d_length; rhs.d_length = 0; d_data = rhs.d_data; rhs.d_data = nullptr; d_ptr = std::move( rhs.d_ptr ); return *this; } template Array &Array::operator=( const std::vector &rhs ) { this->allocate( std::vector( 1, rhs.size() ) ); for ( size_t i = 0; i < rhs.size(); i++ ) this->d_data[i] = rhs[i]; return *this; } template Array::~Array() { } template void Array::clear() { d_ndim = 0; d_length = 0; for ( size_t i = 0; i < ARRAY_NDIM_MAX; i++ ) d_N[i] = 1; d_N[0] = 0; d_ptr.reset(); d_data = nullptr; } /******************************************************** * Check if the size of the array matches rhs * ********************************************************/ template template bool Array::sizeMatch( const Array& rhs ) const { bool test = d_ndim == rhs.d_ndim; for ( int d = 0; d < d_ndim; d++ ) test = test && d_N[d] == rhs.d_N[d]; return test; } /******************************************************** * Resize the array * ********************************************************/ template void Array::resize( size_t N ) { resize( std::vector{N} ); } template void Array::resize( size_t N1, size_t N2 ) { resize( std::vector{N1,N2} ); } template void Array::resize( size_t N1, size_t N2, size_t N3 ) { resize( std::vector{N1,N2,N3} ); } template void Array::resize( const std::vector &N ) { // Check if the array actually changed size size_t new_length = 1; for ( size_t i = 0; i < N.size(); i++ ) new_length *= N[i]; if ( N.empty() ) new_length = 0; bool changed = new_length != d_length || (int) N.size() != d_ndim; for ( size_t i = 0; i < N.size(); i++ ) changed = changed || N[i] != d_N[i]; if ( !changed ) return; // Store the old data #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif std::array N1{ { 1, 1, 1, 1, 1 } }; std::array N2{ { 1, 1, 1, 1, 1 } }; for ( int d = 0; d < d_ndim; d++ ) N1[d] = d_N[d]; for ( size_t d = 0; d < N.size(); d++ ) N2[d] = N[d]; if ( d_ndim == 0 ) { N1[0] = 0; } if ( N.empty() ) { N2[0] = 0; } std::shared_ptr old_data = d_ptr; // Allocate new data allocate( N ); // Copy the old values if ( d_length > 0 ) { TYPE *data1 = old_data.get(); TYPE *data2 = d_data; if ( old_data.unique() ) { // We own the data, use std:move for ( size_t i5 = 0; i5 < std::min( N1[4], N2[4] ); i5++ ) { for ( size_t i4 = 0; i4 < std::min( N1[3], N2[3] ); i4++ ) { for ( size_t i3 = 0; i3 < std::min( N1[2], N2[2] ); i3++ ) { for ( size_t i2 = 0; i2 < std::min( N1[1], N2[1] ); i2++ ) { for ( size_t i1 = 0; i1 < std::min( N1[0], N2[0] ); i1++ ) { size_t index1 = GET_ARRAY_INDEX5D( N1, i1, i2, i3, i4, i5 ); size_t index2 = GET_ARRAY_INDEX5D( N2, i1, i2, i3, i4, i5 ); data2[index2] = std::move( data1[index1] ); } } } } } } else { // We do not own the data, copy for ( size_t i5 = 0; i5 < std::min( N1[4], N2[4] ); i5++ ) { for ( size_t i4 = 0; i4 < std::min( N1[3], N2[3] ); i4++ ) { for ( size_t i3 = 0; i3 < std::min( N1[2], N2[2] ); i3++ ) { for ( size_t i2 = 0; i2 < std::min( N1[1], N2[1] ); i2++ ) { for ( size_t i1 = 0; i1 < std::min( N1[0], N2[0] ); i1++ ) { size_t index1 = GET_ARRAY_INDEX5D( N1, i1, i2, i3, i4, i5 ); size_t index2 = GET_ARRAY_INDEX5D( N2, i1, i2, i3, i4, i5 ); data2[index2] = data1[index1]; } } } } } } } } template void Array::resizeDim( int dim, size_t N, const TYPE &value ) { if ( dim >= d_ndim ) throw std::logic_error( "Invalid dimension" ); std::vector N2 = size(); size_t N0 = N2[dim]; N2[dim] = N; resize( N2 ); size_t n1 = 1, n2 = 1; for ( int d = 0; d < dim; d++ ) n1 *= N2[d]; for ( size_t d = dim + 1; d < N2.size(); d++ ) n2 *= N2[d]; for ( size_t k = 0; k < n2; k++ ) { for ( size_t j = N0; j < N; j++ ) { for ( size_t i = 0; i < n1; i++ ) { d_data[i + j * n1 + k * n1 * N] = value; } } } } /******************************************************** * Reshape the array * ********************************************************/ template void Array::reshape( const std::vector &N ) { size_t new_length = 1; for ( size_t i = 0; i < N.size(); i++ ) new_length *= N[i]; if ( new_length != d_length ) throw std::logic_error( "reshape is not allowed to change the array size" ); d_ndim = N.size(); for ( size_t i = 0; i < ARRAY_NDIM_MAX; i++ ) d_N[i] = 1; for ( size_t i = 0; i < N.size(); i++ ) d_N[i] = N[i]; } /******************************************************** * Subset the array * ********************************************************/ // clang-format off // Helper function to check subset indices template inline void Array::checkSubsetIndex( const std::vector &index ) const { bool test = index.size() % 2 == 0 && (int) index.size() / 2 <= d_ndim; for ( size_t d = 0; d < index.size() / 2; d++ ) test = test && index[2 * d + 0] < d_N[d] && index[2 * d + 1] < d_N[d]; if ( !test ) throw std::logic_error( "indices for subset are invalid" ); } // Helper function to return dimensions as a std::array for hard coded loops template inline std::array Array::getDimArray() const { #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif std::array N{ { 1, 1, 1, 1, 1 } }; for ( int d = 0; d < d_ndim; d++ ) N[d] = d_N[d]; return N; } // Helper function to return dimensions for the subset array template inline void Array::getSubsetArrays( const std::vector &index, std::array &first, std::array &last, std::array &N ) { #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif size_t ndim = index.size() / 2; for ( size_t d = 0; d < ndim; d++ ) { first[d] = index[2 * d + 0]; last[d] = index[2 * d + 1]; N[d] = last[d] - first[d] + 1; } for ( size_t d = ndim; d < 5; d++ ) { first[d] = 0; last[d] = 0; N[d] = 1; } } template template Array Array::subset( const std::vector &index ) const { // Get the subset indicies checkSubsetIndex( index ); std::array first, last, N1; getSubsetArrays( index, first, last, N1 ); std::array N2 = getDimArray(); // Create the new array std::vector dim( d_ndim ); for ( int d = 0; d < d_ndim; d++ ) dim[d] = last[d] - first[d] + 1; Array subset( dim ); // Fill the new array #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif TYPE2 *subset_data = subset.data(); for (size_t i4=first[4]; i4<=last[4]; i4++) { for (size_t i3=first[3]; i3<=last[3]; i3++) { for (size_t i2=first[2]; i2<=last[2]; i2++) { for (size_t i1=first[1]; i1<=last[1]; i1++) { for (size_t i0=first[0]; i0<=last[0]; i0++) { size_t k1 = GET_ARRAY_INDEX5D( N1, i0-first[0], i1-first[1], i2-first[2], i3-first[3], i4-first[4] ); size_t k2 = GET_ARRAY_INDEX5D( N2, i0, i1, i2, i3, i4 ); subset_data[k1] = static_cast( d_data[k2] ); } } } } } return subset; } template template void Array::copySubset( const std::vector &index, const Array &subset ) { // Get the subset indices checkSubsetIndex( index ); std::array first, last, N1; getSubsetArrays( index, first, last, N1 ); std::array N2 = getDimArray(); // Copy the sub-array #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif const TYPE2 *src_data = subset.data(); for (size_t i4=first[4]; i4<=last[4]; i4++) { for (size_t i3=first[3]; i3<=last[3]; i3++) { for (size_t i2=first[2]; i2<=last[2]; i2++) { for (size_t i1=first[1]; i1<=last[1]; i1++) { for (size_t i0=first[0]; i0<=last[0]; i0++) { size_t k1 = GET_ARRAY_INDEX5D( N1, i0-first[0], i1-first[1], i2-first[2], i3-first[3], i4-first[4] ); size_t k2 = GET_ARRAY_INDEX5D( N2, i0, i1, i2, i3, i4 ); d_data[k2] = static_cast( src_data[k1] ); } } } } } } template void Array::addSubset( const std::vector &index, const Array &subset ) { // Get the subset indices checkSubsetIndex( index ); std::array first, last, N1; getSubsetArrays( index, first, last, N1 ); std::array N2 = getDimArray(); // add the sub-array #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif for (size_t i4=first[4]; i4<=last[4]; i4++) { for (size_t i3=first[3]; i3<=last[3]; i3++) { for (size_t i2=first[2]; i2<=last[2]; i2++) { for (size_t i1=first[1]; i1<=last[1]; i1++) { for (size_t i0=first[0]; i0<=last[0]; i0++) { size_t k1 = GET_ARRAY_INDEX5D( N1, i0-first[0], i1-first[1], i2-first[2], i3-first[3], i4-first[4] ); size_t k2 = GET_ARRAY_INDEX5D( N2, i0, i1, i2, i3, i4 ); d_data[k2] += subset.d_data[k1]; } } } } } } // clang-format on /******************************************************** * Operator overloading * ********************************************************/ template bool Array::operator==( const Array &rhs ) const { if ( this == &rhs ) return true; if ( d_length != rhs.d_length ) return false; if ( d_ndim != rhs.d_ndim ) return false; for ( int d = 0; d < d_ndim; d++ ) { if ( d_N[d] != rhs.d_N[d] ) return false; } bool match = true; for ( size_t i = 0; i < d_length; i++ ) match = match && d_data[i] == rhs.d_data[i]; return match; } /******************************************************** * Get a view of an C array * ********************************************************/ template std::shared_ptr> Array::view( size_t N, std::shared_ptr const &data ) { return view( std::vector{N}, data ); } template std::shared_ptr> Array::view( size_t N1, size_t N2, std::shared_ptr const &data ) { return view( std::vector{N1,N2}, data ); } template std::shared_ptr> Array::view( size_t N1, size_t N2, size_t N3, std::shared_ptr const &data ) { return view( std::vector{N1,N2,N3}, data ); } template std::shared_ptr> Array::constView( size_t N, std::shared_ptr const &data ) { return constView( std::vector{N}, data ); } template std::shared_ptr> Array::constView( size_t N1, size_t N2, std::shared_ptr const &data ) { return constView( std::vector{N1,N2}, data ); } template std::shared_ptr> Array::constView( size_t N1, size_t N2, size_t N3, std::shared_ptr const &data ) { return constView( std::vector{N1,N2,N3}, data ); } template std::shared_ptr> Array::view( const std::vector &N, std::shared_ptr const &data ) { std::shared_ptr> array( new Array() ); array->d_ndim = N.size(); array->d_length = 1; for ( size_t i = 0; i < N.size(); i++ ) { array->d_N[i] = N[i]; array->d_length *= N[i]; } if ( array->d_ndim == 0 ) array->d_length = 0; array->d_ptr = data; array->d_data = array->d_ptr.get(); return array; } template std::shared_ptr> Array::constView( const std::vector &N, std::shared_ptr const &data ) { return view( N, std::const_pointer_cast( data ) ); } template void Array::view2( Array &src ) { view2( src.size(), src.getPtr() ); d_data = src.d_data; } template void Array::view2( const std::vector &N, std::shared_ptr const &data ) { d_ndim = static_cast( N.size() ); for ( size_t i = 0; i < ARRAY_NDIM_MAX; i++ ) { d_N[i] = 1; } d_length = d_ndim == 0 ? 0 : 1; for ( size_t i = 0; i < N.size(); i++ ) { d_N[i] = N[i]; d_length *= d_N[i]; } d_ptr = data; d_data = d_ptr.get(); } template void Array::viewRaw( const std::initializer_list &N, TYPE *data ) { d_ndim = static_cast( N.size() ); for ( size_t i = 0; i < ARRAY_NDIM_MAX; i++ ) { d_N[i] = 1; } d_length = d_ndim == 0 ? 0 : 1; size_t i = 0; for ( auto it = N.begin(); it != N.end(); ++it, ++i ) { d_N[i] = *it; d_length *= *it; } d_ptr.reset(); d_data = data; } template void Array::viewRaw( const std::vector &N, TYPE *data ) { d_ndim = static_cast( N.size() ); for ( size_t i = 0; i < ARRAY_NDIM_MAX; i++ ) { d_N[i] = 1; } d_length = d_ndim == 0 ? 0 : 1; size_t i = 0; for ( auto it = N.begin(); it != N.end(); ++it, ++i ) { d_N[i] = *it; d_length *= *it; } d_ptr.reset(); d_data = data; } /******************************************************** * Convert array types * ********************************************************/ template template std::shared_ptr> Array::convert( std::shared_ptr> array ) { if ( std::is_same() ) return array; std::shared_ptr> array2( new Array( array->size() ) ); array2.copy( *array ); return array2; } template template std::shared_ptr> Array::convert( std::shared_ptr> array ) { return Array::convert( std::const_pointer_cast>( array ) ); } template template void Array::copy( const Array &array ) { resize( array.size() ); const TYPE2 *src = array.data(); for ( size_t i = 0; i < d_length; i++ ) d_data[i] = static_cast( src[i] ); } template template void Array::copy( const TYPE2 *src ) { for ( size_t i = 0; i < d_length; i++ ) d_data[i] = static_cast( src[i] ); } template template void Array::copyTo( TYPE2 *dst ) const { for ( size_t i = 0; i < d_length; i++ ) dst[i] = static_cast( d_data[i] ); } template void Array::fill( const TYPE &value ) { for ( size_t i = 0; i < d_length; i++ ) d_data[i] = value; } template void Array::scale( const TYPE &value ) { for ( size_t i = 0; i < d_length; i++ ) d_data[i] *= value; } template void Array::pow(const Array &baseArray, const TYPE &exp ) { // not insisting on the shapes being the same // but insisting on the total size being the same AMP_ASSERT(d_length==baseArray.length()); const auto base_data = baseArray.data(); for ( size_t i = 0; i < d_length; i++ ) d_data[i] = std::pow(base_data[i], exp); } /******************************************************** * Simple math operations * ********************************************************/ template bool Array::NaNs() const { bool test = false; for ( size_t i = 0; i < d_length; i++ ) test = test || d_data[i] != d_data[i]; return test; } template TYPE Array::min() const { TYPE x = std::numeric_limits::max(); for ( size_t i = 0; i < d_length; i++ ) x = std::min( x, d_data[i] ); return x; } template TYPE Array::max() const { TYPE x = std::numeric_limits::min(); for ( size_t i = 0; i < d_length; i++ ) x = std::max( x, d_data[i] ); return x; } template TYPE Array::sum() const { TYPE x = 0; for ( size_t i = 0; i < d_length; i++ ) x += d_data[i]; return x; } template TYPE Array::mean( void ) const { TYPE x = sum() / d_length; return x; } template Array Array::min( int dir ) const { std::vector size_ans = size(); size_ans[dir] = 1; Array ans( size_ans ); size_t N1 = 1, N2 = 1, N3 = 1; for ( int d = 0; d < std::min( dir, d_ndim ); d++ ) N1 *= d_N[d]; N2 = d_N[dir]; for ( int d = dir + 1; d < std::min( d_ndim, ARRAY_NDIM_MAX ); d++ ) N3 *= d_N[d]; TYPE *data2 = ans.d_data; for ( size_t i3 = 0; i3 < N3; i3++ ) { for ( size_t i1 = 0; i1 < N1; i1++ ) { TYPE x = d_data[i1 + i3 * N1 * N2]; for ( size_t i2 = 0; i2 < N2; i2++ ) x = std::min( x, d_data[i1 + i2 * N1 + i3 * N1 * N2] ); data2[i1 + i3 * N1] = x; } } return ans; } template Array Array::max( int dir ) const { std::vector size_ans = size(); size_ans[dir] = 1; Array ans( size_ans ); size_t N1 = 1, N2 = 1, N3 = 1; for ( int d = 0; d < std::min( dir, d_ndim ); d++ ) N1 *= d_N[d]; N2 = d_N[dir]; for ( int d = dir + 1; d < std::min( d_ndim, ARRAY_NDIM_MAX ); d++ ) N3 *= d_N[d]; TYPE *data2 = ans.d_data; for ( size_t i3 = 0; i3 < N3; i3++ ) { for ( size_t i1 = 0; i1 < N1; i1++ ) { TYPE x = d_data[i1 + i3 * N1 * N2]; for ( size_t i2 = 0; i2 < N2; i2++ ) x = std::max( x, d_data[i1 + i2 * N1 + i3 * N1 * N2] ); data2[i1 + i3 * N1] = x; } } return ans; } template Array Array::sum( int dir ) const { std::vector size_ans = size(); size_ans[dir] = 1; Array ans( size_ans ); size_t N1 = 1, N2 = 1, N3 = 1; for ( int d = 0; d < std::min( dir, d_ndim ); d++ ) N1 *= d_N[d]; N2 = d_N[dir]; for ( int d = dir + 1; d < std::min( d_ndim, ARRAY_NDIM_MAX ); d++ ) N3 *= d_N[d]; TYPE *data2 = ans.d_data; for ( int i3 = 0; i3 < N3; i3++ ) { for ( int i1 = 0; i1 < N1; i1++ ) { TYPE x = 0; for ( size_t i2 = 0; i2 < N2; i2++ ) x += d_data[i1 + i2 * N1 + i3 * N1 * N2]; data2[i1 + i3 * N1] = x; } } return ans; } template TYPE Array::min( const std::vector &index ) const { // Get the subset indicies checkSubsetIndex( index ); std::array first, last, N1; getSubsetArrays( index, first, last, N1 ); std::array N2 = getDimArray(); #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif TYPE x = std::numeric_limits::max(); for ( size_t i4 = first[4]; i4 <= last[4]; i4++ ) { for ( size_t i3 = first[3]; i3 <= last[3]; i3++ ) { for ( size_t i2 = first[2]; i2 <= last[2]; i2++ ) { for ( size_t i1 = first[1]; i1 <= last[1]; i1++ ) { for ( size_t i0 = first[0]; i0 <= last[0]; i0++ ) { size_t k1 = GET_ARRAY_INDEX5D( N2, i0, i1, i2, i3, i4 ); x = std::min( x, d_data[k1] ); } } } } } return x; } template TYPE Array::max( const std::vector &index ) const { // Get the subset indicies checkSubsetIndex( index ); std::array first, last, N1; getSubsetArrays( index, first, last, N1 ); std::array N2 = getDimArray(); #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif TYPE x = std::numeric_limits::min(); for ( size_t i4 = first[4]; i4 <= last[4]; i4++ ) { for ( size_t i3 = first[3]; i3 <= last[3]; i3++ ) { for ( size_t i2 = first[2]; i2 <= last[2]; i2++ ) { for ( size_t i1 = first[1]; i1 <= last[1]; i1++ ) { for ( size_t i0 = first[0]; i0 <= last[0]; i0++ ) { size_t k1 = GET_ARRAY_INDEX5D( N2, i0, i1, i2, i3, i4 ); x = std::max( x, d_data[k1] ); } } } } } return x; } template TYPE Array::sum( const std::vector &index ) const { // Get the subset indicies checkSubsetIndex( index ); std::array first, last, N1; getSubsetArrays( index, first, last, N1 ); std::array N2 = getDimArray(); #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif TYPE x = 0; for ( size_t i4 = first[4]; i4 <= last[4]; i4++ ) { for ( size_t i3 = first[3]; i3 <= last[3]; i3++ ) { for ( size_t i2 = first[2]; i2 <= last[2]; i2++ ) { for ( size_t i1 = first[1]; i1 <= last[1]; i1++ ) { for ( size_t i0 = first[0]; i0 <= last[0]; i0++ ) { size_t k1 = GET_ARRAY_INDEX5D( N2, i0, i1, i2, i3, i4 ); x += d_data[k1]; } } } } } return x; } template TYPE Array::mean( const std::vector &index ) const { // Get the subset indicies checkSubsetIndex( index ); std::array first, last, N1; getSubsetArrays( index, first, last, N1 ); #if ARRAY_NDIM_MAX > 5 #error Function programmed for more than 5 dimensions #endif size_t n = 1; for ( auto &d : N1 ) n *= d; TYPE x = sum( index ) / n; return x; } template Array &Array::operator+=( const Array &rhs ) { if ( !sizeMatch(rhs) ) throw std::logic_error( "Array don't match" ); for ( size_t i = 0; i < d_length; i++ ) d_data[i] += rhs.d_data[i]; return *this; } template Array &Array::operator-=( const Array &rhs ) { if ( !sizeMatch(rhs) ) throw std::logic_error( "Array don't match" ); for ( size_t i = 0; i < d_length; i++ ) d_data[i] -= rhs.d_data[i]; return *this; } template Array &Array::operator+=( const TYPE &rhs ) { for ( size_t i = 0; i < d_length; i++ ) d_data[i] += rhs; return *this; } template Array &Array::operator-=( const TYPE &rhs ) { for ( size_t i = 0; i < d_length; i++ ) d_data[i] -= rhs; return *this; } template Array operator+( const Array& a, const Array& b ) { Array c = a; c += b; return c; } template Array operator-( const Array& a, const Array& b ) { Array c = a; c -= b; return c; } template Array operator*( const Array& a, const Array& b ) { return Array::multiply(a,b); } template Array Array::multiply( const Array& a, const Array& b ) { Array c; if ( a.d_ndim==2 && b.d_ndim==2 ) { c.resize( a.size(0), b.size(1) ); c.fill(0); for (size_t k=0; k std::vector Array::find( const TYPE &value, std::function compare ) const { std::vector result; result.reserve( d_length ); for ( size_t i = 0; i < d_length; i++ ) { if ( compare( d_data[i], value ) ) result.push_back( i ); } return result; } /******************************************************** * Print an array to an output stream * ********************************************************/ template void Array::print( std::ostream& os, const std::string& name, const std::string& prefix ) const { if ( d_ndim==1 ) { for (size_t i=0; i Array Array::reverseDim( ) const { std::vector N2(ARRAY_NDIM_MAX); for ( int d=0; d y( N2 ); #if ARRAY_NDIM_MAX != 5 #error Function programmed for dimensions other than 5 #endif TYPE* y2 = y.data(); for (size_t i0=0; i0 Array Array::coarsen( const Array& filter ) const { auto S2 = size(); for (size_t i=0; i y( S2 ); INSIST(d_ndim<=3,"Function programmed for more than 5 dimensions"); const size_t *Nh = filter.d_N; for (size_t k1=0; k1operator()(i1*Nh[0]+i2,j1*Nh[1]+j2,k1*Nh[2]+k2); } } } y(i1,j1,k1) = tmp; } } } return y; } template Array Array::coarsen( const std::vector& ratio, std::function&)> filter ) const { ASSERT((int)ratio.size()==d_ndim); auto S2 = size(); for (size_t i=0; i tmp(ratio); TYPE* tmp2 = tmp.data(); Array y( S2 ); INSIST(d_ndim<=3,"Function programmed for more than 3 dimensions"); for (size_t k1=0; k1operator()(i1*ratio[0]+i2,j1*ratio[1]+j2,k1*ratio[2]+k2); } } } y(i1,j1,k1) = filter(tmp); } } } return y; } #endif