Add Fastor library
This commit is contained in:
1133
noarch/include/Fastor/meta/einsum_meta.h
Normal file
1133
noarch/include/Fastor/meta/einsum_meta.h
Normal file
File diff suppressed because it is too large
Load Diff
344
noarch/include/Fastor/meta/meta.h
Normal file
344
noarch/include/Fastor/meta/meta.h
Normal file
@@ -0,0 +1,344 @@
|
||||
#ifndef META_H_
|
||||
#define META_H_
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include <complex>
|
||||
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template< bool B, class T = void >
|
||||
using enable_if_t_ = typename std::enable_if<B,T>::type;
|
||||
|
||||
template< bool B, class T = void >
|
||||
using disable_if_t_ = typename std::enable_if<!B,T>::type;
|
||||
|
||||
template< bool B, class T, class F >
|
||||
using conditional_t_ = typename std::conditional<B,T,F>::type;
|
||||
|
||||
template< class T, class U >
|
||||
constexpr bool is_same_v_ = std::is_same<T, U>::value;
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_fundamental_v_ = std::is_fundamental<T>::value;
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_arithmetic_v_ = std::is_arithmetic<T>::value;
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_integral_v_ = std::is_integral<T>::value;
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_floating_v_ = std::is_floating_point<T>::value;
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_array_v_ = std::is_array<T>::value;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// If BLAS compatible type
|
||||
template< class T > struct is_numeric { static constexpr bool value = false; };
|
||||
template<> struct is_numeric<float> { static constexpr bool value = true; };
|
||||
template<> struct is_numeric<double> { static constexpr bool value = true; };
|
||||
template<> struct is_numeric<std::complex<float>> { static constexpr bool value = true; };
|
||||
template<> struct is_numeric<std::complex<double>> { static constexpr bool value = true; };
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_numeric_v_ = is_numeric<T>::value;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// If complex type
|
||||
template< class T > struct is_complex { static constexpr bool value = false; };
|
||||
template< class T > struct is_complex<std::complex<T>> { static constexpr bool value = true; };
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_complex_v_ = is_complex<T>::value;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// If a type is std::is_fundamental + std::complex<float/double> + any type that specialises this trait class
|
||||
// This class is provided because the behaviour of any code that specialises std::is_fundamental/arithmetic/
|
||||
// integral/floating_point is undefined
|
||||
template< class T > struct is_primitive {
|
||||
static constexpr bool value = std::is_fundamental<T>::value || is_numeric<T>::value;
|
||||
};
|
||||
|
||||
template< class T >
|
||||
constexpr bool is_primitive_v_ = is_primitive<T>::value;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// Checks if all parameters in a variadic parameter pack are arithmetic
|
||||
template<class ... T>
|
||||
struct is_arithmetic_pack;
|
||||
template<class T, class ... Ts>
|
||||
struct is_arithmetic_pack<T,Ts...> {
|
||||
static constexpr bool value = std::is_arithmetic<T>::value && is_arithmetic_pack<Ts...>::value;
|
||||
};
|
||||
template<class T>
|
||||
struct is_arithmetic_pack<T> { static constexpr bool value = std::is_arithmetic<T>::value; };
|
||||
|
||||
template<class ... T>
|
||||
static constexpr bool is_arithmetic_pack_v = is_arithmetic_pack<T...>::value;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// Remove cv-qualified and their refs
|
||||
template<typename T> struct remove_cvref_ { using type = T; };
|
||||
template<typename T> struct remove_cvref_<const T> { using type = typename remove_cvref_<T>::type; };
|
||||
template<typename T> struct remove_cvref_<T const&> { using type = typename remove_cvref_<T>::type; };
|
||||
template<typename T> struct remove_cvref_<T&> { using type = typename remove_cvref_<T>::type; };
|
||||
template<typename T> struct remove_cvref_<volatile T> { using type = typename remove_cvref_<T>::type; };
|
||||
template<typename T> struct remove_cvref_<T volatile&> { using type = typename remove_cvref_<T>::type; };
|
||||
|
||||
template<typename T>
|
||||
using remove_cv_ref_t = typename remove_cvref_<T>::type;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template<typename T> struct remove_all { using type = T; };
|
||||
template<typename T> struct remove_all<const T> { using type = typename remove_all<T>::type; };
|
||||
template<typename T> struct remove_all<volatile T> { using type = typename remove_all<T>::type; };
|
||||
template<typename T> struct remove_all<T&> { using type = typename remove_all<T>::type; };
|
||||
template<typename T> struct remove_all<T const&> { using type = typename remove_all<T>::type; };
|
||||
template<typename T> struct remove_all<T volatile&> { using type = typename remove_all<T>::type; };
|
||||
template<typename T> struct remove_all<T*> { using type = typename remove_all<T>::type; };
|
||||
template<typename T> struct remove_all<T const*> { using type = typename remove_all<T>::type; };
|
||||
template<typename T> struct remove_all<T volatile*> { using type = typename remove_all<T>::type; };
|
||||
|
||||
template<typename T>
|
||||
using remove_all_t = typename remove_all<T>::type;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// Sum/multiply reduce all elements of a variadic pack
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// Sum
|
||||
template<size_t...Rest> struct pack_add;
|
||||
template<size_t Head, size_t ...Rest>
|
||||
struct pack_add<Head, Rest...> { static const size_t value = Head+pack_add<Rest...>::value;};
|
||||
template<> struct pack_add<> { static const size_t value = 0;};
|
||||
|
||||
// Multiply
|
||||
template<size_t...Rest> struct pack_prod;
|
||||
template<size_t Head, size_t ...Rest>
|
||||
struct pack_prod<Head, Rest...> { static const size_t value = Head*pack_prod<Rest...>::value;};
|
||||
template<> struct pack_prod<> { static const size_t value = 1;};
|
||||
|
||||
// Multiply first n elements
|
||||
template<size_t Idx, size_t ... Rest> struct prod_nel;
|
||||
template<size_t Idx, size_t First, size_t ... Rest>
|
||||
struct prod_nel<Idx, First, Rest...> { static const size_t value = prod_nel<Idx-1, Rest...>::value;};
|
||||
template<size_t First, size_t ... Rest>
|
||||
struct prod_nel<1, First, Rest...> { static const size_t value = pack_prod<Rest...>::value;};
|
||||
|
||||
//! Partial product of a sequence up to an index up_to
|
||||
template<class T, T N>
|
||||
constexpr
|
||||
inline T partial_prod(const T (&ind)[N], T up_to, T num=0) {
|
||||
return num == up_to ? ind[num] : ind[num]*partial_prod(ind, up_to, num+1);
|
||||
}
|
||||
|
||||
//! Partial product of a sequence up to an index num from the end
|
||||
template<class T, T N>
|
||||
constexpr
|
||||
inline T partial_prod_reverse(const T (&ind)[N], T up_to, T num=N-1) {
|
||||
return num == up_to ? ind[num] : ind[num]*partial_prod_reverse(ind, up_to, num-1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T size_proder_(T one){return one.size();}
|
||||
template<typename T>
|
||||
constexpr T size_proder_(T one, T two){return one.size()*two.size();}
|
||||
template<typename T, typename ... Ts>
|
||||
constexpr T size_proder_(T one, T two, Ts ... ts) {return _proder_(_proder_(one,two),ts...);}
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template<size_t Idx, size_t ... Rest>
|
||||
struct get_value;
|
||||
template<size_t Idx, size_t First, size_t ... Rest>
|
||||
struct get_value<Idx, First, Rest...> {
|
||||
static const size_t value = get_value<Idx-1, Rest...>::value;
|
||||
};
|
||||
template<size_t First, size_t ... Rest>
|
||||
struct get_value<1,First,Rest...> {
|
||||
static const size_t value = First;
|
||||
};
|
||||
template<size_t Idx>
|
||||
// Work around to avoid compiler errors
|
||||
struct get_value<Idx> {
|
||||
static const size_t value = 0;
|
||||
};
|
||||
|
||||
template <size_t N, typename... Args>
|
||||
constexpr inline auto get_index(Args&&... as)
|
||||
-> decltype(std::get<N>(std::forward_as_tuple(std::forward<Args>(as)...))) {
|
||||
return std::get<N>(std::forward_as_tuple(std::forward<Args>(as)...));
|
||||
}
|
||||
|
||||
template<int N, typename... Ts>
|
||||
using get_nth_type = typename std::tuple_element<N, std::tuple<Ts...>>::type;
|
||||
|
||||
template<size_t Idx, size_t ... Rest>
|
||||
struct get_all {
|
||||
static const size_t indices[sizeof...(Rest)];
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// comparitors
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template<size_t I, size_t J>
|
||||
struct is_equal {
|
||||
static constexpr bool value = I == J;
|
||||
};
|
||||
template<size_t I, size_t J>
|
||||
static constexpr bool is_equal_v_ = is_equal<I,J>::value;
|
||||
|
||||
template<size_t I, size_t J>
|
||||
struct is_less {
|
||||
static constexpr bool value = (I < J);
|
||||
};
|
||||
template<size_t I, size_t J>
|
||||
static constexpr bool is_less_v_ = is_less<I,J>::value;
|
||||
|
||||
template<size_t I, size_t J>
|
||||
struct is_less_equal {
|
||||
static constexpr bool value = I <= J;
|
||||
};
|
||||
template<size_t I, size_t J>
|
||||
static constexpr bool is_less_equal_v_ = is_less_equal<I,J>::value;
|
||||
|
||||
template<size_t I, size_t J>
|
||||
struct is_greater {
|
||||
static constexpr bool value = I > J;
|
||||
};
|
||||
template<size_t I, size_t J>
|
||||
static constexpr bool is_greater_v_ = is_greater<I,J>::value;
|
||||
|
||||
template<size_t I, size_t J>
|
||||
struct is_greater_equal {
|
||||
static constexpr bool value = I >= J;
|
||||
};
|
||||
template<size_t I, size_t J>
|
||||
static constexpr bool is_greater_equal_v_ = is_greater_equal<I,J>::value;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// min-max
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template<size_t ... rest>
|
||||
struct meta_min;
|
||||
template<size_t m, size_t n, size_t ... rest>
|
||||
struct meta_min<m,n,rest...> {
|
||||
static constexpr size_t pval = meta_min<m,n>::value;
|
||||
static const size_t value = (pval <= meta_min<pval,rest...>::value) ?
|
||||
pval : meta_min<pval,rest...>::value;
|
||||
};
|
||||
template <size_t m, size_t n>
|
||||
struct meta_min<m,n> {
|
||||
static const size_t value = (m<=n) ? m : n;
|
||||
};
|
||||
|
||||
template<size_t ... rest>
|
||||
struct meta_max;
|
||||
template<size_t m, size_t n, size_t ... rest>
|
||||
struct meta_max<m,n,rest...> {
|
||||
static constexpr size_t pval = meta_max<m,n>::value;
|
||||
static const size_t value = (pval >= meta_max<pval,rest...>::value) ?
|
||||
pval : meta_max<pval,rest...>::value;
|
||||
};
|
||||
template<size_t m, size_t n>
|
||||
struct meta_max<m,n> {
|
||||
static const size_t value = (m>=n) ? m : n;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
// namespace to avoid clash with MSVC macros
|
||||
template<typename T> constexpr FASTOR_INLINE T min_(const T a, const T b) {return a < b ? a : b;}
|
||||
template<typename T> constexpr FASTOR_INLINE T max_(const T a, const T b) {return a > b ? a : b;}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template<size_t ... rest>
|
||||
struct meta_argmin;
|
||||
template<size_t m, size_t n, size_t ... rest>
|
||||
struct meta_argmin<m,n,rest...> {
|
||||
static constexpr size_t pval = meta_min<m,n>::value;
|
||||
static const size_t value = (pval <= meta_min<pval,rest...>::value) ?
|
||||
meta_argmin<m,n>::value : meta_argmin<pval,rest...>::value+1;
|
||||
};
|
||||
template<size_t m, size_t n>
|
||||
struct meta_argmin<m,n> {
|
||||
static const size_t value = (m<n) ? 0 : 1;
|
||||
};
|
||||
|
||||
|
||||
template<size_t ... rest>
|
||||
struct meta_argmax;
|
||||
template<size_t m, size_t n, size_t ... rest>
|
||||
struct meta_argmax<m,n,rest...> {
|
||||
static constexpr size_t pval = meta_max<m,n>::value;
|
||||
static const size_t value = (pval >= meta_max<pval,rest...>::value) ?
|
||||
meta_argmax<m,n>::value : meta_argmax<pval,rest...>::value+1;
|
||||
};
|
||||
template<size_t m, size_t n>
|
||||
struct meta_argmax<m,n> {
|
||||
static const size_t value = (m>n) ? 0 : 1;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// square/cube
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
namespace internal {
|
||||
template<size_t Val> struct meta_square { static constexpr size_t value = Val*Val;};
|
||||
template<size_t Val> struct meta_cube { static constexpr size_t value = Val*Val*Val;};
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
//square root of integers at compile time, use like meta_sqrt<36>::ret
|
||||
template<int Y,
|
||||
int InfX = 0,
|
||||
int SupX = ((Y==1) ? 1 : Y/2),
|
||||
bool Done = ((SupX-InfX)<=1 ? true : ((SupX*SupX <= Y) && ((SupX+1)*(SupX+1) > Y))) >
|
||||
// use ?: instead of || just to shut up a gcc 4.3 warning
|
||||
class meta_sqrt
|
||||
{
|
||||
enum {
|
||||
MidX = (InfX+SupX)/2,
|
||||
TakeInf = MidX*MidX > Y ? 1 : 0,
|
||||
NewInf = int(TakeInf) ? InfX : int(MidX),
|
||||
NewSup = int(TakeInf) ? int(MidX) : SupX
|
||||
};
|
||||
public:
|
||||
enum { ret = meta_sqrt<Y,NewInf,NewSup>::ret };
|
||||
};
|
||||
|
||||
template<int Y, int InfX, int SupX>
|
||||
class meta_sqrt<Y, InfX, SupX, true>
|
||||
{
|
||||
public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX };
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // META_H_
|
||||
620
noarch/include/Fastor/meta/opmin_meta.h
Normal file
620
noarch/include/Fastor/meta/opmin_meta.h
Normal file
@@ -0,0 +1,620 @@
|
||||
#ifndef OPMIN_META_H
|
||||
#define OPMIN_META_H
|
||||
|
||||
#ifndef FASTOR_DONT_PERFORM_OP_MIN
|
||||
|
||||
#include "tensor_meta.h"
|
||||
#include "einsum_meta.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
|
||||
// Cost model for by-pair tensor contraction
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
template<class Ind0, class Ind1, class Tensor0, class Tensor1, class Seq>
|
||||
struct pair_flop_cost;
|
||||
|
||||
template<class T, size_t... Idx0, size_t... Idx1, size_t ...Rest0, size_t ...Rest1, size_t... ss>
|
||||
struct pair_flop_cost<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest0...>,Tensor<T,Rest1...>,std_ext::index_sequence<ss...>> {
|
||||
|
||||
static constexpr size_t ind0[sizeof...(Idx0)] = {Idx0... };
|
||||
static constexpr size_t ind1[sizeof...(Idx1)] = {Idx1... };
|
||||
static constexpr int nums1[sizeof...(Rest1)] = {Rest1... };
|
||||
static constexpr size_t cost_tensor0 = pack_prod<Rest0...>::value;
|
||||
static constexpr size_t remaining_cost = pack_prod<retrieve_value(ind0,ind1,nums1,ss)...>::value;
|
||||
static constexpr size_t value = cost_tensor0*remaining_cost;
|
||||
|
||||
using resulting_tensor = typename get_resuling_tensor<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>>::type;
|
||||
using resulting_index = typename get_resuling_index<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>>::type;
|
||||
};
|
||||
|
||||
|
||||
template<class T, size_t... Idx0, size_t ...Rest0, size_t... ss>
|
||||
struct pair_flop_cost<Index<Idx0...>,Index<>,Tensor<T,Rest0...>,Tensor<T>,std_ext::index_sequence<ss...>> {
|
||||
static constexpr size_t value = pack_prod<Rest0...>::value;
|
||||
};
|
||||
|
||||
template<class T, size_t... Idx1, size_t ...Rest1, size_t... ss>
|
||||
struct pair_flop_cost<Index<>,Index<Idx1...>,Tensor<T>,Tensor<T,Rest1...>,std_ext::index_sequence<ss...>> {
|
||||
static constexpr size_t value = pack_prod<Rest1...>::value;
|
||||
};
|
||||
|
||||
template<class T, size_t... ss>
|
||||
struct pair_flop_cost<Index<>,Index<>,Tensor<T>,Tensor<T>,std_ext::index_sequence<ss...>> {
|
||||
static constexpr size_t value = 1;
|
||||
};
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
// Cost of triplet tensor contraction (single evaluation)
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
template<class Ind0, class Ind1, class Ind2, class Tensor0, class Tensor1, class Tensor2>
|
||||
struct single_evaluation_triplet_cost;
|
||||
|
||||
template<class T, size_t... Idx0, size_t... Idx1, size_t... Idx2, size_t ...Rest0, size_t ...Rest1, size_t ...Rest2>
|
||||
struct single_evaluation_triplet_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>> {
|
||||
|
||||
using concat_tensor_01 = typename no_of_loops_to_set<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<no_of_unique<Idx0...,Idx1...>::value>::type>::type;
|
||||
|
||||
using concat_index_01 = typename no_of_loops_to_set<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<no_of_unique<Idx0...,Idx1...>::value>::type>::indices;
|
||||
|
||||
static constexpr size_t value = pair_flop_cost<concat_index_01,Index<Idx2...>,concat_tensor_01,Tensor<T,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest2)>::type>::value;
|
||||
};
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
|
||||
// Cost model for triplet tensor network contraction
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
template<class Ind0, class Ind1, class Ind2, class Tensor0, class Tensor1, class Tensor2>
|
||||
struct triplet_flop_cost;
|
||||
|
||||
template<class T, size_t... Idx0, size_t... Idx1, size_t... Idx2, size_t ...Rest0, size_t ...Rest1, size_t ...Rest2>
|
||||
struct triplet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>> {
|
||||
|
||||
// Perform depth-first search
|
||||
//---------------------------------------------------------------------
|
||||
// first two tensors contracted first
|
||||
using resulting_tensor_0 = typename get_resuling_tensor<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>>::type;
|
||||
using resulting_index_0 = typename get_resuling_index<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>>::type;
|
||||
|
||||
static constexpr size_t flop_count_01_0 = pair_flop_cost<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_01_1 = pair_flop_cost<resulting_index_0,Index<Idx2...>,resulting_tensor_0,Tensor<T,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest2)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_01 = flop_count_01_0 + flop_count_01_1;
|
||||
|
||||
|
||||
// first and last tensors contracted first
|
||||
using resulting_tensor_1 = typename get_resuling_tensor<Index<Idx0...>,Index<Idx2...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest2...>>::type;
|
||||
using resulting_index_1 = typename get_resuling_index<Index<Idx0...>,Index<Idx2...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest2...>>::type;
|
||||
|
||||
static constexpr size_t flop_count_02_0 = pair_flop_cost<Index<Idx0...>,Index<Idx2...>,Tensor<T,Rest0...>,Tensor<T,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest2)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_02_1 = pair_flop_cost<resulting_index_1,Index<Idx1...>,resulting_tensor_1,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_02 = flop_count_02_0 + flop_count_02_1;
|
||||
|
||||
|
||||
// second and last tensors contracted first
|
||||
using resulting_tensor_2 = typename get_resuling_tensor<Index<Idx1...>,Index<Idx2...>,
|
||||
Tensor<T,Rest1...>,Tensor<T,Rest2...>>::type;
|
||||
using resulting_index_2 = typename get_resuling_index<Index<Idx1...>,Index<Idx2...>,
|
||||
Tensor<T,Rest1...>,Tensor<T,Rest2...>>::type;
|
||||
|
||||
static constexpr size_t flop_count_12_0 = pair_flop_cost<Index<Idx1...>,Index<Idx2...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest2)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_12_1 = pair_flop_cost<resulting_index_2,Index<Idx0...>,resulting_tensor_2,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_12 = flop_count_12_0 + flop_count_12_1;
|
||||
|
||||
static constexpr size_t flop_count_012 = single_evaluation_triplet_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>>::value;
|
||||
|
||||
static constexpr size_t min_cost = meta_min<flop_count_01,flop_count_02,flop_count_12,flop_count_012>::value;
|
||||
static constexpr int which_variant = meta_argmin<flop_count_01,flop_count_02,flop_count_12,flop_count_012>::value;
|
||||
|
||||
// this is the overall resulting tensor and index from overall triplet contraction
|
||||
using resulting_tensor = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_tensor<resulting_index_0,Index<Idx2...>,resulting_tensor_0,Tensor<T,Rest2...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_tensor<Index<Idx1...>,resulting_index_1,Tensor<T,Rest1...>,resulting_tensor_1>::type,
|
||||
typename get_resuling_tensor<Index<Idx0...>,resulting_index_2,Tensor<T,Rest0...>,resulting_tensor_2>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
using resulting_index = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_index<resulting_index_0,Index<Idx2...>,resulting_tensor_0,Tensor<T,Rest2...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_index<Index<Idx1...>,resulting_index_1,Tensor<T,Rest1...>,resulting_tensor_1>::type,
|
||||
typename get_resuling_index<Index<Idx0...>,resulting_index_2,Tensor<T,Rest0...>,resulting_tensor_2>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
};
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Cost model for quartet tensor network contraction
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Tensor0, class Tensor1, class Tensor2, class Tensor3>
|
||||
struct quartet_flop_cost;
|
||||
|
||||
template<class T, size_t... Idx0, size_t... Idx1, size_t... Idx2, size_t... Idx3,
|
||||
size_t ...Rest0, size_t ...Rest1, size_t ...Rest2, size_t ...Rest3>
|
||||
struct quartet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>> {
|
||||
|
||||
// Perform depth-first search
|
||||
//---------------------------------------------------------------------
|
||||
// first three tensors contracted first
|
||||
using triplet_cost_012 = triplet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>>;
|
||||
|
||||
using resulting_tensor_0 = typename triplet_cost_012::resulting_tensor;
|
||||
using resulting_index_0 = typename triplet_cost_012::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_012 = triplet_cost_012::min_cost;
|
||||
static constexpr size_t flop_count_012_3 = pair_flop_cost<resulting_index_0,Index<Idx3...>,resulting_tensor_0,Tensor<T,Rest3...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest3)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_0 = flop_count_012 + flop_count_012_3;
|
||||
|
||||
|
||||
// first, second and last tensors contracted first
|
||||
using triplet_cost_013 = triplet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx3...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest3...>>;
|
||||
|
||||
using resulting_tensor_1 = typename triplet_cost_013::resulting_tensor;
|
||||
using resulting_index_1 = typename triplet_cost_013::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_013 = triplet_cost_013::min_cost;
|
||||
static constexpr size_t flop_count_013_2 = pair_flop_cost<resulting_index_1,Index<Idx2...>,resulting_tensor_1,Tensor<T,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest2)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_1 = flop_count_013 + flop_count_013_2;
|
||||
|
||||
|
||||
// first, third and last tensors contracted first
|
||||
using triplet_cost_023 = triplet_flop_cost<Index<Idx0...>,Index<Idx2...>,Index<Idx3...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>>;
|
||||
|
||||
using resulting_tensor_2 = typename triplet_cost_023::resulting_tensor;
|
||||
using resulting_index_2 = typename triplet_cost_023::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_023 = triplet_cost_023::min_cost;
|
||||
static constexpr size_t flop_count_023_1 = pair_flop_cost<resulting_index_2,Index<Idx1...>,resulting_tensor_2,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_2 = flop_count_023 + flop_count_023_1;
|
||||
|
||||
|
||||
// last three tensors contracted first
|
||||
using triplet_cost_123 = triplet_flop_cost<Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,
|
||||
Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>>;
|
||||
|
||||
using resulting_tensor_3 = typename triplet_cost_123::resulting_tensor;
|
||||
using resulting_index_3 = typename triplet_cost_123::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_123 = triplet_cost_123::min_cost;
|
||||
static constexpr size_t flop_count_123_0 = pair_flop_cost<resulting_index_3,Index<Idx0...>,resulting_tensor_3,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_3 = flop_count_123 + flop_count_123_0;
|
||||
|
||||
static constexpr size_t min_cost = meta_min<flop_count_0,flop_count_1,flop_count_2,flop_count_3>::value;
|
||||
static constexpr int which_variant = meta_argmin<flop_count_0,flop_count_1,flop_count_2,flop_count_3>::value;
|
||||
|
||||
|
||||
// this is the overall resulting tensor and index from overall quartet contraction
|
||||
using resulting_tensor = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_tensor<resulting_index_0,Index<Idx3...>,resulting_tensor_0,Tensor<T,Rest3...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_tensor<Index<Idx2...>,resulting_index_1,Tensor<T,Rest2...>,resulting_tensor_1>::type,
|
||||
typename std::conditional<
|
||||
which_variant==2,
|
||||
typename get_resuling_tensor<Index<Idx1...>,resulting_index_2,Tensor<T,Rest1...>,resulting_tensor_2>::type,
|
||||
typename get_resuling_tensor<Index<Idx0...>,resulting_index_3,Tensor<T,Rest0...>,resulting_tensor_3>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
using resulting_index = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_index<resulting_index_0,Index<Idx3...>,resulting_tensor_0,Tensor<T,Rest3...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_index<Index<Idx2...>,resulting_index_1,Tensor<T,Rest2...>,resulting_tensor_1>::type,
|
||||
typename std::conditional<
|
||||
which_variant==2,
|
||||
typename get_resuling_index<Index<Idx1...>,resulting_index_2,Tensor<T,Rest1...>,resulting_tensor_2>::type,
|
||||
typename get_resuling_index<Index<Idx0...>,resulting_index_3,Tensor<T,Rest0...>,resulting_tensor_3>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
};
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Cost model for quintet tensor contraction
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4,
|
||||
class Tensor0, class Tensor1, class Tensor2, class Tensor3, class Tensor4>
|
||||
struct quintet_flop_cost;
|
||||
|
||||
template<class T, size_t... Idx0, size_t... Idx1, size_t... Idx2, size_t... Idx3, size_t... Idx4,
|
||||
size_t ...Rest0, size_t ...Rest1, size_t ...Rest2, size_t ...Rest3, size_t ...Rest4>
|
||||
struct quintet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>, Index<Idx4...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>> {
|
||||
|
||||
// Perform depth-first search
|
||||
//---------------------------------------------------------------------
|
||||
// first four tensors contracted first
|
||||
using quartet_cost_0123 = quartet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>>;
|
||||
|
||||
using resulting_tensor_0 = typename quartet_cost_0123::resulting_tensor;
|
||||
using resulting_index_0 = typename quartet_cost_0123::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_0123 = quartet_cost_0123::min_cost;
|
||||
static constexpr size_t flop_count_0123_4 = pair_flop_cost<resulting_index_0,Index<Idx4...>,resulting_tensor_0,Tensor<T,Rest4...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest4)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_0 = flop_count_0123 + flop_count_0123_4;
|
||||
|
||||
|
||||
// 1st, 2nd, 3rd, 5th tensors contracted first
|
||||
using quartet_cost_0124 = quartet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx4...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest4...>>;
|
||||
|
||||
using resulting_tensor_1 = typename quartet_cost_0124::resulting_tensor;
|
||||
using resulting_index_1 = typename quartet_cost_0124::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_0124 = quartet_cost_0124::min_cost;
|
||||
static constexpr size_t flop_count_0124_3 = pair_flop_cost<resulting_index_1,Index<Idx3...>,resulting_tensor_1,Tensor<T,Rest3...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest3)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_1 = flop_count_0124 + flop_count_0124_3;
|
||||
|
||||
|
||||
// 1st, 2nd, 4th, 5th tensors contracted first
|
||||
using quartet_cost_0134 = quartet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx3...>,Index<Idx4...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>>;
|
||||
|
||||
using resulting_tensor_2 = typename quartet_cost_0134::resulting_tensor;
|
||||
using resulting_index_2 = typename quartet_cost_0134::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_0134 = quartet_cost_0134::min_cost;
|
||||
static constexpr size_t flop_count_0134_2 = pair_flop_cost<resulting_index_2,Index<Idx2...>,resulting_tensor_2,Tensor<T,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest2)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_2 = flop_count_0134 + flop_count_0134_2;
|
||||
|
||||
|
||||
// 1st, 3rd, 4th, 5th tensors contracted first
|
||||
using quartet_cost_0234 = quartet_flop_cost<Index<Idx0...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>>;
|
||||
|
||||
using resulting_tensor_3 = typename quartet_cost_0234::resulting_tensor;
|
||||
using resulting_index_3 = typename quartet_cost_0234::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_0234 = quartet_cost_0234::min_cost;
|
||||
static constexpr size_t flop_count_0234_1 = pair_flop_cost<resulting_index_3,Index<Idx1...>,resulting_tensor_3,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_3 = flop_count_0234 + flop_count_0234_1;
|
||||
|
||||
|
||||
// last four tensors contracted first
|
||||
using quartet_cost_1234 = quartet_flop_cost<Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>,
|
||||
Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>>;
|
||||
|
||||
using resulting_tensor_4 = typename quartet_cost_1234::resulting_tensor;
|
||||
using resulting_index_4 = typename quartet_cost_1234::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_1234 = quartet_cost_1234::min_cost;
|
||||
static constexpr size_t flop_count_1234_0 = pair_flop_cost<resulting_index_4,Index<Idx0...>,resulting_tensor_4,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_4 = flop_count_1234 + flop_count_1234_0;
|
||||
|
||||
|
||||
static constexpr size_t min_cost = meta_min<flop_count_0,flop_count_1,flop_count_2,flop_count_3,flop_count_4>::value;
|
||||
static constexpr int which_variant = meta_argmin<flop_count_0,flop_count_1,flop_count_2,flop_count_3,flop_count_4>::value;
|
||||
|
||||
|
||||
// this is the overall resulting tensor and index from overall quintet contraction
|
||||
using resulting_tensor = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_tensor<resulting_index_0,Index<Idx4...>,resulting_tensor_0,Tensor<T,Rest4...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_tensor<Index<Idx3...>,resulting_index_1,Tensor<T,Rest3...>,resulting_tensor_1>::type,
|
||||
typename std::conditional<
|
||||
which_variant==2,
|
||||
typename get_resuling_tensor<Index<Idx2...>,resulting_index_2,Tensor<T,Rest2...>,resulting_tensor_2>::type,
|
||||
typename std::conditional<
|
||||
which_variant==3,
|
||||
typename get_resuling_tensor<Index<Idx1...>,resulting_index_3,Tensor<T,Rest1...>,resulting_tensor_3>::type,
|
||||
typename get_resuling_tensor<Index<Idx0...>,resulting_index_4,Tensor<T,Rest0...>,resulting_tensor_4>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
using resulting_index = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_index<resulting_index_0,Index<Idx4...>,resulting_tensor_0,Tensor<T,Rest4...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_index<Index<Idx3...>,resulting_index_1,Tensor<T,Rest3...>,resulting_tensor_1>::type,
|
||||
typename std::conditional<
|
||||
which_variant==2,
|
||||
typename get_resuling_index<Index<Idx2...>,resulting_index_2,Tensor<T,Rest2...>,resulting_tensor_2>::type,
|
||||
typename std::conditional<
|
||||
which_variant==3,
|
||||
typename get_resuling_index<Index<Idx1...>,resulting_index_3,Tensor<T,Rest1...>,resulting_tensor_3>::type,
|
||||
typename get_resuling_index<Index<Idx0...>,resulting_index_4,Tensor<T,Rest0...>,resulting_tensor_4>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
};
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
|
||||
// Cost model for sixtet tensor contraction
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4, class Ind5,
|
||||
class Tensor0, class Tensor1, class Tensor2, class Tensor3, class Tensor4, class Tensor5>
|
||||
struct sixtet_flop_cost;
|
||||
|
||||
template<class T, size_t... Idx0, size_t... Idx1, size_t... Idx2, size_t... Idx3, size_t... Idx4, size_t... Idx5,
|
||||
size_t ...Rest0, size_t ...Rest1, size_t ...Rest2, size_t ...Rest3, size_t ...Rest4, size_t ...Rest5>
|
||||
struct sixtet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>, Index<Idx4...>, Index<Idx5...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>> {
|
||||
|
||||
// Perform depth-first search
|
||||
//---------------------------------------------------------------------
|
||||
// first 5 tensors contracted first
|
||||
using quintet_cost_01234 = quintet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>>;
|
||||
|
||||
using resulting_tensor_0 = typename quintet_cost_01234::resulting_tensor;
|
||||
using resulting_index_0 = typename quintet_cost_01234::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_01234 = quintet_cost_01234::min_cost;
|
||||
static constexpr size_t flop_count_01234_5 = pair_flop_cost<resulting_index_0,Index<Idx5...>,resulting_tensor_0,Tensor<T,Rest5...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest5)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_0 = flop_count_01234 + flop_count_01234_5;
|
||||
|
||||
|
||||
// 1st, 2nd, 3rd, 4th, 6th tensors contracted first
|
||||
using quintet_cost_01235 = quintet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx5...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest5...>>;
|
||||
|
||||
using resulting_tensor_1 = typename quintet_cost_01235::resulting_tensor;
|
||||
using resulting_index_1 = typename quintet_cost_01235::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_01235 = quintet_cost_01235::min_cost;
|
||||
static constexpr size_t flop_count_01235_4 = pair_flop_cost<resulting_index_1,Index<Idx4...>,resulting_tensor_1,Tensor<T,Rest4...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest4)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_1 = flop_count_01235 + flop_count_01235_4;
|
||||
|
||||
|
||||
// 1st, 2nd, 3rd, 5th, 6th tensors contracted first
|
||||
using quintet_cost_01245 = quintet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx4...>,Index<Idx5...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>>;
|
||||
|
||||
using resulting_tensor_2 = typename quintet_cost_01245::resulting_tensor;
|
||||
using resulting_index_2 = typename quintet_cost_01245::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_01245 = quintet_cost_01235::min_cost;
|
||||
static constexpr size_t flop_count_01245_3 = pair_flop_cost<resulting_index_2,Index<Idx3...>,resulting_tensor_2,Tensor<T,Rest3...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest3)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_2 = flop_count_01245 + flop_count_01245_3;
|
||||
|
||||
|
||||
// 1st, 2nd, 4th, 5th, 6th tensors contracted first
|
||||
using quintet_cost_01345 = quintet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx3...>,Index<Idx4...>,Index<Idx5...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>>;
|
||||
|
||||
using resulting_tensor_3 = typename quintet_cost_01345::resulting_tensor;
|
||||
using resulting_index_3 = typename quintet_cost_01345::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_01345 = quintet_cost_01235::min_cost;
|
||||
static constexpr size_t flop_count_01345_2 = pair_flop_cost<resulting_index_3,Index<Idx2...>,resulting_tensor_3,Tensor<T,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest2)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_3 = flop_count_01345 + flop_count_01345_2;
|
||||
|
||||
|
||||
// 1st, 3rd, 4th, 5th, 6th tensors contracted first
|
||||
using quintet_cost_02345 = quintet_flop_cost<Index<Idx0...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>,Index<Idx5...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>>;
|
||||
|
||||
using resulting_tensor_4 = typename quintet_cost_02345::resulting_tensor;
|
||||
using resulting_index_4 = typename quintet_cost_02345::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_02345 = quintet_cost_01235::min_cost;
|
||||
static constexpr size_t flop_count_02345_1 = pair_flop_cost<resulting_index_4,Index<Idx1...>,resulting_tensor_4,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_4 = flop_count_02345 + flop_count_02345_1;
|
||||
|
||||
|
||||
// last 5 tensors contracted first
|
||||
using quintet_cost_12345 = quintet_flop_cost<Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>,Index<Idx5...>,
|
||||
Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>>;
|
||||
|
||||
using resulting_tensor_5 = typename quintet_cost_12345::resulting_tensor;
|
||||
using resulting_index_5 = typename quintet_cost_12345::resulting_index;
|
||||
|
||||
static constexpr size_t flop_count_12345 = quintet_cost_01235::min_cost;
|
||||
static constexpr size_t flop_count_12345_0 = pair_flop_cost<resulting_index_5,Index<Idx0...>,resulting_tensor_5,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::value;
|
||||
|
||||
static constexpr size_t flop_count_5 = flop_count_12345 + flop_count_12345_0;
|
||||
|
||||
|
||||
static constexpr size_t min_cost = meta_min<flop_count_0,flop_count_1,flop_count_2,flop_count_3,flop_count_4,flop_count_5>::value;
|
||||
static constexpr int which_variant = meta_argmin<flop_count_0,flop_count_1,flop_count_2,flop_count_3,flop_count_4,flop_count_5>::value;
|
||||
|
||||
|
||||
// this is the overall resulting tensor and index from overall sextet contraction
|
||||
using resulting_tensor = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_tensor<resulting_index_0,Index<Idx5...>,resulting_tensor_0,Tensor<T,Rest5...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_tensor<Index<Idx4...>,resulting_index_1,Tensor<T,Rest4...>,resulting_tensor_1>::type,
|
||||
typename std::conditional<
|
||||
which_variant==2,
|
||||
typename get_resuling_tensor<Index<Idx3...>,resulting_index_2,Tensor<T,Rest3...>,resulting_tensor_2>::type,
|
||||
typename std::conditional<
|
||||
which_variant==3,
|
||||
typename get_resuling_tensor<Index<Idx2...>,resulting_index_3,Tensor<T,Rest2...>,resulting_tensor_3>::type,
|
||||
typename std::conditional<
|
||||
which_variant==4,
|
||||
typename get_resuling_tensor<Index<Idx1...>,resulting_index_4,Tensor<T,Rest1...>,resulting_tensor_4>::type,
|
||||
typename get_resuling_tensor<Index<Idx0...>,resulting_index_5,Tensor<T,Rest0...>,resulting_tensor_5>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
using resulting_index = typename std::conditional<
|
||||
which_variant==0,
|
||||
typename get_resuling_index<resulting_index_0,Index<Idx5...>,resulting_tensor_0,Tensor<T,Rest5...>>::type,
|
||||
typename std::conditional<
|
||||
which_variant==1,
|
||||
typename get_resuling_index<Index<Idx4...>,resulting_index_1,Tensor<T,Rest4...>,resulting_tensor_1>::type,
|
||||
typename std::conditional<
|
||||
which_variant==2,
|
||||
typename get_resuling_index<Index<Idx3...>,resulting_index_2,Tensor<T,Rest3...>,resulting_tensor_2>::type,
|
||||
typename std::conditional<
|
||||
which_variant==3,
|
||||
typename get_resuling_index<Index<Idx2...>,resulting_index_3,Tensor<T,Rest2...>,resulting_tensor_3>::type,
|
||||
typename std::conditional<
|
||||
which_variant==4,
|
||||
typename get_resuling_index<Index<Idx1...>,resulting_index_4,Tensor<T,Rest1...>,resulting_tensor_4>::type,
|
||||
typename get_resuling_index<Index<Idx0...>,resulting_index_5,Tensor<T,Rest0...>,resulting_tensor_5>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
};
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// einsum helper to extract the resulting index and the resulting tensor
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
template<typename ...Ts>
|
||||
struct einsum_helper;
|
||||
|
||||
template<class Ind0,
|
||||
typename T, size_t ... Rest0>
|
||||
struct einsum_helper<Ind0,Tensor<T,Rest0...>> {
|
||||
using resulting_index = typename contraction_impl<Ind0, Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
using resulting_tensor = typename contraction_impl<Ind0, Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::type;
|
||||
};
|
||||
|
||||
template<class Ind0, class Ind1,
|
||||
class Tensor0, class Tensor1>
|
||||
struct einsum_helper<Ind0,Ind1,Tensor0,Tensor1> {
|
||||
using resulting_index = typename get_resuling_index<Ind0,Ind1,Tensor0,Tensor1>::type;
|
||||
using resulting_tensor = typename get_resuling_tensor<Ind0,Ind1,Tensor0,Tensor1>::type;
|
||||
};
|
||||
|
||||
template<class Ind0, class Ind1, class Ind2,
|
||||
class Tensor0, class Tensor1, class Tensor2>
|
||||
struct einsum_helper<Ind0,Ind1,Ind2,Tensor0,Tensor1,Tensor2> {
|
||||
using cost_model = triplet_flop_cost<Ind0,Ind1,Ind2,
|
||||
Tensor0,Tensor1,Tensor2>;
|
||||
using resulting_index = typename cost_model::resulting_index;
|
||||
using resulting_tensor = typename cost_model::resulting_tensor;
|
||||
};
|
||||
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3,
|
||||
class Tensor0, class Tensor1, class Tensor2, class Tensor3>
|
||||
struct einsum_helper<Ind0,Ind1,Ind2,Ind3,Tensor0,Tensor1,Tensor2,Tensor3> {
|
||||
using cost_model = quartet_flop_cost<Ind0,Ind1,Ind2,Ind3,
|
||||
Tensor0,Tensor1,Tensor2,Tensor3>;
|
||||
using resulting_index = typename cost_model::resulting_index;
|
||||
using resulting_tensor = typename cost_model::resulting_tensor;
|
||||
};
|
||||
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4,
|
||||
class Tensor0, class Tensor1, class Tensor2, class Tensor3, class Tensor4>
|
||||
struct einsum_helper<Ind0,Ind1,Ind2,Ind3,Ind4,Tensor0,Tensor1,Tensor2,Tensor3,Tensor4> {
|
||||
using cost_model = quintet_flop_cost<Ind0,Ind1,Ind2,Ind3,Ind4,
|
||||
Tensor0,Tensor1,Tensor2,Tensor3,Tensor4>;
|
||||
using resulting_index = typename cost_model::resulting_index;
|
||||
using resulting_tensor = typename cost_model::resulting_tensor;
|
||||
};
|
||||
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4, class Ind5,
|
||||
class Tensor0, class Tensor1, class Tensor2, class Tensor3, class Tensor4, class Tensor5>
|
||||
struct einsum_helper<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Tensor0,Tensor1,Tensor2,Tensor3,Tensor4,Tensor5> {
|
||||
using cost_model = sixtet_flop_cost<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,
|
||||
Tensor0,Tensor1,Tensor2,Tensor3,Tensor4,Tensor5>;
|
||||
using resulting_index = typename cost_model::resulting_index;
|
||||
using resulting_tensor = typename cost_model::resulting_tensor;
|
||||
};
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
|
||||
#endif // FASTOR_DONT_PERFORM_OP_MIN
|
||||
|
||||
|
||||
#endif // OPMIN_META_H
|
||||
209
noarch/include/Fastor/meta/tensor_meta.h
Normal file
209
noarch/include/Fastor/meta/tensor_meta.h
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef TENSOR_META_H
|
||||
#define TENSOR_META_H
|
||||
|
||||
#include "Fastor/config/config.h"
|
||||
#include "Fastor/meta/meta.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// UpLoType
|
||||
namespace UpLoType {
|
||||
struct General {};
|
||||
struct Lower {};
|
||||
struct UniLower {};
|
||||
struct StrictlyLower {};
|
||||
struct Upper {};
|
||||
struct UniUpper {};
|
||||
struct StrictlyUpper {};
|
||||
struct Diagonal {};
|
||||
struct BiDiagonal {};
|
||||
struct TriDiagonal {};
|
||||
struct BlockDiagonal {};
|
||||
struct Symmetric {};
|
||||
struct SymmetricPositiveDefinite {};
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template <size_t...T>
|
||||
struct is_unique : std::integral_constant<bool, true> {};
|
||||
|
||||
template <size_t T, size_t U, size_t... VV>
|
||||
struct is_unique<T, U, VV...> : std::integral_constant<bool, T != U && is_unique<T, VV...>::value> {};
|
||||
|
||||
template <size_t...T>
|
||||
struct no_of_unique : std::integral_constant<size_t, 0> {};
|
||||
|
||||
template <size_t T, size_t... UU>
|
||||
struct no_of_unique<T, UU...> : std::integral_constant<size_t, is_unique<T, UU...>::value + no_of_unique<UU...>::value> {};
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
// Note that Intel's ICC 2017 does not support make_index_sequence and the following
|
||||
// version also seems faster than c++14's built-in (for clang) on Linux systems
|
||||
namespace std_ext // back port to c++11
|
||||
{
|
||||
template <size_t... Ints>
|
||||
struct index_sequence
|
||||
{
|
||||
using type = index_sequence;
|
||||
using value_type = size_t;
|
||||
static constexpr std::size_t size() { return sizeof...(Ints); }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------
|
||||
|
||||
template <class Sequence1, class Sequence2>
|
||||
struct _merge_and_renumber;
|
||||
|
||||
template <size_t... I1, size_t... I2>
|
||||
struct _merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
|
||||
: index_sequence<I1..., (sizeof...(I1)+I2)...>
|
||||
{ };
|
||||
|
||||
// --------------------------------------------------------------
|
||||
|
||||
template <size_t N>
|
||||
struct make_index_sequence
|
||||
: _merge_and_renumber<typename make_index_sequence<N/2>::type,
|
||||
typename make_index_sequence<N - N/2>::type>
|
||||
{ };
|
||||
|
||||
template<> struct make_index_sequence<0> : index_sequence<> { };
|
||||
template<> struct make_index_sequence<1> : index_sequence<0> { };
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
template <class... > struct typelist { };
|
||||
template <class T, T ... Vals>
|
||||
using typelist_c = typelist<std::integral_constant<T, Vals>...>;
|
||||
|
||||
template <class... > struct concat;
|
||||
template <> struct concat<> { using type = typelist<>; };
|
||||
template <class... Ts> struct concat<typelist<Ts...>> { using type = typelist<Ts...>; };
|
||||
template <class... Ts, class... Us, class... Args>
|
||||
struct concat<typelist<Ts...>, typelist<Us...>, Args...> : concat<typelist<Ts..., Us...>, Args...> { };
|
||||
|
||||
template <class T, class TL> struct filter_out;
|
||||
template <class T, class... Ts> struct filter_out<T, typelist<Ts...>>
|
||||
: concat< conditional_t_<is_same_v_<T, Ts>, typelist<>, typelist<Ts>>...> { };
|
||||
|
||||
template <class T, class TL>
|
||||
using filter_out_t = typename filter_out<T, TL>::type;
|
||||
|
||||
|
||||
|
||||
template <class >
|
||||
struct uniq;
|
||||
|
||||
template <class TL>
|
||||
using uniq_t = typename uniq<TL>::type;
|
||||
|
||||
template <>
|
||||
struct uniq<typelist<>> {
|
||||
using type = typelist<>;
|
||||
};
|
||||
|
||||
template <class T, class... Ts>
|
||||
struct uniq<typelist<T, Ts...>>
|
||||
: concat<typelist<T>, uniq_t<filter_out_t<T, typelist<Ts...>>>>
|
||||
{ };
|
||||
|
||||
template <size_t N>
|
||||
using size_t_ = std::integral_constant<size_t, N>;
|
||||
|
||||
template <class > struct length;
|
||||
template <class T> using length_t = typename length<T>::type;
|
||||
template <class... Ts>
|
||||
struct length<typelist<Ts...>>
|
||||
: size_t_<sizeof...(Ts)>
|
||||
{ };
|
||||
|
||||
template <size_t... Ns>
|
||||
using no_of_uniques = length_t<uniq_t<typelist<size_t_<Ns>...>>>;
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
////////////////
|
||||
template <class T, template <T...> class Z>
|
||||
struct quote_c {
|
||||
template <class... Ts>
|
||||
using apply = Z<Ts::value...>;
|
||||
};
|
||||
|
||||
template <class MFC, class TL>
|
||||
struct apply_typelist;
|
||||
|
||||
template <class MFC, class TL>
|
||||
using apply_typelist_t = typename apply_typelist<MFC, TL>::type;
|
||||
|
||||
|
||||
template <class MFC, class... Ts>
|
||||
struct apply_typelist<MFC, typelist<Ts...>> {
|
||||
using type = typename MFC::template apply<Ts...>;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
// Check if indices appear more than twice [for Einstein summation]
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
namespace useless {
|
||||
|
||||
template <typename T>
|
||||
constexpr const T& ct_max(T const& t1, T const& t2) {
|
||||
return t1 < t2 ? t2 : t1;
|
||||
}
|
||||
|
||||
|
||||
template <size_t S, size_t... Sizes>
|
||||
struct count__;
|
||||
|
||||
template <size_t S>
|
||||
struct count__<S> {
|
||||
static constexpr size_t value = std::integral_constant<size_t, 0>::value;
|
||||
};
|
||||
|
||||
template <size_t S1, size_t... Sizes>
|
||||
struct count__<S1, S1, Sizes...> {
|
||||
static constexpr size_t value = std::integral_constant<size_t, 1 + count__<S1, Sizes...>::value>::value;
|
||||
};
|
||||
|
||||
template <size_t S1, size_t S2, size_t... Sizes>
|
||||
struct count__<S1, S2, Sizes...> {
|
||||
static constexpr size_t value = count__<S1, Sizes...>::value;
|
||||
};
|
||||
|
||||
template <size_t...all>
|
||||
struct max_count;
|
||||
|
||||
template <>
|
||||
struct max_count<> {
|
||||
static constexpr size_t value = std::integral_constant<size_t, 0>::value;
|
||||
};
|
||||
|
||||
template <size_t S, size_t... Sizes>
|
||||
struct max_count<S, Sizes...> {
|
||||
static constexpr size_t value = std::integral_constant<size_t, ct_max(1 + count__<S, Sizes...>::value,
|
||||
max_count<Sizes...>::value)>::value;
|
||||
};
|
||||
|
||||
} // useless
|
||||
|
||||
template <size_t... Sizes>
|
||||
struct no_more_than_two {
|
||||
static constexpr size_t value = std::integral_constant<bool, useless::max_count<Sizes...>::value <= 2>::value;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // TENSOR_META_H
|
||||
Reference in New Issue
Block a user