#ifndef PERMUTATION_H #define PERMUTATION_H #include "Fastor/tensor/Tensor.h" #include "Fastor/tensor/TensorTraits.h" #include "Fastor/tensor_algebra/indicial.h" #include "Fastor/meta/einsum_meta.h" #include "Fastor/expressions/linalg_ops/linalg_traits.h" namespace Fastor { namespace internal { template struct RecursiveCartesianPerm; template struct RecursiveCartesianPerm, 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 RecursiveCartesianPerm, Tensor,Last> { using _permute_impl = 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 _permute_impl::maxes_out_type; static constexpr std::array maxes_idx = resulting_index::values; static constexpr std::array maxes_out = maxes_out_type::values; static constexpr size_t a_dim = sizeof...(Rest); static constexpr size_t out_dim = a_dim; static constexpr std::array maxes_a = {Rest...}; 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 constexpr std::array RecursiveCartesianPerm, Tensor,Last>::maxes_idx; template constexpr std::array RecursiveCartesianPerm, Tensor,Last>::maxes_out; template constexpr std::array RecursiveCartesianPerm, Tensor,Last>::products_a; template constexpr std::array RecursiveCartesianPerm, Tensor,Last>::products_out; // template // struct RecursiveCartesianPerm, Tensor> // { // using OutTensor = typename permute_impl, Tensor, // typename std_ext::make_index_sequence::type>::type; // using maxes_out_type = typename permute_impl, Tensor, // typename std_ext::make_index_sequence::type>::maxes_out_type; // using index_type = typename permute_impl, Tensor, // typename std_ext::make_index_sequence::type>::index_type; // static constexpr auto maxes_idx = permute_impl, Tensor, // typename std_ext::make_index_sequence::type>::index_type::values; // static constexpr auto maxes_out = permute_impl, Tensor, // typename std_ext::make_index_sequence::type>::maxes_out_type::values; // static constexpr int a_dim = sizeof...(Rest); // static constexpr int out_dim = a_dim; // static constexpr std::array maxes_a = {Rest...}; // 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 void Do(const T *a_data, T *out_data, std::array &as, std::array &idx) // { // std::reverse_copy(idx.begin(),idx.end(),as.begin()); // int index_a = as[a_dim-1]; // for(int it = 0; it< a_dim; it++) { // index_a += products_a[it]*as[it]; // } // int index_out = as[maxes_idx[out_dim-1]]; // for(int it = 0; it< out_dim-1; it++) { // index_out += products_out[it]*as[maxes_idx[it]]; // } // out_data[index_out] = a_data[index_a]; // } // }; // template // constexpr std::array RecursiveCartesianPerm, // Tensor>::products_a; // template // constexpr std::array RecursiveCartesianPerm, // Tensor>::products_out; template struct RecursiveCartesianPermDispatcher; template struct RecursiveCartesianPermDispatcher, 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 RecursiveCartesianPerm,Tensor, Args...>::Do(a_data, out_data, as, idx); } }; template struct extractor_perm {}; template struct extractor_perm > { template static FASTOR_INLINE typename permute_impl, Tensor, typename std_ext::make_index_sequence::type>::resulting_tensor permutation_impl(const Tensor &a) { using _permute_impl = 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 resulting_index = typename _permute_impl::resulting_index; using maxes_out_type = typename _permute_impl::maxes_out_type; constexpr auto& maxes_idx = resulting_index::values; constexpr auto& maxes_out = maxes_out_type::values; constexpr int a_dim = sizeof...(Rest); constexpr int out_dim = a_dim; constexpr std::array maxes_a = {Rest...}; constexpr auto& products_a = nprods, typename std_ext::make_index_sequence::type>::values; constexpr auto& products_out = nprods::type>::values; resulting_tensor out; out.zeros(); T *a_data = a.data(); T *out_data = out.data(); int as[out_dim] = {}; int it,jt; while(true) { int index_a = as[a_dim-1]; for(it = 0; it< a_dim; it++) { index_a += products_a[it]*as[it]; } int index_out = as[maxes_idx[out_dim-1]]; for(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 = {}; using nloops = loop_setter< Index, Tensor, typename std_ext::make_index_sequence::type>; using dims_type = typename nloops::dims_type; RecursiveCartesianPermDispatcher,Tensor,dims_type>::Do(a_data,out_data,as,idx); #endif return out; } // Abstract permutation template,bool> = false> static FASTOR_INLINE typename 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 = permute_impl, tensor_type, 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 _permute_impl::maxes_out_type; constexpr auto& maxes_idx = resulting_index::values; constexpr int a_dim = DIMS; constexpr int out_dim = a_dim; constexpr std::array maxes_a = get_tensor_dimensions::dims_int; 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; out.zeros(); T *out_data = out.data(); const Derived & a_src = a.self(); int as[out_dim] = {}; int it,jt; while(true) { int index_a = as[a_dim-1]; for(it = 0; it< a_dim; it++) { index_a += products_a[it]*as[it]; } int index_out = as[maxes_idx[out_dim-1]]; for(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::permute_impl, typename std_ext::make_index_sequence::type>::resulting_tensor permutation(const Tensor &a) { return internal::extractor_perm::permutation_impl(a); } template,bool> = false> FASTOR_INLINE typename internal::permute_impl::type>::resulting_tensor permutation(const AbstractTensor &a) { return internal::extractor_perm::permutation_impl(a.self()); } template,bool> = false> FASTOR_INLINE typename internal::permute_impl::type>::resulting_tensor permutation(const AbstractTensor &a) { using result_type = typename Derived::result_type; const result_type tmp(a); return internal::extractor_perm::permutation_impl(tmp); } } // end of namespace Fastor #endif // PERMUTATION_H