#ifndef PERMUTE_H #define PERMUTE_H #include "Fastor/tensor/Tensor.h" #include "Fastor/tensor/TensorTraits.h" #include "Fastor/meta/einsum_meta.h" #include "Fastor/tensor_algebra/indicial.h" #include "Fastor/expressions/linalg_ops/linalg_traits.h" namespace Fastor { namespace internal { template struct NewRecursiveCartesianPerm; template struct NewRecursiveCartesianPerm, Tensor, First, Lasts...> { static constexpr size_t out_dim = sizeof...(Rest); static FASTOR_INLINE void Do(const T *a_data, T *out_data, std::array &as, std::array &idx) { for (size_t i=0; i, Tensor,Lasts...>::Do(a_data, out_data, as, idx); } } }; template struct NewRecursiveCartesianPerm, Tensor,Last> { using _permute_impl = new_permute_impl, Tensor, typename std_ext::make_index_sequence::type>; using resulting_tensor = typename _permute_impl::resulting_tensor; using resulting_index = typename _permute_impl::resulting_index; using maxes_out_type = typename put_dims_in_Index::type; static constexpr size_t a_dim = sizeof...(Rest); static constexpr size_t out_dim = a_dim; #if FASTOR_CXX_VERSION >= 2017 using reverse_map = internal::permute_mapped_index_t,make_index_t>; static constexpr std::array maxes_idx = reverse_map::values; #else static constexpr std::array maxes_idx = resulting_index::values; #endif static constexpr std::array products_a = nprods, typename std_ext::make_index_sequence::type>::values; static constexpr std::array products_out = nprods::type>::values; static FASTOR_INLINE void Do(const T *a_data, T *out_data, std::array &as, std::array &idx) { constexpr size_t stride = 1; for (size_t i = 0; i < Last; i+=stride) { idx[0] = i; std::reverse_copy(idx.begin(),idx.end(),as.begin()); #if FASTOR_CXX_VERSION >= 2017 size_t index_a = as[maxes_idx[a_dim-1]]; for(size_t it = 0; it< a_dim; it++) { index_a += products_a[it]*as[maxes_idx[it]]; } size_t index_out = as[out_dim-1]; for(size_t it = 0; it< out_dim-1; it++) { index_out += products_out[it]*as[it]; } #else size_t index_a = as[a_dim-1]; for(size_t it = 0; it< a_dim; it++) { index_a += products_a[it]*as[it]; } size_t index_out = as[maxes_idx[out_dim-1]]; for(size_t it = 0; it< out_dim-1; it++) { index_out += products_out[it]*as[maxes_idx[it]]; } #endif out_data[index_out] = a_data[index_a]; } } }; template constexpr std::array NewRecursiveCartesianPerm, Tensor,Last>::maxes_idx; template constexpr std::array NewRecursiveCartesianPerm, Tensor,Last>::products_a; template constexpr std::array NewRecursiveCartesianPerm, Tensor,Last>::products_out; template struct NewRecursiveCartesianPermDispatcher; template struct NewRecursiveCartesianPermDispatcher, Tensor, Index > { static constexpr size_t out_dim = sizeof...(Rest); static FASTOR_INLINE void Do(const T *a_data, T *out_data, std::array &as, std::array &idx) { return NewRecursiveCartesianPerm,Tensor, Args...>::Do(a_data, out_data, as, idx); } }; template struct new_extractor_perm {}; template struct new_extractor_perm > { template static FASTOR_INLINE typename new_permute_impl, Tensor, typename std_ext::make_index_sequence::type>::resulting_tensor permutation_impl(const Tensor &a) { using _permute_impl = new_permute_impl, Tensor, typename std_ext::make_index_sequence::type>; using resulting_tensor = typename _permute_impl::resulting_tensor; constexpr bool requires_permutation = _permute_impl::requires_permutation; FASTOR_IF_CONSTEXPR(!requires_permutation) return a; #if CONTRACT_OPT==-1 using maxes_out_type = typename put_dims_in_Index::type; constexpr size_t a_dim = sizeof...(Rest); constexpr size_t out_dim = a_dim; constexpr auto& products_a = nprods, typename std_ext::make_index_sequence::type>::values; constexpr auto& products_out = nprods::type>::values; resulting_tensor out; T *a_data = a.data(); T *out_data = out.data(); size_t as[out_dim] = {}; int jt; #if FASTOR_CXX_VERSION >= 2017 constexpr std::array maxes_out = maxes_out_type::values; // Map to go from out to in // Get the reverse map - this is to get contiguous memory writes using reverse_map = internal::permute_mapped_index_t,make_index_t>; constexpr auto& maxes_idx = reverse_map::values; // print(type_name()); while(true) { size_t index_a = as[maxes_idx[a_dim-1]]; for(size_t it = 0; it< a_dim; it++) { index_a += products_a[it]*as[maxes_idx[it]]; } size_t index_out = as[out_dim-1]; for(size_t it = 0; it< out_dim-1; it++) { index_out += products_out[it]*as[it]; } // print(index_out); // print(index_a); out_data[index_out] = a_data[index_a]; for(jt = out_dim-1 ; jt>=0 ; jt--) { if(++as[jt] maxes_a = {Rest...}; // Map to go from in to out constexpr auto& maxes_idx = resulting_index::values; while(true) { size_t index_a = as[a_dim-1]; for(size_t it = 0; it< a_dim; it++) { index_a += products_a[it]*as[it]; } size_t index_out = as[maxes_idx[out_dim-1]]; for(size_t it = 0; it< out_dim-1; it++) { index_out += products_out[it]*as[maxes_idx[it]]; } out_data[index_out] = a_data[index_a]; for(jt = out_dim-1 ; jt>=0 ; jt--) { if(++as[jt] as = {}; std::array idx = {}; #if FASTOR_CXX_VERSION >= 2017 using reverse_map = internal::permute_mapped_index_t,make_index_t>; using nloops = loop_setter< reverse_map, resulting_tensor, typename std_ext::make_index_sequence::type>; using dims_type = typename nloops::dims_type; NewRecursiveCartesianPermDispatcher,Tensor,dims_type>::Do(a_data,out_data,as,idx); #else using nloops = loop_setter< Index, Tensor, typename std_ext::make_index_sequence::type>; using dims_type = typename nloops::dims_type; NewRecursiveCartesianPermDispatcher,Tensor,dims_type>::Do(a_data,out_data,as,idx); #endif #endif return out; } // Abstract permutation template,bool> = false> static FASTOR_INLINE typename new_permute_impl< Index, typename Derived::result_type, typename std_ext::make_index_sequence::type>::resulting_tensor permutation_impl(const AbstractTensor &a) { using T = typename Derived::scalar_type; using tensor_type = typename Derived::result_type; using _permute_impl = new_permute_impl, tensor_type, typename std_ext::make_index_sequence::type>; using resulting_tensor = typename _permute_impl::resulting_tensor; constexpr bool requires_permutation = _permute_impl::requires_permutation; FASTOR_IF_CONSTEXPR(!requires_permutation) return a; using maxes_out_type = typename put_dims_in_Index::type; constexpr size_t a_dim = DIMS; constexpr size_t out_dim = a_dim; constexpr auto& products_a = nprods::tensor_to_index, typename std_ext::make_index_sequence::type>::values; constexpr auto& products_out = nprods::type>::values; resulting_tensor out; T *out_data = out.data(); const Derived & a_src = a.self(); size_t as[out_dim] = {}; int jt; #if FASTOR_CXX_VERSION >= 2017 constexpr std::array maxes_out = maxes_out_type::values; // Map to go from in to out // constexpr auto& maxes_idx = resulting_index::values; // Map to go from out to in // Get the reverse map - this is to get contiguous memory writes using reverse_map = internal::permute_mapped_index_t,make_index_t>; constexpr auto& maxes_idx = reverse_map::values; while(true) { size_t index_a = as[maxes_idx[a_dim-1]]; for(size_t it = 0; it< a_dim; it++) { index_a += products_a[it]*as[maxes_idx[it]]; } size_t index_out = as[out_dim-1]; for(size_t it = 0; it< out_dim-1; it++) { index_out += products_out[it]*as[it]; } out_data[index_out] = a_src.template eval_s(index_a); for(jt = out_dim-1 ; jt>=0 ; jt--) { if(++as[jt] maxes_a = get_tensor_dimensions::dims; // Map to go from in to out using resulting_index = typename _permute_impl::resulting_index; constexpr auto& maxes_idx = resulting_index::values; while(true) { size_t index_a = as[a_dim-1]; for(size_t it = 0; it< a_dim; it++) { index_a += products_a[it]*as[it]; } size_t index_out = as[maxes_idx[out_dim-1]]; for(size_t it = 0; it< out_dim-1; it++) { index_out += products_out[it]*as[maxes_idx[it]]; } out_data[index_out] = a_src.template eval_s(index_a); for(jt = out_dim-1 ; jt>=0 ; jt--) { if(++as[jt] FASTOR_INLINE typename internal::new_permute_impl, typename std_ext::make_index_sequence::type>::resulting_tensor permute(const Tensor &a) { return internal::new_extractor_perm::permutation_impl(a); } template,bool> = false> FASTOR_INLINE typename internal::new_permute_impl::type>::resulting_tensor permute(const AbstractTensor &a) { return internal::new_extractor_perm::permutation_impl(a); } template,bool> = false> FASTOR_INLINE typename internal::new_permute_impl::type>::resulting_tensor permute(const AbstractTensor &a) { using result_type = typename Derived::result_type; const result_type tmp(a); return internal::new_extractor_perm::permutation_impl(tmp); } } // end of namespace Fastor #endif // PERMUTE_H