#ifndef REDUCIBLE_CONTRACTION_H #define REDUCIBLE_CONTRACTION_H #include "Fastor/tensor/Tensor.h" #include "Fastor/tensor_algebra/indicial.h" namespace Fastor { // Broadcast-vectorisable contractions (if last dimension is contracted). // Requres working on general strides template struct extractor_reducible_contract {}; template struct extractor_reducible_contract, Index> { #if CONTRACT_OPT==2 template static typename contraction_impl, Tensor, typename std_ext::make_index_sequence::type>::type contract_impl(const Tensor &a, const Tensor &b) { static_assert(!is_pair_reduction_v,Index>,"REDUCTION TO SCALAR REQUESTED. USE REDUCTION FUNCTION INSTEAD"); constexpr int total = no_of_loops_to_set,Index,Tensor,Tensor, typename std_ext::make_index_sequence::value>::type>::value; using index_generator = contract_meta_engine,Index,Tensor,Tensor, typename std_ext::make_index_sequence::type>; using OutTensor = typename index_generator::OutTensor; using OutIndices = typename index_generator::OutIndices; constexpr auto& index_a = index_generator::index_a; constexpr auto& index_b = index_generator::index_b; constexpr auto& index_out = index_generator::index_out; OutTensor out; out.zeros(); const T *a_data = a.data(); const T *b_data = b.data(); T *out_data = out.data(); // Check for reducible vectorisability constexpr int general_stride = general_stride_finder,Index, Tensor,Tensor, typename std_ext::make_index_sequence::type>::value; #ifndef FASTOR_DONT_VECTORISE using vectorisability = is_reducibly_vectorisable; constexpr int stride = vectorisability::stride; using V = typename vectorisability::type; #else constexpr int stride = 1; using V = SIMDVector; #endif V _vec_a, _vec_b; for (int i = 0; i < total; i+=stride) { _vec_a.set(*(a_data+index_a[i])); const auto idx_b = index_b[i]; vector_setter(_vec_b, b_data, idx_b, general_stride); V _vec_out = _vec_a*_vec_b + V(out_data+index_out[i]); _vec_out.store(out_data+index_out[i]); } return out; } #elif CONTRACT_OPT==1 template static typename contraction_impl, Tensor, typename std_ext::make_index_sequence::type>::type contract_impl(const Tensor &a, const Tensor &b) { static_assert(!is_pair_reduction_v,Index>,"REDUCTION TO SCALAR REQUESTED. USE REDUCTION FUNCTION INSTEAD"); using OutTensor = typename contraction_impl, Tensor, typename std_ext::make_index_sequence::type>::type; using OutIndices = typename contraction_impl, Tensor, typename std_ext::make_index_sequence::type>::indices; OutTensor out; out.zeros(); const T *a_data = a.data(); const T *b_data = b.data(); T *out_data = out.data(); constexpr int a_dim = sizeof...(Rest0); constexpr int b_dim = sizeof...(Rest1); constexpr auto& idx_a = IndexFirstTensor,Index, Tensor,Tensor, typename std_ext::make_index_sequence::type>::indices; constexpr auto& idx_b = IndexSecondTensor,Index, Tensor,Tensor, typename std_ext::make_index_sequence::type>::indices; constexpr auto& idx_out = IndexResultingTensor,Index, Tensor,Tensor, typename std_ext::make_index_sequence::type>::indices; constexpr int total = no_of_loops_to_set,Index,Tensor,Tensor, typename std_ext::make_index_sequence::value>::type>::value; using maxes_out_type = typename no_of_loops_to_set,Index,Tensor,Tensor, typename std_ext::make_index_sequence::value>::type>::type; constexpr auto& as_all = cartesian_product::type>::values; constexpr std::array products_a = nprods,typename std_ext::make_index_sequence::type>::values; constexpr std::array products_b = nprods,typename std_ext::make_index_sequence::type>::values; using Index_with_dims = typename put_dims_in_Index::type; constexpr std::array products_out = nprods::type>::values; // Check for reducible vectorisability constexpr int general_stride = general_stride_finder,Index, Tensor,Tensor, typename std_ext::make_index_sequence::type>::value; #ifndef FASTOR_DONT_VECTORISE using vectorisability = is_reducibly_vectorisable; constexpr int stride = vectorisability::stride; using V = typename vectorisability::type; #else constexpr int stride = 1; using V = SIMDVector; #endif int it; V _vec_a, _vec_b; for (int i = 0; i < total; i+=stride) { int index_a = as_all[i][idx_a[a_dim-1]]; for(it = 0; it< a_dim; it++) { index_a += products_a[it]*as_all[i][idx_a[it]]; } int index_b = as_all[i][idx_b[b_dim-1]]; for(it = 0; it< b_dim; it++) { index_b += products_b[it]*as_all[i][idx_b[it]]; } int index_out = as_all[i][idx_out[idx_out.size()-1]]; for(it = 0; it< idx_out.size(); it++) { index_out += products_out[it]*as_all[i][idx_out[it]]; } _vec_a.set(*(a_data+index_a)); // _vec_b.set(b_data[index_b+3*general_stride], b_data[index_b+2*general_stride], // b_data[index_b+general_stride],b_data[index_b]); vector_setter(_vec_b, b_data, index_b, general_stride); V _vec_out = _vec_a*_vec_b + V(out_data+index_out); _vec_out.store(out_data+index_out); } return out; } #else template static typename contraction_impl, Tensor, typename std_ext::make_index_sequence::type>::type contract_impl(const Tensor &a, const Tensor &b) { static_assert(!is_pair_reduction_v,Index>,"REDUCTION TO SCALAR REQUESTED. USE REDUCTION FUNCTION INSTEAD"); using OutTensor = typename contraction_impl, Tensor, typename std_ext::make_index_sequence::type>::type; using OutIndice = typename contraction_impl, Tensor, typename std_ext::make_index_sequence::type>::indices; OutTensor out; out.zeros(); const T *a_data = a.data(); const T *b_data = b.data(); T *out_data = out.data(); constexpr int a_dim = sizeof...(Rest0); constexpr int b_dim = sizeof...(Rest1); constexpr int out_dim = no_of_unique::value; constexpr auto& idx_a = IndexTensors< Index, Tensor, Index,Tensor, typename std_ext::make_index_sequence::type>::indices; constexpr auto& idx_b = IndexTensors< Index, Tensor, Index,Tensor, typename std_ext::make_index_sequence::type>::indices; constexpr auto& idx_out = IndexTensors< Index, Tensor, OutIndice,OutTensor, typename std_ext::make_index_sequence::type>::indices; using nloops = loop_setter< Index, Tensor, typename std_ext::make_index_sequence::type>; constexpr auto& maxes_out = nloops::dims; constexpr int total = nloops::value; constexpr std::array products_a = nprods,typename std_ext::make_index_sequence::type>::values; constexpr std::array products_b = nprods,typename std_ext::make_index_sequence::type>::values; using Index_with_dims = typename put_dims_in_Index::type; constexpr std::array products_out = \ nprods::type>::values; // Check for reducible vectorisability constexpr int general_stride = general_stride_finder,Index, Tensor,Tensor, typename std_ext::make_index_sequence::type>::value; #ifndef FASTOR_DONT_VECTORISE using vectorisability = is_reducibly_vectorisable; constexpr int stride = vectorisability::stride; using V = typename vectorisability::type; #else constexpr int stride = 1; using V = SIMDVector; #endif int as[out_dim]; std::fill(as,as+out_dim,0); int it; V _vec_a, _vec_b; for (int i = 0; i < total; i+=stride) { int remaining = total; for (int n = 0; n < out_dim; ++n) { remaining /= maxes_out[n]; as[n] = ( i / remaining ) % maxes_out[n]; } int index_a = as[idx_a[a_dim-1]]; for(it = 0; it< a_dim; it++) { index_a += products_a[it]*as[idx_a[it]]; } int index_b = as[idx_b[b_dim-1]]; for(it = 0; it< b_dim; it++) { index_b += products_b[it]*as[idx_b[it]]; } int index_out = as[idx_out[OutTensor::Dimension-1]]; for(it = 0; it< static_cast(OutTensor::Dimension); it++) { index_out += products_out[it]*as[idx_out[it]]; } // asm("#BEGIN"); _vec_a.set(*(a_data+index_a)); //_vec_a.broadcast(a_data+index_a); vector_setter(_vec_b, b_data, index_b, general_stride); V _vec_out = _vec_a*_vec_b + V(out_data+index_out); _vec_out.store(out_data+index_out); // asm("#END"); } return out; } #endif }; template FASTOR_INLINE auto strided_contraction(const Tensor &a, const Tensor &b) -> decltype(extractor_reducible_contract::contract_impl(a,b)) { return extractor_reducible_contract::contract_impl(a,b); } } #endif // REDUCIBLE_CONTRACTION_H