#ifndef ABSTRACT_CONTRACTION_H #define ABSTRACT_CONTRACTION_H #include "Fastor/tensor/Tensor.h" #include "Fastor/tensor/TensorTraits.h" #include "Fastor/tensor_algebra/indicial.h" #include "Fastor/meta/opmin_meta.h" #include "Fastor/expressions/expression_traits.h" #include "Fastor/expressions/linalg_ops/linalg_traits.h" #include "Fastor/tensor_algebra/contraction.h" #include "Fastor/tensor_algebra/network_contraction.h" #include "Fastor/tensor_algebra/network_contraction_no_opmin.h" namespace Fastor { #if FASTOR_CXX_VERSION >= 2014 // The following set of functions implement by-pair as well as // network contraction/einsum for infinite number of expressions // the expressions are always evaluated so no aliasing occurs // and the contractions are forwarded to their tensor counterparts // which perform operation minimiation and are optimised for performance // Single expression - contraction //------------------------------------------------------------------------------------------------- template,bool> = false> FASTOR_INLINE decltype(auto) contraction(const AbstractTensor &a) { typename Derived0::result_type res_a(a); return extractor_contract_1::contract_impl(res_a); } //------------------------------------------------------------------------------------------------- // Single expression - einsum //------------------------------------------------------------------------------------------------- template,bool> = false> FASTOR_INLINE decltype(auto) einsum(const AbstractTensor &a) { typename Derived0::result_type res_a(a); return extractor_contract_1::contract_impl(res_a); } //------------------------------------------------------------------------------------------------- // By pair expressions - contraction //------------------------------------------------------------------------------------------------- template && !is_tensor_v,bool> = false> FASTOR_INLINE decltype(auto) contraction(const AbstractTensor &a, const AbstractTensor &b) { typename Derived0::result_type res_a(a); typename Derived1::result_type res_b(b); return extractor_contract_2::contract_impl(res_a,res_b); } template && !is_tensor_v,bool> = false> FASTOR_INLINE decltype(auto) contraction(const AbstractTensor &a, const AbstractTensor &b) { typename Derived1::result_type res_b(b); return extractor_contract_2::contract_impl(a,res_b); } template && is_tensor_v,bool> = false> FASTOR_INLINE decltype(auto) contraction(const AbstractTensor &a, const AbstractTensor &b) { typename Derived0::result_type res_a(a); return extractor_contract_2::contract_impl(res_a,b); } //------------------------------------------------------------------------------------------------- // By pair expressions - einsum //------------------------------------------------------------------------------------------------- template && !is_tensor_v,bool> = false> FASTOR_INLINE decltype(auto) einsum(const AbstractTensor &a, const AbstractTensor &b) { typename Derived0::result_type res_a(a); typename Derived1::result_type res_b(b); return einsum(res_a,res_b); } template && !is_tensor_v,bool> = false> FASTOR_INLINE decltype(auto) einsum(const AbstractTensor &a, const AbstractTensor &b) { typename Derived1::result_type res_b(b); return einsum(a,res_b); } template && is_tensor_v,bool> = false> FASTOR_INLINE decltype(auto) einsum(const AbstractTensor &a, const AbstractTensor &b) { typename Derived0::result_type res_a(a); return einsum(res_a,b); } //------------------------------------------------------------------------------------------------- // network contraction for expressions //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- namespace internal { // helper functions to evaluate expression in to intermediate tensors // We evaluate all intermediate tensors and pack them in to a single tuple FASTOR_INLINE std::tuple<> contraction_chain_evaluate() { return std::tuple<>{}; } // Note that if the expression is a tensor the evaluation is free // as evaluate returns the tensor itself template FASTOR_INLINE decltype(auto) contraction_chain_evaluate(const AbstractTensor& a) { return evaluate(a.self()); } template FASTOR_INLINE decltype(auto) contraction_chain_evaluate(const AbstractTensorType0& a, const AbstractTensorTypes& ... rest) { return std::tuple_cat(std::make_tuple(evaluate(a)),contraction_chain_evaluate(rest...)); } // helper functor to unpack the tuple and forward the pack of tensor // to network contraction for operation minimisation template struct unpack_contraction_tuple { template static auto apply(Tuple t, std_ext::index_sequence) { return contraction(std::get(t) ...); } template static auto apply(Tuple t) { constexpr auto size = std::tuple_size::value; return apply(t, std_ext::make_index_sequence{}); } }; // helper functor to unpack the tuple and forward the pack of tensor // to network einsum for operation minimisation template struct unpack_einsum_tuple { template static auto apply(Tuple t, std_ext::index_sequence) { return einsum(std::get(t) ...); } template static auto apply(Tuple t) { constexpr auto size = std::tuple_size::value; return apply(t, std_ext::make_index_sequence{}); } }; template struct unpack_einsum_helper_tuple { template static constexpr auto apply(Tuple t, std_ext::index_sequence) { return einsum_helper(t)) ...>{}; } template static constexpr auto apply(Tuple t) { constexpr auto size = std::tuple_size::value; return apply(t, std_ext::make_index_sequence{}); } }; } // internal //------------------------------------------------------------------------------------------------- // network contraction template FASTOR_INLINE auto contraction(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest) { return internal::unpack_contraction_tuple::apply(internal::contraction_chain_evaluate(a,b,rest...)); } // network einsum template FASTOR_INLINE auto einsum(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest) { // network einsum is not defined yet return internal::unpack_einsum_tuple::apply(internal::contraction_chain_evaluate(a,b,rest...)); // but it dispatches to network contraction anyway and contraction uses by-pair einsum in turn // return internal::unpack_contraction_tuple::apply(internal::contraction_chain_evaluate(a,b,rest...)); } #endif // CXX 2014 //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- } // end of namespace Fastor #endif // ABSTRACT_CONTRACTION_H