Add Fastor library

This commit is contained in:
Bassem Girgis
2025-03-22 01:17:52 -05:00
parent 5546e086f6
commit 4dd5939693
132 changed files with 55086 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View 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_

View 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

View 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