Add Fastor library
This commit is contained in:
233
noarch/include/Fastor/tensor_algebra/abstract_contraction.h
Normal file
233
noarch/include/Fastor/tensor_algebra/abstract_contraction.h
Normal file
@@ -0,0 +1,233 @@
|
||||
#ifndef ABSTRACT_CONTRACTION_H
|
||||
#define ABSTRACT_CONTRACTION_H
|
||||
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor/TensorTraits.h"
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
#include "Fastor/meta/opmin_meta.h"
|
||||
#include "Fastor/expressions/expression_traits.h"
|
||||
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
|
||||
#include "Fastor/tensor_algebra/contraction.h"
|
||||
#include "Fastor/tensor_algebra/network_contraction.h"
|
||||
#include "Fastor/tensor_algebra/network_contraction_no_opmin.h"
|
||||
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2014
|
||||
// The following set of functions implement by-pair as well as
|
||||
// network contraction/einsum for infinite number of expressions
|
||||
// the expressions are always evaluated so no aliasing occurs
|
||||
// and the contractions are forwarded to their tensor counterparts
|
||||
// which perform operation minimiation and are optimised for performance
|
||||
|
||||
// Single expression - contraction
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
template<class Index_I, typename Derived0, size_t DIM0,
|
||||
enable_if_t_<!is_tensor_v<Derived0>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
contraction(const AbstractTensor<Derived0,DIM0> &a)
|
||||
{
|
||||
typename Derived0::result_type res_a(a);
|
||||
return extractor_contract_1<Index_I>::contract_impl(res_a);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// Single expression - einsum
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
template<class Index_I, typename Derived0, size_t DIM0,
|
||||
enable_if_t_<!is_tensor_v<Derived0>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensor<Derived0,DIM0> &a)
|
||||
{
|
||||
typename Derived0::result_type res_a(a);
|
||||
return extractor_contract_1<Index_I>::contract_impl(res_a);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// By pair expressions - contraction
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
template<class Index_I, class Index_J, typename Derived0, typename Derived1, size_t DIM0, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
contraction(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b)
|
||||
{
|
||||
typename Derived0::result_type res_a(a);
|
||||
typename Derived1::result_type res_b(b);
|
||||
return extractor_contract_2<Index_I,Index_J>::contract_impl(res_a,res_b);
|
||||
}
|
||||
template<class Index_I, class Index_J, typename Derived0, typename Derived1, size_t DIM0, size_t DIM1,
|
||||
enable_if_t_<is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
contraction(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b)
|
||||
{
|
||||
typename Derived1::result_type res_b(b);
|
||||
return extractor_contract_2<Index_I,Index_J>::contract_impl(a,res_b);
|
||||
}
|
||||
template<class Index_I, class Index_J, typename Derived0, typename Derived1, size_t DIM0, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && is_tensor_v<Derived1>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
contraction(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b)
|
||||
{
|
||||
typename Derived0::result_type res_a(a);
|
||||
return extractor_contract_2<Index_I,Index_J>::contract_impl(res_a,b);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// By pair expressions - einsum
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
template<class Index_I, class Index_J, typename Derived0, typename Derived1, size_t DIM0, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b)
|
||||
{
|
||||
typename Derived0::result_type res_a(a);
|
||||
typename Derived1::result_type res_b(b);
|
||||
return einsum<Index_I,Index_J>(res_a,res_b);
|
||||
}
|
||||
template<class Index_I, class Index_J, typename Derived0, typename Derived1, size_t DIM0, size_t DIM1,
|
||||
enable_if_t_<is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b)
|
||||
{
|
||||
typename Derived1::result_type res_b(b);
|
||||
return einsum<Index_I,Index_J>(a,res_b);
|
||||
}
|
||||
template<class Index_I, class Index_J, typename Derived0, typename Derived1, size_t DIM0, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && is_tensor_v<Derived1>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b)
|
||||
{
|
||||
typename Derived0::result_type res_a(a);
|
||||
return einsum<Index_I,Index_J>(res_a,b);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// network contraction for expressions
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
namespace internal {
|
||||
|
||||
// helper functions to evaluate expression in to intermediate tensors
|
||||
// We evaluate all intermediate tensors and pack them in to a single tuple
|
||||
FASTOR_INLINE
|
||||
std::tuple<>
|
||||
contraction_chain_evaluate()
|
||||
{
|
||||
return std::tuple<>{};
|
||||
}
|
||||
|
||||
// Note that if the expression is a tensor the evaluation is free
|
||||
// as evaluate returns the tensor itself
|
||||
template<typename Derived0, size_t DIM0>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
contraction_chain_evaluate(const AbstractTensor<Derived0,DIM0>& a)
|
||||
{
|
||||
return evaluate(a.self());
|
||||
}
|
||||
|
||||
template<typename AbstractTensorType0, typename ... AbstractTensorTypes>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
contraction_chain_evaluate(const AbstractTensorType0& a, const AbstractTensorTypes& ... rest)
|
||||
{
|
||||
return std::tuple_cat(std::make_tuple(evaluate(a)),contraction_chain_evaluate(rest...));
|
||||
}
|
||||
|
||||
// helper functor to unpack the tuple and forward the pack of tensor
|
||||
// to network contraction for operation minimisation
|
||||
template<class Index_I, class Index_J, class ... Index_Ks>
|
||||
struct unpack_contraction_tuple {
|
||||
|
||||
template<typename Tuple, size_t ... I>
|
||||
static auto apply(Tuple t, std_ext::index_sequence<I ...>)
|
||||
{
|
||||
return contraction<Index_I,Index_J,Index_Ks...>(std::get<I>(t) ...);
|
||||
}
|
||||
template<typename Tuple>
|
||||
static auto apply(Tuple t)
|
||||
{
|
||||
constexpr auto size = std::tuple_size<Tuple>::value;
|
||||
return apply(t, std_ext::make_index_sequence<size>{});
|
||||
}
|
||||
};
|
||||
|
||||
// helper functor to unpack the tuple and forward the pack of tensor
|
||||
// to network einsum for operation minimisation
|
||||
template<class Index_I, class Index_J, class ... Index_Ks>
|
||||
struct unpack_einsum_tuple {
|
||||
|
||||
template<typename Tuple, size_t ... I>
|
||||
static auto apply(Tuple t, std_ext::index_sequence<I ...>)
|
||||
{
|
||||
return einsum<Index_I,Index_J,Index_Ks...>(std::get<I>(t) ...);
|
||||
}
|
||||
template<typename Tuple>
|
||||
static auto apply(Tuple t)
|
||||
{
|
||||
constexpr auto size = std::tuple_size<Tuple>::value;
|
||||
return apply(t, std_ext::make_index_sequence<size>{});
|
||||
}
|
||||
};
|
||||
|
||||
template<class Index_I, class Index_J, class ... Index_Ks>
|
||||
struct unpack_einsum_helper_tuple {
|
||||
|
||||
template<typename Tuple, size_t ... I>
|
||||
static constexpr auto apply(Tuple t, std_ext::index_sequence<I ...>)
|
||||
{
|
||||
return einsum_helper<Index_I,Index_J,Index_Ks...,decltype(std::get<I>(t)) ...>{};
|
||||
}
|
||||
template<typename Tuple>
|
||||
static constexpr auto apply(Tuple t)
|
||||
{
|
||||
constexpr auto size = std::tuple_size<Tuple>::value;
|
||||
return apply(t, std_ext::make_index_sequence<size>{});
|
||||
}
|
||||
};
|
||||
} // internal
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// network contraction
|
||||
template<class Index_I, class Index_J, class ... Index_Ks,
|
||||
typename AbstractTensorType0, typename AbstractTensorType1, typename ... AbstractTensorTypes>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
contraction(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest)
|
||||
{
|
||||
return internal::unpack_contraction_tuple<Index_I,Index_J,Index_Ks...>::apply(internal::contraction_chain_evaluate(a,b,rest...));
|
||||
}
|
||||
|
||||
// network einsum
|
||||
template<class Index_I, class Index_J, class ... Index_Ks,
|
||||
typename AbstractTensorType0, typename AbstractTensorType1, typename ... AbstractTensorTypes>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
einsum(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest)
|
||||
{
|
||||
// network einsum is not defined yet
|
||||
return internal::unpack_einsum_tuple<Index_I,Index_J,Index_Ks...>::apply(internal::contraction_chain_evaluate(a,b,rest...));
|
||||
// but it dispatches to network contraction anyway and contraction uses by-pair einsum in turn
|
||||
// return internal::unpack_contraction_tuple<Index_I,Index_J,Index_Ks...>::apply(internal::contraction_chain_evaluate(a,b,rest...));
|
||||
}
|
||||
|
||||
#endif // CXX 2014
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // ABSTRACT_CONTRACTION_H
|
||||
747
noarch/include/Fastor/tensor_algebra/contraction.h
Normal file
747
noarch/include/Fastor/tensor_algebra/contraction.h
Normal file
@@ -0,0 +1,747 @@
|
||||
#ifndef CONTRACTION_H
|
||||
#define CONTRACTION_H
|
||||
|
||||
#include "Fastor/backend/dyadic.h"
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
|
||||
//using namespace details;
|
||||
//namespace details {
|
||||
|
||||
|
||||
// Define this if fastest (complete meta-engine based) tensor contraction is required.
|
||||
// Note that this blows up memory consumption and compilation time exponentially
|
||||
|
||||
//#define CONTRACT_OPT 2
|
||||
|
||||
// Define this if faster (partial meta-engine based) tensor contraction is required.
|
||||
// Note that this blows up memory consumption and compilation time but not as much
|
||||
|
||||
//#define CONTRACT_OPT 1
|
||||
|
||||
|
||||
template<class Idx0, class Idx1, class Tens0, class Tens1, size_t ... Args>
|
||||
struct RecursiveCartesian;
|
||||
|
||||
template<typename T, size_t ...Idx0, size_t ...Idx1, size_t ...Rest0, size_t ...Rest1, size_t First, size_t ... Lasts>
|
||||
struct RecursiveCartesian<Index<Idx0...>, Index<Idx1...>, Tensor<T,Rest0...>, Tensor<T,Rest1...>, First, Lasts...> {
|
||||
|
||||
static constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
static
|
||||
FASTOR_INLINE
|
||||
void Do(const T *a_data, const T *b_data, T *out_data, std::array<int,out_dim> &as, std::array<int,out_dim> &idx) {
|
||||
for (size_t i=0; i<First; ++i) {
|
||||
idx[sizeof...(Lasts)] = i;
|
||||
RecursiveCartesian<Index<Idx0...>, Index<Idx1...>,
|
||||
Tensor<T,Rest0...>, Tensor<T,Rest1...>,Lasts...>::Do(a_data, b_data, out_data, as, idx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx0, size_t ...Idx1, size_t ...Rest0, size_t ...Rest1>
|
||||
struct RecursiveCartesian<Index<Idx0...>, Index<Idx1...>, Tensor<T,Rest0...>, Tensor<T,Rest1...>,Last>
|
||||
{
|
||||
using _contraction_impl = contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>;
|
||||
using resulting_tensor = typename _contraction_impl::type;
|
||||
using resulting_index = typename _contraction_impl::indices;
|
||||
static constexpr bool _is_reduction = resulting_tensor::dimension_t::value == 0;
|
||||
|
||||
static constexpr int a_dim = sizeof...(Rest0);
|
||||
static constexpr int b_dim = sizeof...(Rest1);
|
||||
static constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
|
||||
static constexpr auto& idx_a = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx0...>,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
|
||||
static constexpr auto& idx_b = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx1...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
static constexpr auto& idx_out = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
resulting_index,resulting_tensor,
|
||||
typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::indices;
|
||||
|
||||
using nloops = loop_setter<
|
||||
Index<Idx0...,Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
static constexpr auto& maxes_out = nloops::dims;
|
||||
static constexpr int total = nloops::value;
|
||||
|
||||
static constexpr std::array<size_t,sizeof...(Rest0)> products_a = nprods<Index<Rest0...>,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
static constexpr std::array<size_t,sizeof...(Rest1)> products_b = nprods<Index<Rest1...>,
|
||||
typename std_ext::make_index_sequence<b_dim>::type>::values;
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_vectorisable<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest1...>>;
|
||||
static constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
static constexpr int stride = 1;
|
||||
using V = SIMDVector<T,simd_abi::scalar>;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static
|
||||
FASTOR_INLINE
|
||||
void Do(const T *a_data, const T *b_data, T *out_data, std::array<int,out_dim> &as, std::array<int,out_dim> &idx)
|
||||
{
|
||||
FASTOR_IF_CONSTEXPR(!_is_reduction) {
|
||||
|
||||
using Index_with_dims = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
constexpr std::array<size_t,resulting_tensor::Dimension> products_out = \
|
||||
nprods<Index_with_dims,typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::values;
|
||||
|
||||
V _vec_a;
|
||||
for (size_t i=0; i<Last; i+=stride) {
|
||||
idx[0] = i;
|
||||
std::reverse_copy(idx.begin(),idx.end(),as.begin());
|
||||
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(int it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_b = as[idx_b[b_dim-1]];
|
||||
for(int it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as[idx_b[it]];
|
||||
}
|
||||
int index_out = as[idx_out[resulting_tensor::Dimension-1]];
|
||||
for(int it = 0; it< static_cast<int>(resulting_tensor::Dimension); it++) {
|
||||
index_out += products_out[it]*as[idx_out[it]];
|
||||
}
|
||||
|
||||
// out_data[index_out] += a_data[index_a]*b_data[index_b];
|
||||
// _vec_a.set(*(a_data+index_a));
|
||||
_vec_a.set(a_data[index_a]);
|
||||
// V _vec_out = _vec_a*V(b_data+index_b) + V(out_data+index_out);
|
||||
V _vec_out = fmadd(_vec_a,V(&b_data[index_b]), V(&out_data[index_out]));
|
||||
_vec_out.store(out_data+index_out,false);
|
||||
// _vec_out.aligned_store(&out_data[index_out]);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
using Index_with_dims = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
constexpr std::array<size_t,resulting_tensor::Dimension> products_out = \
|
||||
nprods<Index_with_dims,typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::values;
|
||||
|
||||
V _vec_a;
|
||||
for (size_t i=0; i<Last; i+=stride) {
|
||||
idx[0] = i;
|
||||
std::reverse_copy(idx.begin(),idx.end(),as.begin());
|
||||
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(int it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_b = as[idx_b[b_dim-1]];
|
||||
for(int it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as[idx_b[it]];
|
||||
}
|
||||
|
||||
out_data[0] += a_data[index_a]*b_data[index_b];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// template<typename T, size_t ...Idx0, size_t ...Idx1, size_t ...Rest0, size_t ...Rest1>
|
||||
// struct RecursiveCartesian<Index<Idx0...>, Index<Idx1...>, Tensor<T,Rest0...>, Tensor<T,Rest1...>>
|
||||
// {
|
||||
// using OutTensor = typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::type;
|
||||
// using OutIndices = typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
// static constexpr int a_dim = sizeof...(Rest0);
|
||||
// static constexpr int b_dim = sizeof...(Rest1);
|
||||
// static constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
|
||||
// static constexpr auto& idx_a = IndexTensors<
|
||||
// Index<Idx0..., Idx1...>,
|
||||
// Tensor<T,Rest0...,Rest1...>,
|
||||
// Index<Idx0...>,Tensor<T,Rest0...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
|
||||
// static constexpr auto& idx_b = IndexTensors<
|
||||
// Index<Idx0..., Idx1...>,
|
||||
// Tensor<T,Rest0...,Rest1...>,
|
||||
// Index<Idx1...>,Tensor<T,Rest1...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
// static constexpr auto& idx_out = IndexTensors<
|
||||
// Index<Idx0..., Idx1...>,
|
||||
// Tensor<T,Rest0...,Rest1...>,
|
||||
// OutIndices,OutTensor,
|
||||
// typename std_ext::make_index_sequence<OutTensor::Dimension>::type>::indices;
|
||||
|
||||
// using nloops = loop_setter<
|
||||
// Index<Idx0...,Idx1...>,
|
||||
// Tensor<T,Rest0...,Rest1...>,
|
||||
// typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
// static constexpr auto& maxes_out = nloops::dims;
|
||||
// static constexpr int total = nloops::value;
|
||||
|
||||
// static constexpr std::array<size_t,a_dim> products_a = nprods<Index<Rest0...>,typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
// static constexpr std::array<size_t,b_dim> products_b = nprods<Index<Rest1...>,typename std_ext::make_index_sequence<b_dim>::type>::values;
|
||||
|
||||
// using Index_with_dims = typename put_dims_in_Index<OutTensor>::type;
|
||||
// static constexpr std::array<size_t,OutTensor::Dimension> products_out =
|
||||
// nprods<Index_with_dims,typename std_ext::make_index_sequence<OutTensor::Dimension>::type>::values;
|
||||
|
||||
// #ifndef FASTOR_DONT_VECTORISE
|
||||
// using vectorisability = is_vectorisable<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest1...>>;
|
||||
// static constexpr int stride = vectorisability::stride;
|
||||
// using V = typename vectorisability::type;
|
||||
// #else
|
||||
// static constexpr int stride = 1;
|
||||
// using V = SIMDVector<T,sizeof(T)*8>;
|
||||
// #endif
|
||||
|
||||
|
||||
// static void Do(const T *a_data, const T *b_data, T *out_data, std::array<int,out_dim> &as, std::array<int,out_dim> &idx)
|
||||
// {
|
||||
// std::reverse_copy(idx.begin(),idx.end(),as.begin());
|
||||
|
||||
// int index_a = as[idx_a[a_dim-1]];
|
||||
// for(int it = 0; it< a_dim; it++) {
|
||||
// index_a += products_a[it]*as[idx_a[it]];
|
||||
// }
|
||||
// int index_b = as[idx_b[b_dim-1]];
|
||||
// for(int it = 0; it< b_dim; it++) {
|
||||
// index_b += products_b[it]*as[idx_b[it]];
|
||||
// }
|
||||
// int index_out = as[idx_out[OutTensor::Dimension-1]];
|
||||
// for(int it = 0; it< static_cast<int>(OutTensor::Dimension); it++) {
|
||||
// index_out += products_out[it]*as[idx_out[it]];
|
||||
// }
|
||||
|
||||
// out_data[index_out] += a_data[index_a]*b_data[index_b];
|
||||
// return;
|
||||
// }
|
||||
// };
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx0, size_t ...Idx1, size_t ...Rest0, size_t ...Rest1>
|
||||
constexpr std::array<size_t,sizeof...(Rest0)> RecursiveCartesian<Index<Idx0...>, Index<Idx1...>,
|
||||
Tensor<T,Rest0...>, Tensor<T,Rest1...>,Last>::products_a;
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx0, size_t ...Idx1, size_t ...Rest0, size_t ...Rest1>
|
||||
constexpr std::array<size_t,sizeof...(Rest1)> RecursiveCartesian<Index<Idx0...>, Index<Idx1...>,
|
||||
Tensor<T,Rest0...>, Tensor<T,Rest1...>,Last>::products_b;
|
||||
|
||||
// template<typename T, size_t Last, size_t ...Idx0, size_t ...Idx1, size_t ...Rest0, size_t ...Rest1>
|
||||
// constexpr std::array<size_t,RecursiveCartesian<Index<Idx0...>, Index<Idx1...>,
|
||||
// Tensor<T,Rest0...>, Tensor<T,Rest1...>,Last>::OutTensor::Dimension> RecursiveCartesian<Index<Idx0...>, Index<Idx1...>,
|
||||
// Tensor<T,Rest0...>, Tensor<T,Rest1...>,Last>::products_out;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class Idx0, class Idx1, class Tens0, class Tens1, class Args>
|
||||
struct RecursiveCartesianDispatcher;
|
||||
|
||||
template<typename T, size_t ...Idx0, size_t ...Idx1, size_t ...Rest0, size_t ...Rest1, size_t ... Args>
|
||||
struct RecursiveCartesianDispatcher<Index<Idx0...>, Index<Idx1...>, Tensor<T,Rest0...>, Tensor<T,Rest1...>, Index<Args...> >
|
||||
{
|
||||
static constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
|
||||
static FASTOR_INLINE void Do(const T *a_data, const T *b_data, T *out_data,
|
||||
std::array<int,out_dim> &as, std::array<int,out_dim> &idx) {
|
||||
return RecursiveCartesian<Index<Idx0...>, Index<Idx1...>,
|
||||
Tensor<T,Rest0...>, Tensor<T,Rest1...>, Args...>::Do(a_data, b_data, out_data, as, idx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class T, class U, class enable=void>
|
||||
struct extractor_contract_2 {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1>
|
||||
struct extractor_contract_2<Index<Idx0...>, Index<Idx1...>,
|
||||
typename std::enable_if<no_of_unique<Idx0...,Idx1...>::value!=sizeof...(Idx0)+sizeof...(Idx1)>::type> {
|
||||
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
static
|
||||
FASTOR_INLINE
|
||||
typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::type
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
|
||||
using _contraction_impl = contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>;
|
||||
using resulting_tensor = typename _contraction_impl::type;
|
||||
// is reduction including permuted reduction
|
||||
constexpr bool _is_reduction = resulting_tensor::dimension_t::value == 0;
|
||||
|
||||
#if CONTRACT_OPT==-3
|
||||
|
||||
static_assert(!_is_reduction,"THIS VARIANT OF EINSUM CANNOT DEAL WITH REDUCTION CASES");
|
||||
|
||||
constexpr int total = 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>::value;
|
||||
|
||||
using index_generator = contract_meta_engine<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<total>::type>;
|
||||
|
||||
using OutTensor = typename index_generator::OutTensor;
|
||||
|
||||
constexpr auto& index_a = index_generator::index_a;
|
||||
constexpr auto& index_b = index_generator::index_b;
|
||||
constexpr auto& index_out = index_generator::index_out;
|
||||
|
||||
OutTensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_vectorisable<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest1...>>;
|
||||
constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
constexpr int stride = 1;
|
||||
using V = SIMDVector<T,sizeof(T)*8>;
|
||||
#endif
|
||||
|
||||
V _vec_a;
|
||||
for (int i = 0; i < total; i+=stride) {
|
||||
// out_data[index_out[i]] += a_data[index_a[i]]*b_data[index_b[i]];
|
||||
_vec_a.set(*(a_data+index_a[i]));
|
||||
V _vec_out = _vec_a*V(b_data+index_b[i]) + V(out_data+index_out[i]);
|
||||
// _vec_out.store(out_data+index_out[i]);
|
||||
_vec_out.aligned_store(out_data+index_out[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#elif CONTRACT_OPT==-2
|
||||
|
||||
static_assert(!_is_reduction,"THIS VARIANT OF EINSUM CANNOT DEAL WITH REDUCTION CASES");
|
||||
|
||||
resulting_tensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr int a_dim = sizeof...(Rest0);
|
||||
constexpr int b_dim = sizeof...(Rest1);
|
||||
|
||||
constexpr auto& idx_a = IndexFirstTensor<Index<Idx0...>,Index<Idx1...>, Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
constexpr auto& idx_b = IndexSecondTensor<Index<Idx0...>,Index<Idx1...>, Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::indices;
|
||||
constexpr auto& idx_out = IndexResultingTensor<Index<Idx0...>,Index<Idx1...>, Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::indices;
|
||||
|
||||
constexpr int total = 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>::value;
|
||||
|
||||
using maxes_out_type = 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;
|
||||
|
||||
constexpr auto& as_all = cartesian_product<maxes_out_type,typename std_ext::make_index_sequence<total>::type>::values;
|
||||
// constexpr auto as_all = cartesian_product_2<maxes_out.size(),total>(maxes_out);
|
||||
|
||||
constexpr std::array<size_t,a_dim> products_a = nprods<Index<Rest0...>,typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr std::array<size_t,b_dim> products_b = nprods<Index<Rest1...>,typename std_ext::make_index_sequence<b_dim>::type>::values;
|
||||
using Index_with_dims = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
constexpr std::array<size_t,Index_with_dims::NoIndices> products_out = nprods<Index_with_dims,
|
||||
typename std_ext::make_index_sequence<Index_with_dims::NoIndices>::type>::values;
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_vectorisable<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest1...>>;
|
||||
constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
constexpr int stride = 1;
|
||||
using V = SIMDVector<T,simd_abi::scalar>;
|
||||
#endif
|
||||
|
||||
int it;
|
||||
V _vec_a;
|
||||
for (int i = 0; i < total; i+=stride) {
|
||||
int index_a = as_all[i][idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as_all[i][idx_a[it]];
|
||||
}
|
||||
|
||||
int index_b = as_all[i][idx_b[b_dim-1]];
|
||||
for(it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as_all[i][idx_b[it]];
|
||||
}
|
||||
int index_out = as_all[i][idx_out[idx_out.size()-1]];
|
||||
for(it = 0; it< idx_out.size(); it++) {
|
||||
index_out += products_out[it]*as_all[i][idx_out[it]];
|
||||
}
|
||||
|
||||
_vec_a.set(*(a_data+index_a));
|
||||
V _vec_out = _vec_a*V(b_data+index_b) + V(out_data+index_out);
|
||||
// _vec_out.store(out_data+index_out);
|
||||
_vec_out.aligned_store(out_data+index_out);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#elif CONTRACT_OPT==-1
|
||||
|
||||
using resulting_index = typename _contraction_impl::indices;
|
||||
resulting_tensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr int a_dim = sizeof...(Rest0);
|
||||
constexpr int b_dim = sizeof...(Rest1);
|
||||
constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
|
||||
constexpr auto& idx_a = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx0...>,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
|
||||
constexpr auto& idx_b = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx1...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
constexpr auto& idx_out = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
resulting_index,resulting_tensor,
|
||||
typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::indices;
|
||||
|
||||
using nloops = loop_setter<
|
||||
Index<Idx0...,Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
constexpr auto& maxes_out = nloops::dims;
|
||||
constexpr int total = nloops::value;
|
||||
|
||||
constexpr std::array<size_t,a_dim> products_a = nprods<Index<Rest0...>,typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr std::array<size_t,b_dim> products_b = nprods<Index<Rest1...>,typename std_ext::make_index_sequence<b_dim>::type>::values;
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_vectorisable<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest1...>>;
|
||||
constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
constexpr int stride = 1;
|
||||
using V = SIMDVector<T,sizeof(T)*8>;
|
||||
#endif
|
||||
std::array<int,out_dim> as = {};
|
||||
|
||||
int it;
|
||||
V _vec_a;
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
constexpr std::array<int,out_dim> remainings = find_remaining(maxes_out, total);
|
||||
#endif
|
||||
|
||||
FASTOR_IF_CONSTEXPR(!_is_reduction) {
|
||||
|
||||
using Index_with_dims = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
constexpr std::array<size_t,resulting_tensor::Dimension> products_out = \
|
||||
nprods<Index_with_dims,typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::values;
|
||||
|
||||
for (int i = 0; i < total; i+=stride) {
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
for (int n = 0; n < out_dim; ++n) {
|
||||
as[n] = ( i / remainings[n] ) % (int)maxes_out[n];
|
||||
}
|
||||
#else
|
||||
int remaining = total;
|
||||
for (int n = 0; n < out_dim; ++n) {
|
||||
remaining /= maxes_out[n];
|
||||
as[n] = ( i / remaining ) % maxes_out[n];
|
||||
}
|
||||
#endif
|
||||
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_b = as[idx_b[b_dim-1]];
|
||||
for(it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as[idx_b[it]];
|
||||
}
|
||||
int index_out = as[idx_out[resulting_tensor::Dimension-1]];
|
||||
for(it = 0; it< static_cast<int>(resulting_tensor::Dimension); it++) {
|
||||
index_out += products_out[it]*as[idx_out[it]];
|
||||
}
|
||||
// println(index_out,index_a,index_b,"\n");
|
||||
_vec_a.set(*(a_data+index_a));
|
||||
// _vec_a.broadcast(&a_data[index_a]);
|
||||
V _vec_out = _vec_a*V(b_data+index_b) + V(out_data+index_out);
|
||||
// V _vec_out = fmadd(_vec_a,V(b_data+index_b), V(out_data+index_out));
|
||||
// _vec_out.store(out_data+index_out);
|
||||
_vec_out.aligned_store(out_data+index_out);
|
||||
}
|
||||
|
||||
// ACTUALLY MUCH SLOWER
|
||||
// constexpr auto as_all = cartesian_product_2<out_dim,total>(maxes_out);
|
||||
|
||||
// for (int i = 0; i < total; i+=stride) {
|
||||
// int index_a = as_all[i][idx_a[a_dim-1]];
|
||||
// for(it = 0; it< a_dim; it++) {
|
||||
// index_a += products_a[it]*as_all[i][idx_a[it]];
|
||||
// }
|
||||
// int index_b = as_all[i][idx_b[b_dim-1]];
|
||||
// for(it = 0; it< b_dim; it++) {
|
||||
// index_b += products_b[it]*as_all[i][idx_b[it]];
|
||||
// }
|
||||
// int index_out = as_all[i][idx_out[idx_out.size()-1]];
|
||||
// for(it = 0; it< idx_out.size(); it++) {
|
||||
// index_out += products_out[it]*as_all[i][idx_out[it]];
|
||||
// }
|
||||
|
||||
// _vec_a.set(*(a_data+index_a));
|
||||
// // V _vec_out = _vec_a*V(b_data+index_b) + V(out_data+index_out);
|
||||
// V _vec_out = fmadd(_vec_a,V(b_data+index_b), V(out_data+index_out));
|
||||
// _vec_out.aligned_store(out_data+index_out);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
for (int i = 0; i < total; i+=stride) {
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
for (int n = 0; n < out_dim; ++n) {
|
||||
as[n] = ( i / remainings[n] ) % (int)maxes_out[n];
|
||||
}
|
||||
#else
|
||||
int remaining = total;
|
||||
for (int n = 0; n < out_dim; ++n) {
|
||||
remaining /= maxes_out[n];
|
||||
as[n] = ( i / remaining ) % maxes_out[n];
|
||||
}
|
||||
#endif
|
||||
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_b = as[idx_b[b_dim-1]];
|
||||
for(it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as[idx_b[it]];
|
||||
}
|
||||
out_data[0] += a_data[index_a]*b_data[index_b];
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
#elif CONTRACT_OPT==1
|
||||
|
||||
using resulting_index = typename _contraction_impl::indices;
|
||||
resulting_tensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr int a_dim = sizeof...(Rest0);
|
||||
constexpr int b_dim = sizeof...(Rest1);
|
||||
constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
|
||||
constexpr auto& idx_a = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx0...>,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
|
||||
constexpr auto& idx_b = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx1...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
constexpr auto& idx_out = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
resulting_index,resulting_tensor,
|
||||
typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::indices;
|
||||
|
||||
using nloops = loop_setter<
|
||||
Index<Idx0...,Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
constexpr auto& maxes_out = nloops::dims;
|
||||
constexpr int total = nloops::value;
|
||||
|
||||
constexpr std::array<size_t,a_dim> products_a = nprods<Index<Rest0...>,typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr std::array<size_t,b_dim> products_b = nprods<Index<Rest1...>,typename std_ext::make_index_sequence<b_dim>::type>::values;
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_vectorisable<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest1...>>;
|
||||
constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
constexpr int stride = 1;
|
||||
using V = SIMDVector<T,sizeof(T)*8>;
|
||||
#endif
|
||||
std::array<int,out_dim> as = {};
|
||||
|
||||
int it, jt, counter = 0;
|
||||
V _vec_a;
|
||||
|
||||
FASTOR_IF_CONSTEXPR(!_is_reduction) {
|
||||
using Index_with_dims = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
constexpr std::array<size_t,resulting_tensor::Dimension> products_out = \
|
||||
nprods<Index_with_dims,typename std_ext::make_index_sequence<resulting_tensor::Dimension>::type>::values;
|
||||
|
||||
while(true)
|
||||
{
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_b = as[idx_b[b_dim-1]];
|
||||
for(it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as[idx_b[it]];
|
||||
}
|
||||
|
||||
int index_out = as[idx_out[resulting_tensor::Dimension-1]];
|
||||
for(it = 0; it< static_cast<int>(resulting_tensor::Dimension); it++) {
|
||||
index_out += products_out[it]*as[idx_out[it]];
|
||||
}
|
||||
|
||||
_vec_a.set(*(a_data+index_a));
|
||||
// V _vec_out = _vec_a*V(b_data+index_b) + V(out_data+index_out);
|
||||
V _vec_out = fmadd(_vec_a,V(b_data+index_b), V(out_data+index_out));
|
||||
_vec_out.store(out_data+index_out,false);
|
||||
// _vec_out.aligned_store(out_data+index_out);
|
||||
|
||||
counter++;
|
||||
for(jt = maxes_out.size()-1; jt>=0 ; jt--)
|
||||
{
|
||||
if (jt == maxes_out.size()-1) as[jt]+=stride;
|
||||
else as[jt] +=1;
|
||||
if(as[jt]<maxes_out[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
while(true)
|
||||
{
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_b = as[idx_b[b_dim-1]];
|
||||
for(it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as[idx_b[it]];
|
||||
}
|
||||
|
||||
out_data[0] += a_data[index_a]*b_data[index_b];
|
||||
|
||||
counter++;
|
||||
for(jt = maxes_out.size()-1; jt>=0 ; jt--)
|
||||
{
|
||||
if (jt == maxes_out.size()-1) as[jt]+=1;
|
||||
else as[jt] +=1;
|
||||
if(as[jt]<maxes_out[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
#else
|
||||
|
||||
resulting_tensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
|
||||
std::array<int,out_dim> as = {};
|
||||
std::array<int,out_dim> idx = {};
|
||||
|
||||
using nloops = loop_setter<
|
||||
Index<Idx0...,Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
using dims_type = typename nloops::dims_type;
|
||||
|
||||
RecursiveCartesianDispatcher<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,dims_type>::Do(a_data,b_data,out_data,as,idx);
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Specialisation for outer product case
|
||||
template<size_t ... Idx0, size_t ... Idx1>
|
||||
struct extractor_contract_2<Index<Idx0...>, Index<Idx1...>,
|
||||
typename std::enable_if<no_of_unique<Idx0...,Idx1...>::value==sizeof...(Idx0)+sizeof...(Idx1)>::type> {
|
||||
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
static Tensor<T,Rest0...,Rest1...>
|
||||
FASTOR_INLINE contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
Tensor<T,Rest0...,Rest1...> out;
|
||||
_dyadic<T,pack_prod<Rest0...>::value, pack_prod<Rest1...>::value>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class Index_I, class Index_J,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
FASTOR_INLINE
|
||||
auto contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b)
|
||||
-> decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) {
|
||||
return extractor_contract_2<Index_I,Index_J>::contract_impl(a,b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CONTRACTION_H
|
||||
|
||||
131
noarch/include/Fastor/tensor_algebra/contraction_single.h
Normal file
131
noarch/include/Fastor/tensor_algebra/contraction_single.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#ifndef CONTRACTION_SINGLE_H
|
||||
#define CONTRACTION_SINGLE_H
|
||||
|
||||
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
|
||||
template<class T>
|
||||
struct extractor_contract_1 {};
|
||||
|
||||
template<size_t ... Idx0>
|
||||
struct extractor_contract_1<Index<Idx0...>> {
|
||||
|
||||
template<typename T, size_t ... Rest0>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...>, Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::type
|
||||
FASTOR_INLINE contract_impl(const Tensor<T,Rest0...> &a) {
|
||||
|
||||
constexpr bool _is_reduction = is_single_reduction_v<Index<Idx0...>,Tensor<T,Rest0...>>;
|
||||
|
||||
using OutTensor = typename contraction_impl<Index<Idx0...>, Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::type;
|
||||
using OutIndices = typename contraction_impl<Index<Idx0...>, Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
|
||||
OutTensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr int a_dim = sizeof...(Rest0);
|
||||
constexpr int out_dim = no_of_unique<Idx0...>::value;
|
||||
|
||||
constexpr auto& idx_a = IndexTensors<
|
||||
Index<Idx0...>,
|
||||
Tensor<T,Rest0...>,
|
||||
Index<Idx0...>,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
|
||||
constexpr auto& idx_out = IndexTensors<
|
||||
Index<Idx0...>,
|
||||
Tensor<T,Rest0...>,
|
||||
OutIndices,OutTensor,
|
||||
typename std_ext::make_index_sequence<OutTensor::Dimension>::type>::indices;
|
||||
|
||||
using nloops = loop_setter<
|
||||
Index<Idx0...>,
|
||||
Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
constexpr auto& maxes_out = nloops::dims;
|
||||
constexpr int total = nloops::value;
|
||||
|
||||
constexpr std::array<size_t,a_dim> products_a = nprods<Index<Rest0...>,typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
int as[out_dim] = {};
|
||||
constexpr int stride = 1;
|
||||
|
||||
FASTOR_IF_CONSTEXPR (!_is_reduction) {
|
||||
|
||||
using Index_with_dims = typename put_dims_in_Index<OutTensor>::type;
|
||||
constexpr std::array<size_t,OutTensor::Dimension> products_out = \
|
||||
nprods<Index_with_dims,typename std_ext::make_index_sequence<OutTensor::Dimension>::type>::values;
|
||||
|
||||
int it, jt, counter = 0;
|
||||
while(counter < total)
|
||||
{
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_out = as[idx_out[OutTensor::Dimension-1]];
|
||||
for(it = 0; it< static_cast<int>(OutTensor::Dimension); it++) {
|
||||
index_out += products_out[it]*as[idx_out[it]];
|
||||
}
|
||||
|
||||
out_data[index_out] += a_data[index_a];
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_out[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int it, jt, counter = 0;
|
||||
while(counter < total)
|
||||
{
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
out_data[0] += a_data[index_a];
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_out[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Index_I,
|
||||
typename T, size_t ... Rest0>
|
||||
auto contraction(const Tensor<T,Rest0...> &a)
|
||||
-> decltype(extractor_contract_1<Index_I>::contract_impl(a)) {
|
||||
return extractor_contract_1<Index_I>::contract_impl(a);
|
||||
}
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // CONTRACTION_SINGLE_H
|
||||
292
noarch/include/Fastor/tensor_algebra/einsum.h
Normal file
292
noarch/include/Fastor/tensor_algebra/einsum.h
Normal file
@@ -0,0 +1,292 @@
|
||||
#ifndef EINSUM_H
|
||||
#define EINSUM_H
|
||||
|
||||
#include "Fastor/backend/backend.h"
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/meta/einsum_meta.h"
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
#include "Fastor/backend/voigt.h"
|
||||
|
||||
#include "Fastor/tensor_algebra/permutation.h"
|
||||
#include "Fastor/tensor_algebra/permute.h"
|
||||
#include "Fastor/tensor_algebra/innerproduct.h"
|
||||
#include "Fastor/tensor_algebra/outerproduct.h"
|
||||
#include "Fastor/tensor_algebra/contraction.h"
|
||||
#include "Fastor/tensor_algebra/contraction_single.h"
|
||||
#include "Fastor/tensor_algebra/strided_contraction.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
|
||||
// Single tensor
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, typename T, size_t ... Rest0>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a)
|
||||
-> decltype(extractor_contract_1<Index_I>::contract_impl(a)) {
|
||||
static_assert(einsum_index_checker<Index_I>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE INNER INSTEAD");
|
||||
return extractor_contract_1<Index_I>::contract_impl(a);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// Two tensor (by-pair)
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
// Inner product case
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_J,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
enable_if_t_<is_pair_reduction_v<Index_I,Index_J>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
Tensor<T> einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
return inner(a,b);
|
||||
}
|
||||
|
||||
// General by-pair product cases
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_J,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
typename std::enable_if<!is_pair_reduction<Index_I,Index_J>::value &&
|
||||
!internal::is_generalised_matrix_vector<Index_I,Index_J>::value &&
|
||||
!internal::is_generalised_vector_matrix<Index_I,Index_J>::value &&
|
||||
!internal::is_generalised_matrix_matrix<Index_I,Index_J>::value
|
||||
,bool>::type=0>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b)
|
||||
-> decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) {
|
||||
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE INNER INSTEAD");
|
||||
|
||||
// // Dispatch to the right routine
|
||||
// using vectorisability = is_vectorisable<Index_I,Index_J,Tensor<T,Rest1...>>;
|
||||
// // constexpr bool is_reducible = vectorisability::last_index_contracted;
|
||||
// constexpr bool is_reducible = vectorisability::is_reducible;
|
||||
// FASTOR_IF_CONSTEXPR (is_reducible) {
|
||||
// return extractor_reducible_contract<Index_I,Index_J>::contract_impl(a,b);
|
||||
// }
|
||||
// else {
|
||||
// return extractor_contract_2<Index_I,Index_J>::contract_impl(a,b);
|
||||
// }
|
||||
return extractor_contract_2<Index_I,Index_J>::contract_impl(a,b);
|
||||
}
|
||||
|
||||
|
||||
template<class Index_I, class Index_J,
|
||||
typename T, size_t ...Rest0, size_t ...Rest1,
|
||||
typename std::enable_if<
|
||||
internal::is_generalised_matrix_vector<Index_I,Index_J>::value,
|
||||
bool>::type = 0>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) //{
|
||||
-> decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) {
|
||||
|
||||
constexpr size_t which_one_is_vector = internal::is_generalised_matrix_vector<Index_I,Index_J>::which_one_is_vector;
|
||||
constexpr size_t matches_up_to = internal::is_generalised_matrix_vector<Index_I,Index_J>::matches_up_to;
|
||||
constexpr size_t rest0[sizeof...(Rest0)] = {Rest0...};
|
||||
constexpr size_t rest1[sizeof...(Rest1)] = {Rest1...};
|
||||
constexpr size_t product = which_one_is_vector == 1 ? partial_prod(rest0, matches_up_to) : partial_prod(rest1, matches_up_to);
|
||||
constexpr size_t vec_product = which_one_is_vector == 1 ? pack_prod<Rest1...>::value : pack_prod<Rest0...>::value;
|
||||
decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) out;
|
||||
which_one_is_vector == 1 ? _matmul<T,product,vec_product,1>(a.data(),b.data(),out.data()) :\
|
||||
_matmul<T,product,vec_product,1>(b.data(),a.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template<class Index_I, class Index_J,
|
||||
typename T, size_t ...Rest0, size_t ...Rest1,
|
||||
typename std::enable_if<
|
||||
internal::is_generalised_vector_matrix<Index_I,Index_J>::value,
|
||||
bool>::type = 0>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) //{
|
||||
-> decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) {
|
||||
|
||||
constexpr size_t which_one_is_vector = internal::is_generalised_vector_matrix<Index_I,Index_J>::which_one_is_vector;
|
||||
constexpr size_t matches_up_to = internal::is_generalised_vector_matrix<Index_I,Index_J>::matches_up_to;
|
||||
constexpr size_t rest0[sizeof...(Rest0)] = {Rest0...};
|
||||
constexpr size_t rest1[sizeof...(Rest1)] = {Rest1...};
|
||||
constexpr size_t product = which_one_is_vector == 1 ? partial_prod_reverse(rest0, matches_up_to) : partial_prod_reverse(rest1, matches_up_to);
|
||||
constexpr size_t vec_product = which_one_is_vector == 1 ? pack_prod<Rest1...>::value : pack_prod<Rest0...>::value;
|
||||
decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) out;
|
||||
which_one_is_vector == 1 ? _matmul<T,1,vec_product,product>(b.data(),a.data(),out.data()) :\
|
||||
_matmul<T,1,vec_product,product>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
template<class Index_I, class Index_J,
|
||||
typename T, size_t ...Rest0, size_t ...Rest1,
|
||||
typename std::enable_if<
|
||||
internal::is_generalised_matrix_matrix<Index_I,Index_J>::value,
|
||||
bool>::type = 0>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) //{
|
||||
-> decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) {
|
||||
|
||||
constexpr size_t matches_up_to = internal::is_generalised_matrix_matrix<Index_I,Index_J>::ncontracted;
|
||||
constexpr size_t rest0[sizeof...(Rest0)] = {Rest0...};
|
||||
constexpr size_t rest1[sizeof...(Rest1)] = {Rest1...};
|
||||
constexpr size_t K_product = partial_prod(rest1, matches_up_to - 1);
|
||||
constexpr size_t M = partial_prod(rest0, sizeof...(Rest0) - matches_up_to - 1);
|
||||
constexpr size_t N = partial_prod(rest1, sizeof...(Rest1) - 1, matches_up_to);
|
||||
|
||||
decltype(extractor_contract_2<Index_I,Index_J>::contract_impl(a,b)) out;
|
||||
_matmul<T,M,K_product,N>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// matmul dispatcher for 2nd order tensors (matrix-matrix)
|
||||
// also includes matrix-vector and vector-matrix when vector is of size
|
||||
// nx1 or 1xn
|
||||
template<class Ind0, class Ind1,
|
||||
typename T, size_t I, size_t J, size_t K,
|
||||
typename std::enable_if<Ind0::Size==2 && Ind1::Size==2 &&
|
||||
Ind0::values[1] == Ind1::values[0] &&
|
||||
Ind0::values[1] != Ind0::values[0] &&
|
||||
Ind0::values[1] != Ind1::values[1] &&
|
||||
Ind0::values[0] != Ind1::values[1]
|
||||
,bool>::type = 0>
|
||||
FASTOR_INLINE Tensor<T,I,K>
|
||||
einsum(const Tensor<T,I,J> &a, const Tensor<T,J,K> &b) {
|
||||
Tensor<T,I,K> out;
|
||||
_matmul<T,I,J,K>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// matmul dispatcher for matrix-vector
|
||||
template<class Ind0, class Ind1,
|
||||
typename T, size_t I, size_t J,
|
||||
typename std::enable_if<Ind0::Size==2 && Ind1::Size==1 &&
|
||||
Ind0::values[1] == Ind1::values[0] &&
|
||||
Ind0::values[0] != Ind1::values[0]
|
||||
,bool>::type = 0>
|
||||
FASTOR_INLINE Tensor<T,I>
|
||||
einsum(const Tensor<T,I,J> &a, const Tensor<T,J> &b) {
|
||||
Tensor<T,I> out;
|
||||
_matmul<T,I,J,1>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
// matmul dispatcher for matrix-vector
|
||||
template<class Ind0, class Ind1,
|
||||
typename T, size_t I, size_t J,
|
||||
typename std::enable_if<Ind0::Size==2 && Ind1::Size==1 &&
|
||||
Ind0::values[0] == Ind1::values[0] &&
|
||||
Ind0::values[1] != Ind1::values[0],bool>::type = 0>
|
||||
FASTOR_INLINE Tensor<T,J>
|
||||
einsum(const Tensor<T,I,J> &a, const Tensor<T,I> &b) {
|
||||
Tensor<T,J> out;
|
||||
_matmul<T,1,I,J>(b.data(),a.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// matmul dispatcher for vector-matrix
|
||||
template<class Ind0, class Ind1,
|
||||
typename T, size_t I, size_t J,
|
||||
typename std::enable_if<Ind1::Size==2 && Ind0::Size==1 &&
|
||||
Ind1::values[0] == Ind0::values[0] &&
|
||||
Ind1::values[1] != Ind0::values[0],bool>::type = 0>
|
||||
FASTOR_INLINE Tensor<T,J>
|
||||
einsum(const Tensor<T,I> &a, const Tensor<T,I,J> &b) {
|
||||
Tensor<T,J> out;
|
||||
_matmul<T,1,I,J>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// matmul dispatcher for vector-matrix
|
||||
template<class Ind0, class Ind1,
|
||||
typename T, size_t I, size_t J,
|
||||
typename std::enable_if<Ind1::Size==2 && Ind0::Size==1 &&
|
||||
Ind1::values[1] == Ind0::values[0] &&
|
||||
Ind1::values[0] != Ind0::values[0],bool>::type = 0>
|
||||
FASTOR_INLINE Tensor<T,I>
|
||||
einsum(const Tensor<T,J> &a, const Tensor<T,I,J> &b) {
|
||||
Tensor<T,I> out;
|
||||
_matmul<T,I,J,1>(b.data(),a.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef FASTOR_AVX_IMPL
|
||||
|
||||
// Specific overloads
|
||||
|
||||
// With Voigt conversion
|
||||
template<class Ind0, class Ind1, int Convert,
|
||||
typename T, size_t I, size_t J, size_t K, size_t L,
|
||||
typename std::enable_if<(std::is_same<T,float>::value || std::is_same<T,double>::value) &&
|
||||
I==J && J==K && K==L && (I==2 || I==3) &&
|
||||
Ind0::NoIndices==2 && Ind1::NoIndices==2 && Convert==FASTOR_Voigt,bool>::type = 0>
|
||||
FASTOR_INLINE typename VoigtType<T,I,J,K,L>::return_type
|
||||
einsum(const Tensor<T,I,J> & a, const Tensor<T,K,L> &b) {
|
||||
|
||||
using OutTensor = typename VoigtType<T,I,J,K,L>::return_type;
|
||||
OutTensor out;
|
||||
|
||||
constexpr int i = static_cast<int>(Ind0::values[0]);
|
||||
constexpr int j = static_cast<int>(Ind0::values[1]);
|
||||
constexpr int k = static_cast<int>(Ind1::values[0]);
|
||||
constexpr int l = static_cast<int>(Ind1::values[1]);
|
||||
|
||||
constexpr bool is_dyadic = i<j && j<k && k<l;
|
||||
constexpr bool is_cyclic = (i<j && i<k && i<l) && j>k && j<l;
|
||||
static_assert(is_dyadic || is_cyclic, "INCORRECT INPUT FOR EINSUM FUNCTION");
|
||||
|
||||
if (is_dyadic) {
|
||||
_outer<T,I,J,K,L>(a.data(),b.data(),out.data());
|
||||
}
|
||||
|
||||
if (is_cyclic) {
|
||||
_cyclic<T,I,J,K,L>(a.data(),b.data(),out.data());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template<class Ind0, class Ind1, int Convert,
|
||||
typename T, size_t I, size_t J, size_t K, size_t L,
|
||||
typename std::enable_if<(!std::is_same<T,float>::value && !std::is_same<T,double>::value) &&
|
||||
I==J && J==K && K==L && (I==2 || I==3) &&
|
||||
Ind0::Size==2 && Ind1::Size==2 && Convert==FASTOR_Voigt,bool>::type = 0>
|
||||
FASTOR_INLINE typename VoigtType<T,I,J,K,L>::return_type
|
||||
einsum(const Tensor<T,I,J> & a, const Tensor<T,K,L> &b) {
|
||||
|
||||
constexpr int i = static_cast<int>(Ind0::values[0]);
|
||||
constexpr int j = static_cast<int>(Ind0::values[1]);
|
||||
constexpr int k = static_cast<int>(Ind1::values[0]);
|
||||
constexpr int l = static_cast<int>(Ind1::values[1]);
|
||||
|
||||
constexpr bool is_dyadic = i<j && j<k && k<l;
|
||||
constexpr bool is_cyclic = (i<j && i<k && i<l) && j>k && j<l;
|
||||
static_assert(is_dyadic || is_cyclic, "INCORRECT INPUT FOR EINSUM FUNCTION");
|
||||
|
||||
using Ind = typename concat_<Ind0,Ind1>::type;
|
||||
|
||||
if (is_dyadic) {
|
||||
auto out = contraction<Ind0,Ind1>(a,b);
|
||||
return voigt(out);
|
||||
}
|
||||
|
||||
if (is_cyclic) {
|
||||
auto out = permutation<Ind>(contraction<Ind0,Ind1>(a,b));
|
||||
return voigt(out);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // EINSUM_H
|
||||
332
noarch/include/Fastor/tensor_algebra/einsum_explicit.h
Normal file
332
noarch/include/Fastor/tensor_algebra/einsum_explicit.h
Normal file
@@ -0,0 +1,332 @@
|
||||
#ifndef EXPLICIT_EINSUM_H
|
||||
#define EXPLICIT_EINSUM_H
|
||||
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
#include "Fastor/meta/opmin_meta.h"
|
||||
#include "Fastor/tensor_algebra/permutation.h"
|
||||
#include "Fastor/tensor_algebra/permute.h"
|
||||
#include "Fastor/tensor_algebra/einsum.h"
|
||||
#include "Fastor/tensor_algebra/network_einsum.h"
|
||||
#include "Fastor/tensor_algebra/abstract_contraction.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
|
||||
// Single tensor
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_O,
|
||||
typename T, size_t ... Rest0>
|
||||
FASTOR_INLINE
|
||||
typename permute_helper<internal::permute_mapped_index_t<
|
||||
typename einsum_helper<Index_I,Tensor<T,Rest0...>>::resulting_index, typename Index_O::parent_type>,
|
||||
typename einsum_helper<Index_I,Tensor<T,Rest0...>>::resulting_tensor>::resulting_tensor
|
||||
einsum(const Tensor<T,Rest0...> &a) {
|
||||
using _einsum_helper = einsum_helper<Index_I,Tensor<T,Rest0...>>;
|
||||
using resulting_index_einsum = typename _einsum_helper::resulting_index;
|
||||
using resulting_tensor_einsum = typename _einsum_helper::resulting_tensor;
|
||||
auto res = einsum<Index_I>(a);
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, resulting_tensor_einsum>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// Two tensor (by-pair)
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_J, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
FASTOR_INLINE
|
||||
typename permute_helper<internal::permute_mapped_index_t<
|
||||
typename einsum_helper<Index_I,Index_J,Tensor<T,Rest0...>,Tensor<T,Rest1...>>::resulting_index, typename Index_O::parent_type>,
|
||||
typename einsum_helper<Index_I,Index_J,Tensor<T,Rest0...>,Tensor<T,Rest1...>>::resulting_tensor>::resulting_tensor
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
using _einsum_helper = einsum_helper<Index_I,Index_J,Tensor<T,Rest0...>,Tensor<T,Rest1...>>;
|
||||
using resulting_index_einsum = typename _einsum_helper::resulting_index;
|
||||
using resulting_tensor_einsum = typename _einsum_helper::resulting_tensor;
|
||||
auto res = einsum<Index_I,Index_J>(a,b);
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, resulting_tensor_einsum>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// 3 tensor network
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2>
|
||||
FASTOR_INLINE
|
||||
typename permute_helper<
|
||||
internal::permute_mapped_index_t<
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>>::resulting_index,
|
||||
typename Index_O::parent_type
|
||||
>,
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>>::resulting_tensor>::resulting_tensor
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c) {
|
||||
using _einsum_helper = einsum_helper<Index_I,Index_J,Index_K,Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>>;
|
||||
using resulting_index_einsum = typename _einsum_helper::resulting_index;
|
||||
using resulting_tensor_einsum = typename _einsum_helper::resulting_tensor;
|
||||
auto res = einsum<Index_I,Index_J,Index_K>(a,b,c);
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, resulting_tensor_einsum>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// 4 tensor network
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3>
|
||||
FASTOR_INLINE
|
||||
typename permute_helper<
|
||||
internal::permute_mapped_index_t<
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Index_L,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>>::resulting_index,
|
||||
typename Index_O::parent_type
|
||||
>,
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Index_L,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>>::resulting_tensor>::resulting_tensor
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d) {
|
||||
using _einsum_helper = einsum_helper<Index_I,Index_J,Index_K,Index_L,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>>;
|
||||
using resulting_index_einsum = typename _einsum_helper::resulting_index;
|
||||
using resulting_tensor_einsum = typename _einsum_helper::resulting_tensor;
|
||||
auto res = einsum<Index_I,Index_J,Index_K,Index_L>(a,b,c,d);
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, resulting_tensor_einsum>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// 5 tensor network
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4>
|
||||
FASTOR_INLINE
|
||||
typename permute_helper<
|
||||
internal::permute_mapped_index_t<
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>>::resulting_index,
|
||||
typename Index_O::parent_type
|
||||
>,
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>>::resulting_tensor
|
||||
>::resulting_tensor
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c,
|
||||
const Tensor<T,Rest3...> &d, const Tensor<T,Rest4...> &e) {
|
||||
using _einsum_helper = einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>>;
|
||||
using resulting_index_einsum = typename _einsum_helper::resulting_index;
|
||||
using resulting_tensor_einsum = typename _einsum_helper::resulting_tensor;
|
||||
auto res = einsum<Index_I,Index_J,Index_K,Index_L,Index_M>(a,b,c,d,e);
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, resulting_tensor_einsum>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// 6 tensor network
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5>
|
||||
FASTOR_INLINE
|
||||
typename permute_helper<
|
||||
internal::permute_mapped_index_t<
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>>::resulting_index,
|
||||
typename Index_O::parent_type
|
||||
>,
|
||||
typename einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>>::resulting_tensor
|
||||
>::resulting_tensor
|
||||
einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c,
|
||||
const Tensor<T,Rest3...> &d, const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f) {
|
||||
using _einsum_helper = einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>,Tensor<T,Rest3...>,Tensor<T,Rest4...>,Tensor<T,Rest5...>>;
|
||||
using resulting_index_einsum = typename _einsum_helper::resulting_index;
|
||||
using resulting_tensor_einsum = typename _einsum_helper::resulting_tensor;
|
||||
auto res = einsum<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>(a,b,c,d,e,f);
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, resulting_tensor_einsum>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
// network einsum for expressions
|
||||
//-----------------------------------------------------------------------------------------------------------------------//
|
||||
// single expression explicit einsum
|
||||
template<class Index_I, class Index_O,
|
||||
typename AbstractTensorType0, enable_if_t_<!is_tensor_v<AbstractTensorType0>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensorType0& a)
|
||||
{
|
||||
decltype(auto) tmp = evaluate(a);
|
||||
auto res = einsum<Index_I>(tmp);
|
||||
using resulting_index_einsum = typename einsum_helper<Index_I,decltype(tmp)>::resulting_index;
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, decltype(res)>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
|
||||
// pair expression explicit einsum
|
||||
template<class Index_I, class Index_J, class Index_O,
|
||||
typename Derived0, typename Derived1, size_t DIM0, size_t DIM1>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensor<Derived0,DIM0>& a, const AbstractTensor<Derived1,DIM1>& b)
|
||||
{
|
||||
auto res = einsum<Index_I,Index_J>(a.self(),b.self());
|
||||
using ttype0 = typename Derived0::resulting_type;
|
||||
using ttype1 = typename Derived1::resulting_type;
|
||||
using resulting_index_einsum = typename einsum_helper<Index_I,Index_J,ttype0,ttype1>::resulting_index;
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, decltype(res)>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
|
||||
// 3 tensor network expression explicit einsum
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_O,
|
||||
typename Derived0, typename Derived1, typename Derived2, size_t DIM0, size_t DIM1, size_t DIM2>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensor<Derived0,DIM0>& a, const AbstractTensor<Derived1,DIM1>& b, const AbstractTensor<Derived2,DIM2>& c)
|
||||
{
|
||||
auto res = einsum<Index_I,Index_J,Index_K>(a.self(),b.self(),c.self());
|
||||
using ttype0 = typename Derived0::resulting_type;
|
||||
using ttype1 = typename Derived1::resulting_type;
|
||||
using ttype2 = typename Derived2::resulting_type;
|
||||
using resulting_index_einsum = typename einsum_helper<Index_I,Index_J,Index_K,ttype0,ttype1,ttype2>::resulting_index;
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, decltype(res)>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
|
||||
// 4 tensor network expression explicit einsum
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_O,
|
||||
typename Derived0, typename Derived1, typename Derived2, typename Derived3,
|
||||
size_t DIM0, size_t DIM1, size_t DIM2, size_t DIM3>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(
|
||||
const AbstractTensor<Derived0,DIM0>& a, const AbstractTensor<Derived1,DIM1>& b,
|
||||
const AbstractTensor<Derived2,DIM2>& c, const AbstractTensor<Derived3,DIM3>& d)
|
||||
{
|
||||
auto res = einsum<Index_I,Index_J,Index_K,Index_L>(a.self(),b.self(),c.self(),d.self());
|
||||
using ttype0 = typename Derived0::resulting_type;
|
||||
using ttype1 = typename Derived1::resulting_type;
|
||||
using ttype2 = typename Derived2::resulting_type;
|
||||
using ttype3 = typename Derived3::resulting_type;
|
||||
using resulting_index_einsum = typename einsum_helper<Index_I,Index_J,Index_K,Index_L,ttype0,ttype1,ttype2,ttype3>::resulting_index;
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, decltype(res)>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
|
||||
// 5 tensor network expression explicit einsum
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_O,
|
||||
typename Derived0, typename Derived1, typename Derived2, typename Derived3, typename Derived4,
|
||||
size_t DIM0, size_t DIM1, size_t DIM2, size_t DIM3, size_t DIM4>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(
|
||||
const AbstractTensor<Derived0,DIM0>& a, const AbstractTensor<Derived1,DIM1>& b,
|
||||
const AbstractTensor<Derived2,DIM2>& c, const AbstractTensor<Derived3,DIM3>& d,
|
||||
const AbstractTensor<Derived4,DIM4>& e)
|
||||
{
|
||||
auto res = einsum<Index_I,Index_J,Index_K,Index_L,Index_M>(a.self(),b.self(),c.self(),d.self(),e.self());
|
||||
using ttype0 = typename Derived0::resulting_type;
|
||||
using ttype1 = typename Derived1::resulting_type;
|
||||
using ttype2 = typename Derived2::resulting_type;
|
||||
using ttype3 = typename Derived3::resulting_type;
|
||||
using ttype4 = typename Derived4::resulting_type;
|
||||
using resulting_index_einsum = typename einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,
|
||||
ttype0,ttype1,ttype2,ttype3,ttype4>::resulting_index;
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, decltype(res)>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
|
||||
// 6 tensor network expression explicit einsum
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N, class Index_O,
|
||||
typename Derived0, typename Derived1, typename Derived2, typename Derived3, typename Derived4, typename Derived5,
|
||||
size_t DIM0, size_t DIM1, size_t DIM2, size_t DIM3, size_t DIM4, size_t DIM5>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(
|
||||
const AbstractTensor<Derived0,DIM0>& a, const AbstractTensor<Derived1,DIM1>& b,
|
||||
const AbstractTensor<Derived2,DIM2>& c, const AbstractTensor<Derived3,DIM3>& d,
|
||||
const AbstractTensor<Derived4,DIM4>& e, const AbstractTensor<Derived5,DIM5>& f)
|
||||
{
|
||||
auto res = einsum<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>(a.self(),b.self(),c.self(),d.self(),e.self(),f.self());
|
||||
using ttype0 = typename Derived0::resulting_type;
|
||||
using ttype1 = typename Derived1::resulting_type;
|
||||
using ttype2 = typename Derived2::resulting_type;
|
||||
using ttype3 = typename Derived3::resulting_type;
|
||||
using ttype4 = typename Derived4::resulting_type;
|
||||
using ttype5 = typename Derived5::resulting_type;
|
||||
using resulting_index_einsum = typename einsum_helper<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,
|
||||
ttype0,ttype1,ttype2,ttype3,ttype4,ttype5>::resulting_index;
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<resulting_index_einsum,typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, decltype(res)>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
|
||||
#if !defined(FASTOR_MSVC)
|
||||
template<class Index_I, class ... Index_Ks, class Index_O,
|
||||
typename AbstractTensorType0, typename ... AbstractTensorTypes,
|
||||
enable_if_t_<sizeof...(AbstractTensorTypes) >= 6, bool > = false>
|
||||
FASTOR_INLINE
|
||||
decltype(auto)
|
||||
einsum(const AbstractTensorType0& a, const AbstractTensorTypes& ... rest)
|
||||
{
|
||||
auto res = internal::unpack_einsum_tuple<Index_I,Index_Ks...>::apply(internal::contraction_chain_evaluate(a,rest...));
|
||||
auto res_idx = internal::unpack_einsum_helper_tuple<Index_I,Index_Ks...>::apply(internal::contraction_chain_evaluate(a,rest...));
|
||||
|
||||
using mapped_index = internal::permute_mapped_index_t<decltype(res_idx),typename Index_O::parent_type>;
|
||||
constexpr bool requires_permutation = requires_permute_v<mapped_index, decltype(res)>;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return res;
|
||||
return permute<mapped_index>(res);
|
||||
}
|
||||
#endif
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif // CXX 2017
|
||||
|
||||
} // end of namespace
|
||||
|
||||
|
||||
#endif // EXPLICIT_EINSUM_H
|
||||
66
noarch/include/Fastor/tensor_algebra/indicial.h
Normal file
66
noarch/include/Fastor/tensor_algebra/indicial.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef INDICIAL_H
|
||||
#define INDICIAL_H
|
||||
|
||||
#include "Fastor/config/config.h"
|
||||
#include "Fastor/meta/einsum_meta.h"
|
||||
#include <array>
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------//
|
||||
template <FASTOR_INDEX ... All>
|
||||
struct Index {
|
||||
static constexpr FASTOR_INDEX Size = sizeof...(All);
|
||||
static constexpr std::array<FASTOR_INDEX,sizeof...(All)> values = {All...};
|
||||
};
|
||||
|
||||
template<FASTOR_INDEX ... All>
|
||||
constexpr FASTOR_INDEX Index<All...>::Size;
|
||||
|
||||
template<FASTOR_INDEX ... All>
|
||||
constexpr std::array<FASTOR_INDEX,sizeof...(All)> Index<All...>::values;
|
||||
|
||||
namespace internal {
|
||||
template<FASTOR_INDEX N, class seq>
|
||||
struct make_index_impl;
|
||||
template<FASTOR_INDEX N, size_t ... ss>
|
||||
struct make_index_impl<N,std_ext::index_sequence<ss...>> {
|
||||
using type = Index<ss...>;
|
||||
};
|
||||
} // internal
|
||||
|
||||
template<FASTOR_INDEX N>
|
||||
struct make_index {
|
||||
using type = typename internal::make_index_impl<N,typename std_ext::make_index_sequence<N>::type>::type;
|
||||
};
|
||||
|
||||
template<FASTOR_INDEX N>
|
||||
using make_index_t = typename make_index<N>::type;
|
||||
|
||||
|
||||
template<FASTOR_INDEX ... All>
|
||||
struct OIndex : public Index<All...> {
|
||||
static constexpr FASTOR_INDEX Size = sizeof...(All);
|
||||
using parent_type = Index<All...>;
|
||||
};
|
||||
|
||||
template<FASTOR_INDEX ... All>
|
||||
constexpr FASTOR_INDEX OIndex<All...>::Size;
|
||||
|
||||
template<class Idx>
|
||||
struct to_oindex;
|
||||
template<FASTOR_INDEX ... All>
|
||||
struct to_oindex<Index<All...>>
|
||||
{
|
||||
using type = OIndex<All...>;
|
||||
};
|
||||
|
||||
template<class Idx>
|
||||
using to_oindex_t = typename to_oindex<Idx>::type;
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------//
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // INDICIAL_H
|
||||
|
||||
149
noarch/include/Fastor/tensor_algebra/innerproduct.h
Normal file
149
noarch/include/Fastor/tensor_algebra/innerproduct.h
Normal file
@@ -0,0 +1,149 @@
|
||||
#ifndef INNERPRODUCT_H
|
||||
#define INNERPRODUCT_H
|
||||
|
||||
#include "Fastor/backend/doublecontract.h"
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor/TensorTraits.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
|
||||
// Inner products - reduction to a scalar
|
||||
//----------------------------------------------------------------------------------------------
|
||||
template<typename T, size_t ... Rest>
|
||||
T inner(const Tensor<T,Rest...> &a) {
|
||||
//! Reduces a multi-dimensional tensor to a scalar
|
||||
//!
|
||||
//! If a is scalar/Tensor<T> returns the value itself
|
||||
//! If a is a vector Tensor<T,N> returns the sum of values
|
||||
//! If a is a second order tensor Tensor<T,N,N> returns the trace
|
||||
//! If a is a third order tensor Tensor<T,N,N,N> returns a_iii
|
||||
//! ...
|
||||
//!
|
||||
//! The size of the tensor in all dimensions should be equal (uniform)
|
||||
|
||||
static_assert(no_of_unique<Rest...>::value<=1, "REDUCTION IS ONLY POSSIBLE ON UNIFORM TENSORS");
|
||||
constexpr int ndim = sizeof...(Rest);
|
||||
|
||||
T *a_data = a.data();
|
||||
if (ndim==0) {
|
||||
return a_data[0];
|
||||
}
|
||||
else if (ndim==1) {
|
||||
return a.sum();
|
||||
}
|
||||
else {
|
||||
constexpr std::array<size_t,ndim> products = nprods<Index<Rest...>,
|
||||
typename std_ext::make_index_sequence<ndim>::type>::values;
|
||||
|
||||
T reductor = static_cast<T>(0);
|
||||
for (size_t i=0; i<a.dimension(0); ++i) {
|
||||
size_t index_a = i;
|
||||
for(size_t it = 0; it< ndim; it++) {
|
||||
index_a += products[it]*i;
|
||||
}
|
||||
reductor += a_data[index_a];
|
||||
}
|
||||
return reductor;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t ... Rest>
|
||||
FASTOR_INLINE T inner(const Tensor<T,Rest...> &a, const Tensor<T,Rest...> &b) {
|
||||
//! Reduction of a tensor pair to a scalar, for instance A_ijklm * B_ijklm
|
||||
//! If a and b are scalars/vectors, returns dot product
|
||||
//! If a and b are matrices, returns double contraction
|
||||
//! For third order tensors returns a_ijk*b_ijk
|
||||
//! ...
|
||||
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
|
||||
constexpr size_t ndim = sizeof...(Rest);
|
||||
FASTOR_IF_CONSTEXPR (ndim>0) {
|
||||
return _doublecontract<T,pack_prod<Rest...>::value,1>(a_data,b_data);
|
||||
}
|
||||
else {
|
||||
return (*a_data)*(*b_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Expressions
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
template<typename Derived0, size_t DIM0>
|
||||
FASTOR_INLINE
|
||||
typename Derived0::scalar_type
|
||||
inner(const AbstractTensor<Derived0,DIM0> &a) {
|
||||
using result_type = typename Derived0::result_type;
|
||||
return inner(result_type(a));
|
||||
}
|
||||
|
||||
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
typename Derived0::scalar_type
|
||||
inner(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
|
||||
using lhs_type = typename Derived0::result_type;
|
||||
using rhs_type = typename Derived1::result_type;
|
||||
return inner(lhs_type(a),rhs_type(b));
|
||||
}
|
||||
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && is_tensor_v<Derived1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
typename Derived0::scalar_type
|
||||
inner(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
|
||||
using lhs_type = typename Derived0::result_type;
|
||||
return inner(lhs_type(a),b.self());
|
||||
}
|
||||
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
|
||||
enable_if_t_<is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
typename Derived0::scalar_type
|
||||
inner(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
|
||||
using rhs_type = typename Derived1::result_type;
|
||||
return inner(a.self(),rhs_type(b));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// multiple chained expressions - network innerproduct
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#if FASTOR_CXX_VERSION >= 2014
|
||||
namespace internal {
|
||||
template<typename AbstractTensorType0>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
innerproduct_chain_expression(const AbstractTensorType0& a)
|
||||
-> decltype(a.self())
|
||||
{
|
||||
return a.self();
|
||||
}
|
||||
template<typename AbstractTensorType0, typename AbstractTensorType1, typename ... AbstractTensorTypes>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
innerproduct_chain_expression(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest)
|
||||
// -> decltype(innerproduct_chain_expression(evaluate(a*b),rest...))
|
||||
{
|
||||
const auto src = evaluate(a*b);
|
||||
return innerproduct_chain_expression(src,rest...);
|
||||
}
|
||||
} // internal
|
||||
|
||||
template<typename AbstractTensorType0, typename AbstractTensorType1, typename ... AbstractTensorTypes,
|
||||
enable_if_t_<sizeof...(AbstractTensorTypes) >= 1,bool> = false>
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
inner(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest)
|
||||
-> decltype(internal::innerproduct_chain_expression(a,b,rest...).sum())
|
||||
{
|
||||
return internal::innerproduct_chain_expression(a,b,rest...).sum();
|
||||
}
|
||||
#endif
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // INNERPRODUCT_H
|
||||
|
||||
448
noarch/include/Fastor/tensor_algebra/network_contraction.h
Normal file
448
noarch/include/Fastor/tensor_algebra/network_contraction.h
Normal file
@@ -0,0 +1,448 @@
|
||||
#ifndef NETWORK_CONTRACTION_H
|
||||
#define NETWORK_CONTRACTION_H
|
||||
|
||||
#ifndef FASTOR_DONT_PERFORM_OP_MIN
|
||||
|
||||
#include "Fastor/tensor_algebra/einsum.h"
|
||||
#include "Fastor/meta/opmin_meta.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
|
||||
// Three tensor network
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
template<class T, class U, class V>
|
||||
struct extractor_contract_3 {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1, size_t ... Idx2>
|
||||
struct extractor_contract_3<Index<Idx0...>, Index<Idx1...>, Index<Idx2...> > {
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2>
|
||||
static
|
||||
typename contraction_impl<
|
||||
Index<Idx0...,Idx1...,Idx2...>, Tensor<T,Rest0...,Rest1...,Rest2...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)+sizeof...(Rest2)>::type>::type
|
||||
FASTOR_INLINE
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c) {
|
||||
|
||||
using cost_model = triplet_flop_cost<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>,Tensor<T,Rest2...>>;
|
||||
|
||||
using resulting_index_0 = typename cost_model::resulting_index_0;
|
||||
using resulting_index_1 = typename cost_model::resulting_index_1;
|
||||
using resulting_index_2 = typename cost_model::resulting_index_2;
|
||||
|
||||
#ifndef FASTOR_KEEP_DP_FIXED
|
||||
|
||||
constexpr int which_variant = cost_model::which_variant;
|
||||
|
||||
FASTOR_IF_CONSTEXPR (which_variant == 0) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>>(a,b);
|
||||
return einsum<resulting_index_0,Index<Idx2...>>(tmp,c);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant == 1) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx2...>>(a,c);
|
||||
return einsum<Index<Idx1...>,resulting_index_1>(b,tmp);
|
||||
}
|
||||
else {
|
||||
auto tmp = einsum<Index<Idx1...>,Index<Idx2...>>(b,c);
|
||||
return einsum<Index<Idx0...>,resulting_index_2>(a,tmp);
|
||||
}
|
||||
|
||||
#else
|
||||
// for benchmarks
|
||||
auto tmp = einsum<Index<Idx1...>,Index<Idx2...>>(b,c);
|
||||
return einsum<Index<Idx0...>,resulting_index_2>(a,tmp);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<class Index_I, class Index_J, class Index_K,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2>
|
||||
FASTOR_INLINE
|
||||
auto contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c)
|
||||
-> decltype(extractor_contract_3<Index_I,Index_J,Index_K>::contract_impl(a,b,c)) {
|
||||
return extractor_contract_3<Index_I,Index_J,Index_K>::contract_impl(a,b,c);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Four tensor network
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
template<class T, class U, class V, class W>
|
||||
struct extractor_contract_4 {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1, size_t ... Idx2, size_t ... Idx3>
|
||||
struct extractor_contract_4<Index<Idx0...>, Index<Idx1...>, Index<Idx2...>, Index<Idx3...> > {
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3>
|
||||
static
|
||||
typename contraction_impl<
|
||||
Index<Idx0...,Idx1...,Idx2...,Idx3...>, Tensor<T,Rest0...,Rest1...,Rest2...,Rest3...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)+sizeof...(Rest2)+sizeof...(Rest3)>::type>::type
|
||||
FASTOR_INLINE
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d) {
|
||||
|
||||
#ifndef FASTOR_KEEP_DP_FIXED
|
||||
|
||||
using cost_model = 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_index_0 = typename cost_model::resulting_index_0;
|
||||
using resulting_index_1 = typename cost_model::resulting_index_1;
|
||||
using resulting_index_2 = typename cost_model::resulting_index_2;
|
||||
using resulting_index_3 = typename cost_model::resulting_index_3;
|
||||
|
||||
constexpr int which_variant = cost_model::which_variant;
|
||||
|
||||
FASTOR_IF_CONSTEXPR (which_variant==0) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>>(a,b,c);
|
||||
return einsum<resulting_index_0,Index<Idx3...>>(tmp,d);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==1) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx3...>>(a,b,d);
|
||||
return einsum<Index<Idx2...>,resulting_index_1>(c,tmp);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==2) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx2...>,Index<Idx3...>>(a,c,d);
|
||||
return einsum<Index<Idx1...>,resulting_index_2>(b,tmp);
|
||||
}
|
||||
else {
|
||||
auto tmp = einsum<Index<Idx1...>,Index<Idx2...>,Index<Idx3...>>(b,c,d);
|
||||
return einsum<Index<Idx0...>,resulting_index_3>(a,tmp);
|
||||
}
|
||||
|
||||
#else
|
||||
// for benchmarks
|
||||
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;
|
||||
|
||||
using resulting_tensor_1 = typename get_resuling_tensor<Index<Idx2...>,Index<Idx3...>,
|
||||
Tensor<T,Rest2...>,Tensor<T,Rest3...>>::type;
|
||||
using resulting_index_1 = typename get_resuling_index<Index<Idx2...>,Index<Idx3...>,
|
||||
Tensor<T,Rest2...>,Tensor<T,Rest3...>>::type;
|
||||
|
||||
resulting_tensor_0 tmp0 = einsum<Index<Idx0...>,Index<Idx1...>>(a,b);
|
||||
resulting_tensor_1 tmp1 = einsum<Index<Idx2...>,Index<Idx3...>>(c,d);
|
||||
auto res = einsum<resulting_index_0,resulting_index_1>(tmp0,tmp1);
|
||||
|
||||
return res;
|
||||
#endif
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3>
|
||||
FASTOR_INLINE
|
||||
auto contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d)
|
||||
-> decltype(extractor_contract_4<Index_I,Index_J,Index_K,Index_L>::contract_impl(a,b,c,d)) {
|
||||
return extractor_contract_4<Index_I,Index_J,Index_K,Index_L>::contract_impl(a,b,c,d);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
// Five tensor network
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
template<class T, class U, class V, class W, class X>
|
||||
struct extractor_contract_5 {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1, size_t ... Idx2, size_t ... Idx3, size_t ... Idx4>
|
||||
struct extractor_contract_5<Index<Idx0...>, Index<Idx1...>, Index<Idx2...>, Index<Idx3...>, Index<Idx4...> > {
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...,Idx1...,Idx2...,Idx3...,Idx4...>, Tensor<T,Rest0...,Rest1...,Rest2...,Rest3...,Rest4...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)+
|
||||
sizeof...(Rest2)+sizeof...(Rest3)+sizeof...(Rest4)>::type>::type
|
||||
FASTOR_INLINE
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e) {
|
||||
|
||||
using cost_model = 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_index_0 = typename cost_model::resulting_index_0;
|
||||
using resulting_index_1 = typename cost_model::resulting_index_1;
|
||||
using resulting_index_2 = typename cost_model::resulting_index_2;
|
||||
using resulting_index_3 = typename cost_model::resulting_index_3;
|
||||
using resulting_index_4 = typename cost_model::resulting_index_4;
|
||||
|
||||
constexpr int which_variant = cost_model::which_variant;
|
||||
|
||||
FASTOR_IF_CONSTEXPR (which_variant==0) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>>(a,b,c,d);
|
||||
return einsum<resulting_index_0,Index<Idx4...>>(tmp,e);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==1) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx4...>>(a,b,c,e);
|
||||
return einsum<Index<Idx3...>,resulting_index_1>(d,tmp);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==2) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx3...>,Index<Idx4...>>(a,b,d,e);
|
||||
return einsum<Index<Idx2...>,resulting_index_2>(c,tmp);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==3) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>>(a,c,d,e);
|
||||
return einsum<Index<Idx1...>,resulting_index_3>(b,tmp);
|
||||
}
|
||||
else {
|
||||
auto tmp = einsum<Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>>(b,c,d,e);
|
||||
return einsum<Index<Idx0...>,resulting_index_4>(a,tmp);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4>
|
||||
FASTOR_INLINE
|
||||
auto contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e)
|
||||
-> decltype(extractor_contract_5<Index_I,Index_J,Index_K,Index_L,Index_M>::contract_impl(a,b,c,d,e)) {
|
||||
return extractor_contract_5<Index_I,Index_J,Index_K,Index_L,Index_M>::contract_impl(a,b,c,d,e);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
// Six tensor network
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
template<class T, class U, class V, class W, class X, class Y>
|
||||
struct extractor_contract_6 {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1, size_t ... Idx2, size_t ... Idx3, size_t ... Idx4, size_t ... Idx5>
|
||||
struct extractor_contract_6<Index<Idx0...>, Index<Idx1...>, Index<Idx2...>, Index<Idx3...>, Index<Idx4...>, Index<Idx5...> > {
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...,Idx1...,Idx2...,Idx3...,Idx4...,Idx5...>, Tensor<T,Rest0...,Rest1...,Rest2...,Rest3...,Rest4...,Rest5...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)+\
|
||||
sizeof...(Rest2)+sizeof...(Rest3)+sizeof...(Rest4)+sizeof...(Rest5)>::type>::type
|
||||
FASTOR_INLINE
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f) {
|
||||
|
||||
|
||||
using cost_model = 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...>>;
|
||||
|
||||
using resulting_index_0 = typename cost_model::resulting_index_0;
|
||||
using resulting_index_1 = typename cost_model::resulting_index_1;
|
||||
using resulting_index_2 = typename cost_model::resulting_index_2;
|
||||
using resulting_index_3 = typename cost_model::resulting_index_3;
|
||||
using resulting_index_4 = typename cost_model::resulting_index_4;
|
||||
using resulting_index_5 = typename cost_model::resulting_index_5;
|
||||
|
||||
constexpr int which_variant = cost_model::which_variant;
|
||||
|
||||
FASTOR_IF_CONSTEXPR (which_variant==0) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>>(a,b,c,d,e);
|
||||
return einsum<resulting_index_0,Index<Idx5...>>(tmp,f);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==1) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx5...>>(a,b,c,d,f);
|
||||
return einsum<Index<Idx4...>,resulting_index_1>(e,tmp);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==2) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx2...>,Index<Idx4...>,Index<Idx5...>>(a,b,c,e,f);
|
||||
return einsum<Index<Idx3...>,resulting_index_2>(d,tmp);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==3) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx1...>,Index<Idx3...>,Index<Idx4...>,Index<Idx5...>>(a,b,d,e,f);
|
||||
return einsum<Index<Idx2...>,resulting_index_3>(c,tmp);
|
||||
}
|
||||
else FASTOR_IF_CONSTEXPR (which_variant==4) {
|
||||
auto tmp = einsum<Index<Idx0...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>,Index<Idx5...>>(a,c,d,e,f);
|
||||
return einsum<Index<Idx1...>,resulting_index_4>(b,tmp);
|
||||
}
|
||||
else {
|
||||
auto tmp = einsum<Index<Idx1...>,Index<Idx2...>,Index<Idx3...>,Index<Idx4...>,Index<Idx5...>>(b,c,d,e,f);
|
||||
return einsum<Index<Idx0...>,resulting_index_5>(a,tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5>
|
||||
FASTOR_INLINE
|
||||
auto contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f)
|
||||
-> decltype(extractor_contract_6<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::contract_impl(a,b,c,d,e,f)) {
|
||||
return extractor_contract_6<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::contract_impl(a,b,c,d,e,f);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
// Seven tensor network
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
template<class T, class U, class V, class W, class X, class Y, class Z>
|
||||
struct extractor_contract_7 {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1, size_t ... Idx2, size_t ... Idx3,
|
||||
size_t ... Idx4, size_t ... Idx5, size_t ... Idx6>
|
||||
struct extractor_contract_7<Index<Idx0...>, Index<Idx1...>, Index<Idx2...>,
|
||||
Index<Idx3...>, Index<Idx4...>, Index<Idx5...>, Index<Idx6...> > {
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2,
|
||||
size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...,Idx1...,Idx2...,Idx3...,Idx4...,Idx5...,Idx6...>,
|
||||
Tensor<T,Rest0...,Rest1...,Rest2...,Rest3...,Rest4...,Rest5...,Rest6...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)+\
|
||||
sizeof...(Rest2)+sizeof...(Rest3)+sizeof...(Rest4)+sizeof...(Rest5)+sizeof...(Rest6)>::type>::type
|
||||
FASTOR_INLINE
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g) {
|
||||
|
||||
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;
|
||||
using resulting_tensor_1 = typename get_resuling_tensor<resulting_index_0,Index<Idx2...>,
|
||||
resulting_tensor_0,Tensor<T,Rest2...>>::type;
|
||||
using resulting_index_1 = typename get_resuling_index<resulting_index_0,Index<Idx2...>,
|
||||
resulting_tensor_0,Tensor<T,Rest2...>>::type;
|
||||
using resulting_tensor_2 = typename get_resuling_tensor<resulting_index_1,Index<Idx3...>,
|
||||
resulting_tensor_1,Tensor<T,Rest3...>>::type;
|
||||
using resulting_index_2 = typename get_resuling_index<resulting_index_1,Index<Idx3...>,
|
||||
resulting_tensor_1,Tensor<T,Rest3...>>::type;
|
||||
using resulting_tensor_3 = typename get_resuling_tensor<resulting_index_2,Index<Idx4...>,
|
||||
resulting_tensor_2,Tensor<T,Rest4...>>::type;
|
||||
using resulting_index_3 = typename get_resuling_index<resulting_index_2,Index<Idx4...>,
|
||||
resulting_tensor_2,Tensor<T,Rest4...>>::type;
|
||||
using resulting_tensor_4 = typename get_resuling_tensor<resulting_index_3,Index<Idx5...>,
|
||||
resulting_tensor_3,Tensor<T,Rest5...>>::type;
|
||||
using resulting_index_4 = typename get_resuling_index<resulting_index_3,Index<Idx5...>,
|
||||
resulting_tensor_3,Tensor<T,Rest5...>>::type;
|
||||
|
||||
|
||||
resulting_tensor_0 tmp0 = einsum<Index<Idx0...>,Index<Idx1...>>(a,b);
|
||||
resulting_tensor_1 tmp1 = einsum<resulting_index_0,Index<Idx2...>>(tmp0,c);
|
||||
resulting_tensor_2 tmp2 = einsum<resulting_index_1,Index<Idx3...>>(tmp1,d);
|
||||
resulting_tensor_3 tmp3 = einsum<resulting_index_2,Index<Idx4...>>(tmp2,e);
|
||||
resulting_tensor_4 tmp4 = einsum<resulting_index_3,Index<Idx5...>>(tmp3,f);
|
||||
auto tmp5 = einsum<resulting_index_4,Index<Idx6...>>(tmp4,g);
|
||||
|
||||
return tmp5;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L,
|
||||
class Index_M, class Index_N, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6>
|
||||
FASTOR_INLINE
|
||||
auto contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g)
|
||||
-> decltype(extractor_contract_7<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::contract_impl(a,b,c,d,e,f,g)) {
|
||||
return extractor_contract_7<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::contract_impl(a,b,c,d,e,f,g);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
// Eight tensor network
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
struct extractor_contract_8 {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1, size_t ... Idx2, size_t ... Idx3,
|
||||
size_t ... Idx4, size_t ... Idx5, size_t ... Idx6, size_t ... Idx7>
|
||||
struct extractor_contract_8<Index<Idx0...>, Index<Idx1...>, Index<Idx2...>,
|
||||
Index<Idx3...>, Index<Idx4...>, Index<Idx5...>, Index<Idx6...>, Index<Idx7...> > {
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2,
|
||||
size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6, size_t ... Rest7>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...,Idx1...,Idx2...,Idx3...,Idx4...,Idx5...,Idx6...>,
|
||||
Tensor<T,Rest0...,Rest1...,Rest2...,Rest3...,Rest4...,Rest5...,Rest6...,Rest7...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)+\
|
||||
sizeof...(Rest2)+sizeof...(Rest3)+sizeof...(Rest4)+sizeof...(Rest5)+\
|
||||
sizeof...(Rest6)+sizeof...(Rest7)>::type>::type
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g, const Tensor<T,Rest7...> &h) {
|
||||
|
||||
|
||||
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;
|
||||
using resulting_tensor_1 = typename get_resuling_tensor<resulting_index_0,Index<Idx2...>,
|
||||
resulting_tensor_0,Tensor<T,Rest2...>>::type;
|
||||
using resulting_index_1 = typename get_resuling_index<resulting_index_0,Index<Idx2...>,
|
||||
resulting_tensor_0,Tensor<T,Rest2...>>::type;
|
||||
using resulting_tensor_2 = typename get_resuling_tensor<resulting_index_1,Index<Idx3...>,
|
||||
resulting_tensor_1,Tensor<T,Rest3...>>::type;
|
||||
using resulting_index_2 = typename get_resuling_index<resulting_index_1,Index<Idx3...>,
|
||||
resulting_tensor_1,Tensor<T,Rest3...>>::type;
|
||||
using resulting_tensor_3 = typename get_resuling_tensor<resulting_index_2,Index<Idx4...>,
|
||||
resulting_tensor_2,Tensor<T,Rest4...>>::type;
|
||||
using resulting_index_3 = typename get_resuling_index<resulting_index_2,Index<Idx4...>,
|
||||
resulting_tensor_2,Tensor<T,Rest4...>>::type;
|
||||
using resulting_tensor_4 = typename get_resuling_tensor<resulting_index_3,Index<Idx5...>,
|
||||
resulting_tensor_3,Tensor<T,Rest5...>>::type;
|
||||
using resulting_index_4 = typename get_resuling_index<resulting_index_3,Index<Idx5...>,
|
||||
resulting_tensor_3,Tensor<T,Rest5...>>::type;
|
||||
using resulting_tensor_5 = typename get_resuling_tensor<resulting_index_4,Index<Idx6...>,
|
||||
resulting_tensor_4,Tensor<T,Rest6...>>::type;
|
||||
using resulting_index_5 = typename get_resuling_index<resulting_index_4,Index<Idx6...>,
|
||||
resulting_tensor_4,Tensor<T,Rest6...>>::type;
|
||||
|
||||
|
||||
resulting_tensor_0 tmp0 = einsum<Index<Idx0...>,Index<Idx1...>>(a,b);
|
||||
resulting_tensor_1 tmp1 = einsum<resulting_index_0,Index<Idx2...>>(tmp0,c);
|
||||
resulting_tensor_2 tmp2 = einsum<resulting_index_1,Index<Idx3...>>(tmp1,d);
|
||||
resulting_tensor_3 tmp3 = einsum<resulting_index_2,Index<Idx4...>>(tmp2,e);
|
||||
resulting_tensor_4 tmp4 = einsum<resulting_index_3,Index<Idx5...>>(tmp3,f);
|
||||
resulting_tensor_5 tmp5 = einsum<resulting_index_4,Index<Idx6...>>(tmp4,g);
|
||||
auto tmp6 = einsum<resulting_index_5,Index<Idx7...>>(tmp5,h);
|
||||
|
||||
return tmp6;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L,
|
||||
class Index_M, class Index_N, class Index_O, class Index_P,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6, size_t ... Rest7>
|
||||
FASTOR_INLINE
|
||||
auto contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g, const Tensor<T,Rest7...> &h)
|
||||
-> decltype(extractor_contract_8<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O,Index_P>::contract_impl(a,b,c,d,e,f,g,h)) {
|
||||
return extractor_contract_8<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O,Index_P>::contract_impl(a,b,c,d,e,f,g,h);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // FASTOR_DONT_PERFORM_OP_MIN
|
||||
|
||||
#endif // NETWORK_CONTRACTION_H
|
||||
1988
noarch/include/Fastor/tensor_algebra/network_contraction_no_opmin.h
Normal file
1988
noarch/include/Fastor/tensor_algebra/network_contraction_no_opmin.h
Normal file
File diff suppressed because it is too large
Load Diff
254
noarch/include/Fastor/tensor_algebra/network_einsum.h
Normal file
254
noarch/include/Fastor/tensor_algebra/network_einsum.h
Normal file
@@ -0,0 +1,254 @@
|
||||
#ifndef EINSUM_NETWORK_H
|
||||
#define EINSUM_NETWORK_H
|
||||
|
||||
#include "Fastor/tensor_algebra/network_contraction.h"
|
||||
#include "Fastor/tensor_algebra/network_contraction_no_opmin.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
// Networks
|
||||
//-----------------------------------------------------------------------------------------
|
||||
#ifndef FASTOR_DONT_PERFORM_OP_MIN
|
||||
|
||||
// 3
|
||||
template<class Index_I, class Index_J, class Index_K,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c)
|
||||
-> decltype(extractor_contract_3<Index_I,Index_J,Index_K>::contract_impl(a,b,c)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_3<Index_I,Index_J,Index_K>::contract_impl(a,b,c);
|
||||
}
|
||||
|
||||
|
||||
// 4
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3>
|
||||
FASTOR_INLINE auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d)
|
||||
-> decltype(extractor_contract_4<Index_I,Index_J,Index_K,Index_L>::contract_impl(a,b,c,d)) {
|
||||
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_4<Index_I,Index_J,Index_K,Index_L>::contract_impl(a,b,c,d);
|
||||
}
|
||||
|
||||
|
||||
// 5
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e)
|
||||
-> decltype(extractor_contract_5<Index_I,Index_J,Index_K,Index_L,Index_M>::contract_impl(a,b,c,d,e)) {
|
||||
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L,Index_M>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_5<Index_I,Index_J,Index_K,Index_L,Index_M>::contract_impl(a,b,c,d,e);
|
||||
}
|
||||
|
||||
|
||||
// 6
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f)
|
||||
-> decltype(extractor_contract_6<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::contract_impl(a,b,c,d,e,f)) {
|
||||
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_6<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::contract_impl(a,b,c,d,e,f);
|
||||
}
|
||||
|
||||
|
||||
// 7
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2,
|
||||
size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g)
|
||||
-> decltype(extractor_contract_7<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::contract_impl(a,b,c,d,e,f,g)) {
|
||||
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_7<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::contract_impl(a,b,c,d,e,f,g);
|
||||
}
|
||||
|
||||
|
||||
// 8
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N, class Index_O, class Index_P,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2,
|
||||
size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6, size_t ... Rest7>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g, const Tensor<T,Rest7...> &h)
|
||||
-> decltype(extractor_contract_8<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O,Index_P>::contract_impl(a,b,c,d,e,f,g,h)) {
|
||||
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O,Index_P>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_8<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O,Index_P>::contract_impl(a,b,c,d,e,f,g,h);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
|
||||
// No operation minimisation
|
||||
//------------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
// 3
|
||||
template<class Index_I, class Index_J, class Index_K,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b, const Tensor<T,Rest2...> &c)
|
||||
-> decltype(extractor_contract_3_no_opt<Index_I,Index_J,Index_K>::contract_impl(a,b,c)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_3_no_opt<Index_I,Index_J,Index_K>::contract_impl(a,b,c);
|
||||
}
|
||||
|
||||
// 4
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d)
|
||||
-> decltype(extractor_contract_4_no_opt<Index_I,Index_J,Index_K,Index_L>::contract_impl(a,b,c,d)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_4_no_opt<Index_I,Index_J,Index_K,Index_L>::contract_impl(a,b,c,d);
|
||||
}
|
||||
|
||||
// 5
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e)
|
||||
-> decltype(extractor_contract_5_no_opt<Index_I,Index_J,Index_K,Index_L,Index_M>::contract_impl(a,b,c,d,e)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L,Index_M>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_5_no_opt<Index_I,Index_J,Index_K,Index_L,Index_M>::contract_impl(a,b,c,d,e);
|
||||
}
|
||||
|
||||
// 6
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f)
|
||||
-> decltype(extractor_contract_6_no_opt<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::contract_impl(a,b,c,d,e,f)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_6_no_opt<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N>::contract_impl(a,b,c,d,e,f);
|
||||
}
|
||||
|
||||
// 7
|
||||
template<class Index_I, class Index_J, class Index_K, class Index_L, class Index_M, class Index_N, class Index_O,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g)
|
||||
-> decltype(extractor_contract_7_no_opt<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::contract_impl(a,b,c,d,e,f,g)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_7_no_opt<Index_I,Index_J,Index_K,Index_L,Index_M,Index_N,Index_O>::contract_impl(a,b,c,d,e,f,g);
|
||||
}
|
||||
|
||||
// 8
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4, class Ind5, class Ind6, class Ind7,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3,
|
||||
size_t ... Rest4, size_t ... Rest5, size_t ... Rest6, size_t ... Rest7>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g, const Tensor<T,Rest7...> &h)
|
||||
-> decltype(extractor_contract_8_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7>::contract_impl(a,b,c,d,e,f,g,h)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_8_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7>::contract_impl(a,b,c,d,e,f,g,h);
|
||||
}
|
||||
|
||||
// 9
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4, class Ind5, class Ind6,
|
||||
class Ind7, class Ind8,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6,
|
||||
size_t ... Rest7, size_t ... Rest8>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g, const Tensor<T,Rest7...> &h,
|
||||
const Tensor<T,Rest8...> &h1)
|
||||
-> decltype(extractor_contract_9_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8>::contract_impl(a,b,c,d,e,f,g,h,h1)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_9_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8>::contract_impl(a,b,c,d,e,f,g,h,h1);
|
||||
}
|
||||
|
||||
|
||||
// 10
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4, class Ind5, class Ind6,
|
||||
class Ind7, class Ind8, class Ind9,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6,
|
||||
size_t ... Rest7, size_t ... Rest8, size_t ... Rest9>
|
||||
FASTOR_INLINE
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g, const Tensor<T,Rest7...> &h,
|
||||
const Tensor<T,Rest8...> &h1, const Tensor<T,Rest9...> &h2)
|
||||
-> decltype(extractor_contract_10_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8,Ind9>::contract_impl(a,b,c,d,e,f,g,h,h1,h2)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8,Ind9>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_10_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8,Ind9>::contract_impl(a,b,c,d,e,f,g,h,h1,h2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 11
|
||||
template<class Ind0, class Ind1, class Ind2, class Ind3, class Ind4, class Ind5, class Ind6,
|
||||
class Ind7, class Ind8, class Ind9, class Ind10,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1,
|
||||
size_t ... Rest2, size_t ... Rest3, size_t ... Rest4, size_t ... Rest5, size_t ... Rest6,
|
||||
size_t ... Rest7, size_t ... Rest8, size_t ... Rest9, size_t ... Rest10>
|
||||
auto einsum(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b,
|
||||
const Tensor<T,Rest2...> &c, const Tensor<T,Rest3...> &d,
|
||||
const Tensor<T,Rest4...> &e, const Tensor<T,Rest5...> &f,
|
||||
const Tensor<T,Rest6...> &g, const Tensor<T,Rest7...> &h,
|
||||
const Tensor<T,Rest8...> &h1, const Tensor<T,Rest9...> &h2,
|
||||
const Tensor<T,Rest10...> &h3)
|
||||
-> decltype(extractor_contract_11_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8,Ind9,Ind10>::contract_impl(a,b,c,d,e,f,g,h,h1,h2,h3)) {
|
||||
static_assert(einsum_index_checker<typename concat_<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8,Ind9,Ind10>::type>::value,
|
||||
"INDICES FOR EINSUM FUNCTION CANNOT APPEAR MORE THAN TWICE. USE CONTRACTION INSTEAD");
|
||||
return extractor_contract_11_no_opt<Ind0,Ind1,Ind2,Ind3,Ind4,Ind5,Ind6,Ind7,Ind8,Ind9,Ind10>::contract_impl(a,b,c,d,e,f,g,h,h1,h2,h3);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
|
||||
#endif
|
||||
124
noarch/include/Fastor/tensor_algebra/outerproduct.h
Normal file
124
noarch/include/Fastor/tensor_algebra/outerproduct.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#ifndef OUTERPRODUCT_H
|
||||
#define OUTERPRODUCT_H
|
||||
|
||||
#include "Fastor/backend/dyadic.h"
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor/TensorTraits.h"
|
||||
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
// These set of functions implement the outer/dyadic products of two or multiple tensor expressions
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
template<typename T, size_t ...Rest0, size_t ...Rest1>
|
||||
FASTOR_INLINE Tensor<T,Rest0...,Rest1...>
|
||||
outer(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
Tensor<T,Rest0...,Rest1...> out;
|
||||
_dyadic<T,pack_prod<Rest0...>::value,pack_prod<Rest1...>::value>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T, size_t ...Rest0>
|
||||
FASTOR_INLINE Tensor<T,Rest0...>
|
||||
outer(const Tensor<T,Rest0...> &a, const Tensor<T,1> &b) {
|
||||
Tensor<T,Rest0...,1> out = a*b.toscalar();
|
||||
return out;
|
||||
}
|
||||
template<typename T, size_t ...Rest1>
|
||||
FASTOR_INLINE Tensor<T,Rest1...>
|
||||
outer(const Tensor<T,1> &a, const Tensor<T,Rest1...> &b) {
|
||||
Tensor<T,1,Rest1...> out = a.toscalar()*b;
|
||||
return out;
|
||||
}
|
||||
template<typename T>
|
||||
FASTOR_INLINE Tensor<T>
|
||||
outer(const Tensor<T> &a, const Tensor<T> &b) {
|
||||
Tensor<T> out;
|
||||
_dyadic<T,1,1>(a.data(),b.data(),out.data());
|
||||
return out;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Expressions
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
concatenated_tensor_t<typename Derived0::result_type,typename Derived1::result_type>
|
||||
outer(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
|
||||
using lhs_type = typename Derived0::result_type;
|
||||
using rhs_type = typename Derived1::result_type;
|
||||
return outer(lhs_type(a),rhs_type(b));
|
||||
}
|
||||
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
|
||||
enable_if_t_<!is_tensor_v<Derived0> && is_tensor_v<Derived1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
concatenated_tensor_t<typename Derived0::result_type,typename Derived1::result_type>
|
||||
outer(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
|
||||
using lhs_type = typename Derived0::result_type;
|
||||
return outer(lhs_type(a),b.self());
|
||||
}
|
||||
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
|
||||
enable_if_t_<is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
concatenated_tensor_t<typename Derived0::result_type,typename Derived1::result_type>
|
||||
outer(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
|
||||
using rhs_type = typename Derived1::result_type;
|
||||
return outer(a.self(),rhs_type(b));
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
FASTOR_INLINE Tensor<T,Rest0...,Rest1...>
|
||||
dyadic(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
return outer(a,b);
|
||||
}
|
||||
|
||||
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1>
|
||||
FASTOR_INLINE
|
||||
concatenated_tensor_t<typename Derived0::result_type,typename Derived1::result_type>
|
||||
dyadic(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
|
||||
return outer(a,b);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// multiple chained expressions - network outerproduct
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#if FASTOR_CXX_VERSION >= 2014
|
||||
// template<typename AbstractTensorType0>
|
||||
// FASTOR_INLINE
|
||||
// auto
|
||||
// outer(const AbstractTensorType0& a)
|
||||
// {
|
||||
// return a;
|
||||
// }
|
||||
|
||||
template<typename AbstractTensorType0, typename AbstractTensorType1, typename ... AbstractTensorTypes,
|
||||
enable_if_t_<is_greater_equal_v_<sizeof...(AbstractTensorTypes),1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
outer(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest)
|
||||
{
|
||||
const auto res = outer(a,b);
|
||||
return outer(res, rest...);
|
||||
}
|
||||
|
||||
template<typename AbstractTensorType0, typename AbstractTensorType1, typename ... AbstractTensorTypes,
|
||||
enable_if_t_<is_greater_equal_v_<sizeof...(AbstractTensorTypes),1>,bool> = false >
|
||||
FASTOR_INLINE
|
||||
auto
|
||||
dyadic(const AbstractTensorType0& a, const AbstractTensorType1& b, const AbstractTensorTypes& ... rest)
|
||||
{
|
||||
return outer(a, b, rest...);
|
||||
}
|
||||
#endif
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // OUTERPRODUCT_H
|
||||
|
||||
356
noarch/include/Fastor/tensor_algebra/permutation.h
Normal file
356
noarch/include/Fastor/tensor_algebra/permutation.h
Normal file
@@ -0,0 +1,356 @@
|
||||
#ifndef PERMUTATION_H
|
||||
#define PERMUTATION_H
|
||||
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor/TensorTraits.h"
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
#include "Fastor/meta/einsum_meta.h"
|
||||
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<class Idx, class Tens, size_t ... Args>
|
||||
struct RecursiveCartesianPerm;
|
||||
|
||||
template<typename T, size_t ...Idx, size_t ...Rest, size_t First, size_t ... Lasts>
|
||||
struct RecursiveCartesianPerm<Index<Idx...>, Tensor<T,Rest...>, First, Lasts...> {
|
||||
|
||||
static constexpr size_t out_dim = sizeof...(Rest);
|
||||
static
|
||||
FASTOR_INLINE
|
||||
void Do(const T *a_data, T *out_data, std::array<size_t,out_dim> &as, std::array<size_t,out_dim> &idx) {
|
||||
for (size_t i=0; i<First; ++i) {
|
||||
idx[sizeof...(Lasts)] = i;
|
||||
RecursiveCartesianPerm<Index<Idx...>, Tensor<T,Rest...>,Lasts...>::Do(a_data, out_data, as, idx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
struct RecursiveCartesianPerm<Index<Idx...>, Tensor<T,Rest...>,Last>
|
||||
{
|
||||
using _permute_impl = permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>;
|
||||
using resulting_tensor = typename _permute_impl::resulting_tensor;
|
||||
using resulting_index = typename _permute_impl::resulting_index;
|
||||
using maxes_out_type = typename _permute_impl::maxes_out_type;
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> maxes_idx = resulting_index::values;
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> maxes_out = maxes_out_type::values;
|
||||
|
||||
static constexpr size_t a_dim = sizeof...(Rest);
|
||||
static constexpr size_t out_dim = a_dim;
|
||||
static constexpr std::array<size_t,a_dim> maxes_a = {Rest...};
|
||||
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> products_a = nprods<Index<Rest...>,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> products_out = nprods<maxes_out_type,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
static
|
||||
FASTOR_INLINE
|
||||
void Do(const T *a_data, T *out_data, std::array<size_t,out_dim> &as, std::array<size_t,out_dim> &idx)
|
||||
{
|
||||
constexpr size_t stride = 1;
|
||||
for (size_t i=0; i<Last; i+=stride) {
|
||||
idx[0] = i;
|
||||
std::reverse_copy(idx.begin(),idx.end(),as.begin());
|
||||
|
||||
size_t index_a = as[a_dim-1];
|
||||
for(size_t it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[it];
|
||||
}
|
||||
size_t index_out = as[maxes_idx[out_dim-1]];
|
||||
for(size_t it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[maxes_idx[it]];
|
||||
}
|
||||
|
||||
out_data[index_out] = a_data[index_a];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
constexpr std::array<size_t,sizeof...(Rest)> RecursiveCartesianPerm<Index<Idx...>,
|
||||
Tensor<T,Rest...>,Last>::maxes_idx;
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
constexpr std::array<size_t,sizeof...(Rest)> RecursiveCartesianPerm<Index<Idx...>,
|
||||
Tensor<T,Rest...>,Last>::maxes_out;
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
constexpr std::array<size_t,sizeof...(Rest)> RecursiveCartesianPerm<Index<Idx...>,
|
||||
Tensor<T,Rest...>,Last>::products_a;
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
constexpr std::array<size_t,sizeof...(Rest)> RecursiveCartesianPerm<Index<Idx...>,
|
||||
Tensor<T,Rest...>,Last>::products_out;
|
||||
|
||||
|
||||
|
||||
// template<typename T, size_t ...Idx, size_t ...Rest>
|
||||
// struct RecursiveCartesianPerm<Index<Idx...>, Tensor<T,Rest...>>
|
||||
// {
|
||||
// using OutTensor = typename permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::type;
|
||||
// using maxes_out_type = typename permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::maxes_out_type;
|
||||
// using index_type = typename permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::index_type;
|
||||
// static constexpr auto maxes_idx = permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::index_type::values;
|
||||
// static constexpr auto maxes_out = permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
// typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::maxes_out_type::values;
|
||||
|
||||
// static constexpr int a_dim = sizeof...(Rest);
|
||||
// static constexpr int out_dim = a_dim;
|
||||
// static constexpr std::array<int,a_dim> maxes_a = {Rest...};
|
||||
|
||||
// static constexpr std::array<size_t,sizeof...(Rest)> products_a = nprods<Index<Rest...>,
|
||||
// typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
// static constexpr std::array<size_t,sizeof...(Rest)> products_out = nprods<maxes_out_type,
|
||||
// typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
// static void Do(const T *a_data, T *out_data, std::array<int,out_dim> &as, std::array<int,out_dim> &idx)
|
||||
// {
|
||||
// std::reverse_copy(idx.begin(),idx.end(),as.begin());
|
||||
|
||||
// int index_a = as[a_dim-1];
|
||||
// for(int it = 0; it< a_dim; it++) {
|
||||
// index_a += products_a[it]*as[it];
|
||||
// }
|
||||
// int index_out = as[maxes_idx[out_dim-1]];
|
||||
// for(int it = 0; it< out_dim-1; it++) {
|
||||
// index_out += products_out[it]*as[maxes_idx[it]];
|
||||
// }
|
||||
|
||||
// out_data[index_out] = a_data[index_a];
|
||||
// }
|
||||
// };
|
||||
|
||||
// template<typename T, size_t ...Idx, size_t ...Rest>
|
||||
// constexpr std::array<size_t,sizeof...(Rest)> RecursiveCartesianPerm<Index<Idx...>,
|
||||
// Tensor<T,Rest...>>::products_a;
|
||||
|
||||
// template<typename T, size_t ...Idx, size_t ...Rest>
|
||||
// constexpr std::array<size_t,sizeof...(Rest)> RecursiveCartesianPerm<Index<Idx...>,
|
||||
// Tensor<T,Rest...>>::products_out;
|
||||
|
||||
|
||||
|
||||
template<class Idx, class Tens, class Args>
|
||||
struct RecursiveCartesianPermDispatcher;
|
||||
|
||||
template<typename T, size_t ...Idx, size_t ...Rest, size_t ... Args>
|
||||
struct RecursiveCartesianPermDispatcher<Index<Idx...>, Tensor<T,Rest...>, Index<Args...> >
|
||||
{
|
||||
static constexpr size_t out_dim = sizeof...(Rest);
|
||||
|
||||
static FASTOR_INLINE void Do(const T *a_data, T *out_data,
|
||||
std::array<size_t,out_dim> &as, std::array<size_t,out_dim> &idx) {
|
||||
return RecursiveCartesianPerm<Index<Idx...>,Tensor<T,Rest...>, Args...>::Do(a_data, out_data, as, idx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
struct extractor_perm {};
|
||||
|
||||
template<size_t ... Idx>
|
||||
struct extractor_perm<Index<Idx...> > {
|
||||
|
||||
template<typename T, size_t ... Rest>
|
||||
static
|
||||
FASTOR_INLINE
|
||||
typename permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::resulting_tensor
|
||||
permutation_impl(const Tensor<T,Rest...> &a) {
|
||||
|
||||
using _permute_impl = permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>;
|
||||
using resulting_tensor = typename _permute_impl::resulting_tensor;
|
||||
constexpr bool requires_permutation = _permute_impl::requires_permutation;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return a;
|
||||
|
||||
#if CONTRACT_OPT==-1
|
||||
|
||||
using resulting_index = typename _permute_impl::resulting_index;
|
||||
using maxes_out_type = typename _permute_impl::maxes_out_type;
|
||||
constexpr auto& maxes_idx = resulting_index::values;
|
||||
constexpr auto& maxes_out = maxes_out_type::values;
|
||||
|
||||
constexpr int a_dim = sizeof...(Rest);
|
||||
constexpr int out_dim = a_dim;
|
||||
constexpr std::array<int,a_dim> maxes_a = {Rest...};
|
||||
|
||||
constexpr auto& products_a = nprods<Index<Rest...>,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr auto& products_out = nprods<maxes_out_type,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
resulting_tensor out;
|
||||
out.zeros();
|
||||
|
||||
T *a_data = a.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
int as[out_dim] = {};
|
||||
int it,jt;
|
||||
|
||||
while(true)
|
||||
{
|
||||
int index_a = as[a_dim-1];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[it];
|
||||
}
|
||||
int index_out = as[maxes_idx[out_dim-1]];
|
||||
for(it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[maxes_idx[it]];
|
||||
}
|
||||
|
||||
out_data[index_out] = a_data[index_a];
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_a[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
resulting_tensor out;
|
||||
|
||||
const T *a_data = a.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr size_t out_dim = sizeof...(Rest);
|
||||
|
||||
std::array<size_t,out_dim> as = {};
|
||||
std::array<size_t,out_dim> idx = {};
|
||||
|
||||
using nloops = loop_setter<
|
||||
Index<Idx...>,
|
||||
Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
using dims_type = typename nloops::dims_type;
|
||||
|
||||
RecursiveCartesianPermDispatcher<Index<Idx...>,Tensor<T,Rest...>,dims_type>::Do(a_data,out_data,as,idx);
|
||||
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Abstract permutation
|
||||
template<typename Derived, size_t DIMS,
|
||||
enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
|
||||
static
|
||||
FASTOR_INLINE
|
||||
typename permute_impl<
|
||||
Index<Idx...>, typename Derived::result_type,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::resulting_tensor
|
||||
permutation_impl(const AbstractTensor<Derived,DIMS> &a) {
|
||||
|
||||
using T = typename Derived::scalar_type;
|
||||
using tensor_type = typename Derived::result_type;
|
||||
|
||||
using _permute_impl = permute_impl<Index<Idx...>, tensor_type,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>;
|
||||
using resulting_tensor = typename _permute_impl::resulting_tensor;
|
||||
using resulting_index = typename _permute_impl::resulting_index;
|
||||
using maxes_out_type = typename _permute_impl::maxes_out_type;
|
||||
constexpr auto& maxes_idx = resulting_index::values;
|
||||
|
||||
constexpr int a_dim = DIMS;
|
||||
constexpr int out_dim = a_dim;
|
||||
constexpr std::array<int,a_dim> maxes_a = get_tensor_dimensions<tensor_type>::dims_int;
|
||||
|
||||
constexpr auto& products_a = nprods<typename get_tensor_dimensions<tensor_type>::tensor_to_index,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr auto& products_out = nprods<maxes_out_type,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
resulting_tensor out;
|
||||
out.zeros();
|
||||
T *out_data = out.data();
|
||||
const Derived & a_src = a.self();
|
||||
|
||||
int as[out_dim] = {};
|
||||
int it,jt;
|
||||
|
||||
while(true)
|
||||
{
|
||||
int index_a = as[a_dim-1];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[it];
|
||||
}
|
||||
int index_out = as[maxes_idx[out_dim-1]];
|
||||
for(it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[maxes_idx[it]];
|
||||
}
|
||||
|
||||
out_data[index_out] = a_src.template eval_s<T>(index_a);
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_a[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
} // internal
|
||||
|
||||
|
||||
|
||||
template<class Index_I, typename T, size_t ... Rest>
|
||||
FASTOR_INLINE
|
||||
typename internal::permute_impl<Index_I, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest)>::type>::resulting_tensor
|
||||
permutation(const Tensor<T, Rest...> &a) {
|
||||
return internal::extractor_perm<Index_I>::permutation_impl(a);
|
||||
}
|
||||
|
||||
template<class Index_I, typename Derived, size_t DIMS,
|
||||
enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
typename internal::permute_impl<Index_I,
|
||||
typename Derived::result_type,
|
||||
typename std_ext::make_index_sequence<DIMS>::type>::resulting_tensor
|
||||
permutation(const AbstractTensor<Derived, DIMS> &a) {
|
||||
return internal::extractor_perm<Index_I>::permutation_impl(a.self());
|
||||
}
|
||||
|
||||
template<class Index_I, typename Derived, size_t DIMS,
|
||||
enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
typename internal::permute_impl<Index_I,
|
||||
typename Derived::result_type,
|
||||
typename std_ext::make_index_sequence<DIMS>::type>::resulting_tensor
|
||||
permutation(const AbstractTensor<Derived, DIMS> &a) {
|
||||
using result_type = typename Derived::result_type;
|
||||
const result_type tmp(a);
|
||||
return internal::extractor_perm<Index_I>::permutation_impl(tmp);
|
||||
}
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // PERMUTATION_H
|
||||
397
noarch/include/Fastor/tensor_algebra/permute.h
Normal file
397
noarch/include/Fastor/tensor_algebra/permute.h
Normal file
@@ -0,0 +1,397 @@
|
||||
#ifndef PERMUTE_H
|
||||
#define PERMUTE_H
|
||||
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor/TensorTraits.h"
|
||||
#include "Fastor/meta/einsum_meta.h"
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<class Idx, class Tens, size_t ... Args>
|
||||
struct NewRecursiveCartesianPerm;
|
||||
|
||||
template<typename T, size_t ...Idx, size_t ...Rest, size_t First, size_t ... Lasts>
|
||||
struct NewRecursiveCartesianPerm<Index<Idx...>, Tensor<T,Rest...>, First, Lasts...> {
|
||||
|
||||
static constexpr size_t out_dim = sizeof...(Rest);
|
||||
static
|
||||
FASTOR_INLINE
|
||||
void Do(const T *a_data, T *out_data, std::array<size_t,out_dim> &as, std::array<size_t,out_dim> &idx) {
|
||||
for (size_t i=0; i<First; ++i) {
|
||||
idx[sizeof...(Lasts)] = i;
|
||||
NewRecursiveCartesianPerm<Index<Idx...>, Tensor<T,Rest...>,Lasts...>::Do(a_data, out_data, as, idx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
struct NewRecursiveCartesianPerm<Index<Idx...>, Tensor<T,Rest...>,Last>
|
||||
{
|
||||
using _permute_impl = new_permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>;
|
||||
using resulting_tensor = typename _permute_impl::resulting_tensor;
|
||||
using resulting_index = typename _permute_impl::resulting_index;
|
||||
using maxes_out_type = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
|
||||
static constexpr size_t a_dim = sizeof...(Rest);
|
||||
static constexpr size_t out_dim = a_dim;
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
using reverse_map = internal::permute_mapped_index_t<Index<Idx...>,make_index_t<a_dim>>;
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> maxes_idx = reverse_map::values;
|
||||
#else
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> maxes_idx = resulting_index::values;
|
||||
#endif
|
||||
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> products_a = nprods<Index<Rest...>,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
static constexpr std::array<size_t,sizeof...(Rest)> products_out = nprods<maxes_out_type,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
static
|
||||
FASTOR_INLINE
|
||||
void Do(const T *a_data, T *out_data, std::array<size_t,out_dim> &as, std::array<size_t,out_dim> &idx)
|
||||
{
|
||||
constexpr size_t stride = 1;
|
||||
for (size_t i = 0; i < Last; i+=stride) {
|
||||
idx[0] = i;
|
||||
std::reverse_copy(idx.begin(),idx.end(),as.begin());
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
size_t index_a = as[maxes_idx[a_dim-1]];
|
||||
for(size_t it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[maxes_idx[it]];
|
||||
}
|
||||
size_t index_out = as[out_dim-1];
|
||||
for(size_t it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[it];
|
||||
}
|
||||
#else
|
||||
size_t index_a = as[a_dim-1];
|
||||
for(size_t it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[it];
|
||||
}
|
||||
size_t index_out = as[maxes_idx[out_dim-1]];
|
||||
for(size_t it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[maxes_idx[it]];
|
||||
}
|
||||
#endif
|
||||
|
||||
out_data[index_out] = a_data[index_a];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
constexpr std::array<size_t,sizeof...(Rest)> NewRecursiveCartesianPerm<Index<Idx...>,
|
||||
Tensor<T,Rest...>,Last>::maxes_idx;
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
constexpr std::array<size_t,sizeof...(Rest)> NewRecursiveCartesianPerm<Index<Idx...>,
|
||||
Tensor<T,Rest...>,Last>::products_a;
|
||||
|
||||
template<typename T, size_t Last, size_t ...Idx, size_t ...Rest>
|
||||
constexpr std::array<size_t,sizeof...(Rest)> NewRecursiveCartesianPerm<Index<Idx...>,
|
||||
Tensor<T,Rest...>,Last>::products_out;
|
||||
|
||||
|
||||
|
||||
template<class Idx, class Tens, class Args>
|
||||
struct NewRecursiveCartesianPermDispatcher;
|
||||
|
||||
template<typename T, size_t ...Idx, size_t ...Rest, size_t ... Args>
|
||||
struct NewRecursiveCartesianPermDispatcher<Index<Idx...>, Tensor<T,Rest...>, Index<Args...> >
|
||||
{
|
||||
static constexpr size_t out_dim = sizeof...(Rest);
|
||||
|
||||
static FASTOR_INLINE void Do(const T *a_data, T *out_data,
|
||||
std::array<size_t,out_dim> &as, std::array<size_t,out_dim> &idx) {
|
||||
return NewRecursiveCartesianPerm<Index<Idx...>,Tensor<T,Rest...>, Args...>::Do(a_data, out_data, as, idx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
struct new_extractor_perm {};
|
||||
|
||||
template<size_t ... Idx>
|
||||
struct new_extractor_perm<Index<Idx...> > {
|
||||
|
||||
template<typename T, size_t ... Rest>
|
||||
static
|
||||
FASTOR_INLINE
|
||||
typename new_permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::resulting_tensor
|
||||
permutation_impl(const Tensor<T,Rest...> &a) {
|
||||
|
||||
using _permute_impl = new_permute_impl<Index<Idx...>, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>;
|
||||
using resulting_tensor = typename _permute_impl::resulting_tensor;
|
||||
constexpr bool requires_permutation = _permute_impl::requires_permutation;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return a;
|
||||
|
||||
#if CONTRACT_OPT==-1
|
||||
|
||||
using maxes_out_type = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
|
||||
constexpr size_t a_dim = sizeof...(Rest);
|
||||
constexpr size_t out_dim = a_dim;
|
||||
|
||||
constexpr auto& products_a = nprods<Index<Rest...>,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr auto& products_out = nprods<maxes_out_type,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
resulting_tensor out;
|
||||
|
||||
T *a_data = a.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
size_t as[out_dim] = {};
|
||||
int jt;
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
constexpr std::array<size_t,a_dim> maxes_out = maxes_out_type::values;
|
||||
// Map to go from out to in
|
||||
// Get the reverse map - this is to get contiguous memory writes
|
||||
using reverse_map = internal::permute_mapped_index_t<Index<Idx...>,make_index_t<a_dim>>;
|
||||
constexpr auto& maxes_idx = reverse_map::values;
|
||||
// print(type_name<mapped_index>());
|
||||
|
||||
while(true)
|
||||
{
|
||||
size_t index_a = as[maxes_idx[a_dim-1]];
|
||||
for(size_t it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[maxes_idx[it]];
|
||||
}
|
||||
size_t index_out = as[out_dim-1];
|
||||
for(size_t it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[it];
|
||||
}
|
||||
// print(index_out);
|
||||
// print(index_a);
|
||||
|
||||
out_data[index_out] = a_data[index_a];
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_out[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
#else
|
||||
using resulting_index = typename _permute_impl::resulting_index;
|
||||
constexpr std::array<size_t,a_dim> maxes_a = {Rest...};
|
||||
// Map to go from in to out
|
||||
constexpr auto& maxes_idx = resulting_index::values;
|
||||
|
||||
while(true)
|
||||
{
|
||||
size_t index_a = as[a_dim-1];
|
||||
for(size_t it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[it];
|
||||
}
|
||||
size_t index_out = as[maxes_idx[out_dim-1]];
|
||||
for(size_t it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[maxes_idx[it]];
|
||||
}
|
||||
|
||||
out_data[index_out] = a_data[index_a];
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_a[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
resulting_tensor out;
|
||||
|
||||
const T *a_data = a.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr size_t a_dim = sizeof...(Rest);
|
||||
constexpr size_t out_dim = sizeof...(Rest);
|
||||
|
||||
std::array<size_t,out_dim> as = {};
|
||||
std::array<size_t,out_dim> idx = {};
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
using reverse_map = internal::permute_mapped_index_t<Index<Idx...>,make_index_t<a_dim>>;
|
||||
using nloops = loop_setter<
|
||||
reverse_map,
|
||||
resulting_tensor,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
using dims_type = typename nloops::dims_type;
|
||||
|
||||
NewRecursiveCartesianPermDispatcher<Index<Idx...>,Tensor<T,Rest...>,dims_type>::Do(a_data,out_data,as,idx);
|
||||
#else
|
||||
using nloops = loop_setter<
|
||||
Index<Idx...>,
|
||||
Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
using dims_type = typename nloops::dims_type;
|
||||
|
||||
NewRecursiveCartesianPermDispatcher<Index<Idx...>,Tensor<T,Rest...>,dims_type>::Do(a_data,out_data,as,idx);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Abstract permutation
|
||||
template<typename Derived, size_t DIMS,
|
||||
enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
|
||||
static
|
||||
FASTOR_INLINE
|
||||
typename new_permute_impl<
|
||||
Index<Idx...>, typename Derived::result_type,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>::resulting_tensor
|
||||
permutation_impl(const AbstractTensor<Derived,DIMS> &a) {
|
||||
|
||||
using T = typename Derived::scalar_type;
|
||||
using tensor_type = typename Derived::result_type;
|
||||
|
||||
using _permute_impl = new_permute_impl<Index<Idx...>, tensor_type,
|
||||
typename std_ext::make_index_sequence<sizeof...(Idx)>::type>;
|
||||
using resulting_tensor = typename _permute_impl::resulting_tensor;
|
||||
constexpr bool requires_permutation = _permute_impl::requires_permutation;
|
||||
FASTOR_IF_CONSTEXPR(!requires_permutation) return a;
|
||||
|
||||
using maxes_out_type = typename put_dims_in_Index<resulting_tensor>::type;
|
||||
|
||||
constexpr size_t a_dim = DIMS;
|
||||
constexpr size_t out_dim = a_dim;
|
||||
|
||||
constexpr auto& products_a = nprods<typename get_tensor_dimensions<tensor_type>::tensor_to_index,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr auto& products_out = nprods<maxes_out_type,
|
||||
typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
|
||||
resulting_tensor out;
|
||||
T *out_data = out.data();
|
||||
const Derived & a_src = a.self();
|
||||
|
||||
size_t as[out_dim] = {};
|
||||
int jt;
|
||||
|
||||
#if FASTOR_CXX_VERSION >= 2017
|
||||
constexpr std::array<size_t,a_dim> maxes_out = maxes_out_type::values;
|
||||
// Map to go from in to out
|
||||
// constexpr auto& maxes_idx = resulting_index::values;
|
||||
// Map to go from out to in
|
||||
// Get the reverse map - this is to get contiguous memory writes
|
||||
using reverse_map = internal::permute_mapped_index_t<Index<Idx...>,make_index_t<a_dim>>;
|
||||
constexpr auto& maxes_idx = reverse_map::values;
|
||||
|
||||
while(true)
|
||||
{
|
||||
size_t index_a = as[maxes_idx[a_dim-1]];
|
||||
for(size_t it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[maxes_idx[it]];
|
||||
}
|
||||
size_t index_out = as[out_dim-1];
|
||||
for(size_t it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[it];
|
||||
}
|
||||
|
||||
out_data[index_out] = a_src.template eval_s<T>(index_a);
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_out[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
#else
|
||||
constexpr std::array<size_t,a_dim> maxes_a = get_tensor_dimensions<tensor_type>::dims;
|
||||
// Map to go from in to out
|
||||
using resulting_index = typename _permute_impl::resulting_index;
|
||||
constexpr auto& maxes_idx = resulting_index::values;
|
||||
|
||||
while(true)
|
||||
{
|
||||
size_t index_a = as[a_dim-1];
|
||||
for(size_t it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[it];
|
||||
}
|
||||
size_t index_out = as[maxes_idx[out_dim-1]];
|
||||
for(size_t it = 0; it< out_dim-1; it++) {
|
||||
index_out += products_out[it]*as[maxes_idx[it]];
|
||||
}
|
||||
|
||||
out_data[index_out] = a_src.template eval_s<T>(index_a);
|
||||
|
||||
for(jt = out_dim-1 ; jt>=0 ; jt--)
|
||||
{
|
||||
if(++as[jt]<maxes_a[jt])
|
||||
break;
|
||||
else
|
||||
as[jt]=0;
|
||||
}
|
||||
if(jt<0)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
} // internal
|
||||
|
||||
|
||||
|
||||
template<class Index_I, typename T, size_t ... Rest>
|
||||
FASTOR_INLINE
|
||||
typename internal::new_permute_impl<Index_I, Tensor<T,Rest...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest)>::type>::resulting_tensor
|
||||
permute(const Tensor<T, Rest...> &a) {
|
||||
return internal::new_extractor_perm<Index_I>::permutation_impl(a);
|
||||
}
|
||||
|
||||
template<class Index_I, typename Derived, size_t DIMS,
|
||||
enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
typename internal::new_permute_impl<Index_I,
|
||||
typename Derived::result_type,
|
||||
typename std_ext::make_index_sequence<DIMS>::type>::resulting_tensor
|
||||
permute(const AbstractTensor<Derived, DIMS> &a) {
|
||||
return internal::new_extractor_perm<Index_I>::permutation_impl(a);
|
||||
}
|
||||
|
||||
template<class Index_I, typename Derived, size_t DIMS,
|
||||
enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
|
||||
FASTOR_INLINE
|
||||
typename internal::new_permute_impl<Index_I,
|
||||
typename Derived::result_type,
|
||||
typename std_ext::make_index_sequence<DIMS>::type>::resulting_tensor
|
||||
permute(const AbstractTensor<Derived, DIMS> &a) {
|
||||
using result_type = typename Derived::result_type;
|
||||
const result_type tmp(a);
|
||||
return internal::new_extractor_perm<Index_I>::permutation_impl(tmp);
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace Fastor
|
||||
|
||||
#endif // PERMUTE_H
|
||||
293
noarch/include/Fastor/tensor_algebra/strided_contraction.h
Normal file
293
noarch/include/Fastor/tensor_algebra/strided_contraction.h
Normal file
@@ -0,0 +1,293 @@
|
||||
#ifndef REDUCIBLE_CONTRACTION_H
|
||||
#define REDUCIBLE_CONTRACTION_H
|
||||
|
||||
#include "Fastor/tensor/Tensor.h"
|
||||
#include "Fastor/tensor_algebra/indicial.h"
|
||||
|
||||
|
||||
namespace Fastor {
|
||||
|
||||
// Broadcast-vectorisable contractions (if last dimension is contracted).
|
||||
// Requres working on general strides
|
||||
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
struct extractor_reducible_contract {};
|
||||
|
||||
template<size_t ... Idx0, size_t ... Idx1>
|
||||
struct extractor_reducible_contract<Index<Idx0...>, Index<Idx1...>> {
|
||||
|
||||
|
||||
#if CONTRACT_OPT==2
|
||||
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::type
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
|
||||
static_assert(!is_pair_reduction_v<Index<Idx0...>,Index<Idx1...>>,"REDUCTION TO SCALAR REQUESTED. USE REDUCTION FUNCTION INSTEAD");
|
||||
|
||||
constexpr int total = 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>::value;
|
||||
|
||||
using index_generator = contract_meta_engine<Index<Idx0...>,Index<Idx1...>,Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<total>::type>;
|
||||
|
||||
using OutTensor = typename index_generator::OutTensor;
|
||||
using OutIndices = typename index_generator::OutIndices;
|
||||
|
||||
constexpr auto& index_a = index_generator::index_a;
|
||||
constexpr auto& index_b = index_generator::index_b;
|
||||
constexpr auto& index_out = index_generator::index_out;
|
||||
|
||||
OutTensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
// Check for reducible vectorisability
|
||||
constexpr int general_stride = general_stride_finder<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>, typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::value;
|
||||
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_reducibly_vectorisable<OutIndices,OutTensor>;
|
||||
constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
constexpr int stride = 1;
|
||||
using V = SIMDVector<T,sizeof(T)*8>;
|
||||
#endif
|
||||
|
||||
V _vec_a, _vec_b;
|
||||
for (int i = 0; i < total; i+=stride) {
|
||||
_vec_a.set(*(a_data+index_a[i]));
|
||||
const auto idx_b = index_b[i];
|
||||
vector_setter(_vec_b, b_data, idx_b, general_stride);
|
||||
V _vec_out = _vec_a*_vec_b + V(out_data+index_out[i]);
|
||||
_vec_out.store(out_data+index_out[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#elif CONTRACT_OPT==1
|
||||
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::type
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
|
||||
static_assert(!is_pair_reduction_v<Index<Idx0...>,Index<Idx1...>>,"REDUCTION TO SCALAR REQUESTED. USE REDUCTION FUNCTION INSTEAD");
|
||||
|
||||
using OutTensor = typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::type;
|
||||
using OutIndices = typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
OutTensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr int a_dim = sizeof...(Rest0);
|
||||
constexpr int b_dim = sizeof...(Rest1);
|
||||
|
||||
constexpr auto& idx_a = IndexFirstTensor<Index<Idx0...>,Index<Idx1...>, Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
constexpr auto& idx_b = IndexSecondTensor<Index<Idx0...>,Index<Idx1...>, Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::indices;
|
||||
constexpr auto& idx_out = IndexResultingTensor<Index<Idx0...>,Index<Idx1...>, Tensor<T,Rest0...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<OutTensor::Dimension>::type>::indices;
|
||||
|
||||
constexpr int total = 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>::value;
|
||||
|
||||
using maxes_out_type = 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;
|
||||
|
||||
constexpr auto& as_all = cartesian_product<maxes_out_type,typename std_ext::make_index_sequence<total>::type>::values;
|
||||
|
||||
constexpr std::array<size_t,a_dim> products_a = nprods<Index<Rest0...>,typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr std::array<size_t,b_dim> products_b = nprods<Index<Rest1...>,typename std_ext::make_index_sequence<b_dim>::type>::values;
|
||||
using Index_with_dims = typename put_dims_in_Index<OutTensor>::type;
|
||||
constexpr std::array<size_t,Index_with_dims::NoIndices> products_out = nprods<Index_with_dims,
|
||||
typename std_ext::make_index_sequence<Index_with_dims::NoIndices>::type>::values;
|
||||
|
||||
|
||||
// Check for reducible vectorisability
|
||||
constexpr int general_stride = general_stride_finder<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>, typename std_ext::make_index_sequence<b_dim>::type>::value;
|
||||
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_reducibly_vectorisable<OutIndices,OutTensor>;
|
||||
constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
constexpr int stride = 1;
|
||||
using V = SIMDVector<T,sizeof(T)*8>;
|
||||
#endif
|
||||
|
||||
int it;
|
||||
V _vec_a, _vec_b;
|
||||
|
||||
for (int i = 0; i < total; i+=stride) {
|
||||
int index_a = as_all[i][idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as_all[i][idx_a[it]];
|
||||
}
|
||||
|
||||
int index_b = as_all[i][idx_b[b_dim-1]];
|
||||
for(it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as_all[i][idx_b[it]];
|
||||
}
|
||||
int index_out = as_all[i][idx_out[idx_out.size()-1]];
|
||||
for(it = 0; it< idx_out.size(); it++) {
|
||||
index_out += products_out[it]*as_all[i][idx_out[it]];
|
||||
}
|
||||
|
||||
_vec_a.set(*(a_data+index_a));
|
||||
// _vec_b.set(b_data[index_b+3*general_stride], b_data[index_b+2*general_stride],
|
||||
// b_data[index_b+general_stride],b_data[index_b]);
|
||||
vector_setter(_vec_b, b_data, index_b, general_stride);
|
||||
V _vec_out = _vec_a*_vec_b + V(out_data+index_out);
|
||||
_vec_out.store(out_data+index_out);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
template<typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
static
|
||||
typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::type
|
||||
contract_impl(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b) {
|
||||
|
||||
static_assert(!is_pair_reduction_v<Index<Idx0...>,Index<Idx1...>>,"REDUCTION TO SCALAR REQUESTED. USE REDUCTION FUNCTION INSTEAD");
|
||||
|
||||
using OutTensor = typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::type;
|
||||
using OutIndice = typename contraction_impl<Index<Idx0...,Idx1...>, Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)+sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
OutTensor out;
|
||||
out.zeros();
|
||||
const T *a_data = a.data();
|
||||
const T *b_data = b.data();
|
||||
T *out_data = out.data();
|
||||
|
||||
constexpr int a_dim = sizeof...(Rest0);
|
||||
constexpr int b_dim = sizeof...(Rest1);
|
||||
constexpr int out_dim = no_of_unique<Idx0...,Idx1...>::value;
|
||||
|
||||
constexpr auto& idx_a = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx0...>,Tensor<T,Rest0...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest0)>::type>::indices;
|
||||
|
||||
constexpr auto& idx_b = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
Index<Idx1...>,Tensor<T,Rest1...>,
|
||||
typename std_ext::make_index_sequence<sizeof...(Rest1)>::type>::indices;
|
||||
|
||||
constexpr auto& idx_out = IndexTensors<
|
||||
Index<Idx0..., Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
OutIndice,OutTensor,
|
||||
typename std_ext::make_index_sequence<OutTensor::Dimension>::type>::indices;
|
||||
|
||||
using nloops = loop_setter<
|
||||
Index<Idx0...,Idx1...>,
|
||||
Tensor<T,Rest0...,Rest1...>,
|
||||
typename std_ext::make_index_sequence<out_dim>::type>;
|
||||
constexpr auto& maxes_out = nloops::dims;
|
||||
constexpr int total = nloops::value;
|
||||
|
||||
constexpr std::array<size_t,a_dim> products_a = nprods<Index<Rest0...>,typename std_ext::make_index_sequence<a_dim>::type>::values;
|
||||
constexpr std::array<size_t,b_dim> products_b = nprods<Index<Rest1...>,typename std_ext::make_index_sequence<b_dim>::type>::values;
|
||||
|
||||
using Index_with_dims = typename put_dims_in_Index<OutTensor>::type;
|
||||
constexpr std::array<size_t,OutTensor::Dimension> products_out = \
|
||||
nprods<Index_with_dims,typename std_ext::make_index_sequence<OutTensor::Dimension>::type>::values;
|
||||
|
||||
// Check for reducible vectorisability
|
||||
constexpr int general_stride = general_stride_finder<Index<Idx0...>,Index<Idx1...>,
|
||||
Tensor<T,Rest0...>,Tensor<T,Rest1...>, typename std_ext::make_index_sequence<b_dim>::type>::value;
|
||||
|
||||
#ifndef FASTOR_DONT_VECTORISE
|
||||
using vectorisability = is_reducibly_vectorisable<OutIndice,OutTensor>;
|
||||
constexpr int stride = vectorisability::stride;
|
||||
using V = typename vectorisability::type;
|
||||
#else
|
||||
constexpr int stride = 1;
|
||||
using V = SIMDVector<T,simd_abi::scalar>;
|
||||
#endif
|
||||
|
||||
int as[out_dim];
|
||||
std::fill(as,as+out_dim,0);
|
||||
|
||||
int it;
|
||||
V _vec_a, _vec_b;
|
||||
|
||||
for (int i = 0; i < total; i+=stride) {
|
||||
int remaining = total;
|
||||
for (int n = 0; n < out_dim; ++n) {
|
||||
remaining /= maxes_out[n];
|
||||
as[n] = ( i / remaining ) % maxes_out[n];
|
||||
}
|
||||
|
||||
int index_a = as[idx_a[a_dim-1]];
|
||||
for(it = 0; it< a_dim; it++) {
|
||||
index_a += products_a[it]*as[idx_a[it]];
|
||||
}
|
||||
int index_b = as[idx_b[b_dim-1]];
|
||||
for(it = 0; it< b_dim; it++) {
|
||||
index_b += products_b[it]*as[idx_b[it]];
|
||||
}
|
||||
int index_out = as[idx_out[OutTensor::Dimension-1]];
|
||||
for(it = 0; it< static_cast<int>(OutTensor::Dimension); it++) {
|
||||
index_out += products_out[it]*as[idx_out[it]];
|
||||
}
|
||||
|
||||
// asm("#BEGIN");
|
||||
_vec_a.set(*(a_data+index_a));
|
||||
//_vec_a.broadcast(a_data+index_a);
|
||||
vector_setter(_vec_b, b_data, index_b, general_stride);
|
||||
V _vec_out = _vec_a*_vec_b + V(out_data+index_out);
|
||||
_vec_out.store(out_data+index_out);
|
||||
// asm("#END");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class Index_I, class Index_J,
|
||||
typename T, size_t ... Rest0, size_t ... Rest1>
|
||||
FASTOR_INLINE auto strided_contraction(const Tensor<T,Rest0...> &a, const Tensor<T,Rest1...> &b)
|
||||
-> decltype(extractor_reducible_contract<Index_I,Index_J>::contract_impl(a,b)) {
|
||||
return extractor_reducible_contract<Index_I,Index_J>::contract_impl(a,b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // REDUCIBLE_CONTRACTION_H
|
||||
Reference in New Issue
Block a user