Add Fastor library

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

View File

@@ -0,0 +1,33 @@
#ifndef TENSORBASE_H
#define TENSORBASE_H
#include "Fastor/config/config.h"
#include "Fastor/meta/tensor_meta.h"
namespace Fastor {
template<typename T, size_t ... Rest>
class Tensor;
template<typename T, size_t ... Rest>
class TensorMap;
template<class Derived, FASTOR_INDEX Rank>
class AbstractTensor {
public:
constexpr FASTOR_INLINE AbstractTensor() = default;
constexpr FASTOR_INLINE const Derived& self() const {return *static_cast<const Derived*>(this);}
FASTOR_INLINE Derived& self() {return *static_cast<Derived*>(this);}
static constexpr FASTOR_INDEX Dimension = Rank;
#ifndef FASTOR_DYNAMIC_MODE
static constexpr FASTOR_INDEX size() {return Derived::Size;}
#else
FASTOR_INDEX size() const {return (*static_cast<const Derived*>(this)).size();}
#endif
};
}
#endif // TENSORBASE_H

View File

@@ -0,0 +1,393 @@
#ifndef ABSTRACT_TENSOR_FUNCTIONS_H
#define ABSTRACT_TENSOR_FUNCTIONS_H
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include <limits>
namespace Fastor {
/* The implementation of the evaluate function that evaluates any expression in to a tensor
*/
//----------------------------------------------------------------------------------------------------------//
template<typename T, size_t ... Rest>
FASTOR_INLINE const Tensor<T,Rest...>& evaluate(const Tensor<T,Rest...> &src) {
return src;
}
template<class Derived, size_t DIMS>
FASTOR_INLINE typename Derived::result_type evaluate(const AbstractTensor<Derived,DIMS> &src) {
typename Derived::result_type out(src);
return out;
}
//----------------------------------------------------------------------------------------------------------//
/* IO for tensor expressions */
//----------------------------------------------------------------------------------------------------------//
template<class Expr, size_t DIM>
inline std::ostream& operator<<(std::ostream &os, const AbstractTensor<Expr,DIM> &src) {
using result_type = typename Expr::result_type;
result_type tmp(src);
print(tmp);
return os;
}
template<class Expr, size_t DIM>
inline void print(const AbstractTensor<Expr,DIM> &src) {
using result_type = typename Expr::result_type;
result_type tmp(src);
print(tmp);
}
//----------------------------------------------------------------------------------------------------------//
/* These are the set of functions that work on any expression that evaluate immediately
*/
/* Add all the elements of the tensor in a flattened sense
*/
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type sum(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out(src);
return out.sum();
}
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type sum(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
FASTOR_INDEX i;
T _scal=0; V _vec(_scal);
for (i = 0; i < ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
_vec += src.template eval<T>(i);
}
for (; i < src.size(); ++i) {
_scal += src.template eval_s<T>(i);
}
return _vec.sum() + _scal;
}
/* Multiply all the elements of the tensor in a flattened sense
*/
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type product(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out(src);
return out.product();
}
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type product(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
FASTOR_INDEX i;
T _scal=1; V _vec(_scal);
for (i = 0; i < ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
_vec *= src.template eval<T>(i);
}
for (; i < src.size(); ++i) {
_scal *= src.template eval_s<T>(i);
}
return _vec.product() * _scal;
}
/* Get minimum element of a tensor
*/
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type min(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out(src);
return min(out);
}
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type min(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
FASTOR_INDEX i;
T _scal=std::numeric_limits<T>::max(); V _vec(_scal);
for (i = 0; i < ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
_vec = min(src.template eval<T>(i),_vec);
}
for (; i < src.size(); ++i) {
_scal = std::min(src.template eval_s<T>(i),_scal);
}
return std::min(_vec.minimum(), _scal);
}
/* Get maximum element of a tensor
*/
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type max(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out(src);
return max(out);
}
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type max(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
FASTOR_INDEX i;
T _scal=std::numeric_limits<T>::min(); V _vec(_scal);
for (i = 0; i < ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
_vec = max(src.template eval<T>(i),_vec);
}
for (; i < src.size(); ++i) {
_scal = std::max(src.template eval_s<T>(i),_scal);
}
return std::max(_vec.maximum(), _scal);
}
/* Get the lower triangular matrix from a 2D expression
*/
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type tril(const AbstractTensor<Derived,DIMS> &_src, int k = 0) {
static_assert(DIMS==2,"TENSOR HAS TO BE 2D FOR TRIL");
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out(src);
return tril(out,k);
}
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::result_type tril(const AbstractTensor<Derived,DIMS> &_src, int k = 0) {
static_assert(DIMS==2,"TENSOR HAS TO BE 2D FOR TRIL");
const Derived &src = _src.self();
using T = typename Derived::scalar_type;
typename Derived::result_type out(0);
int M = int(src.dimension(0));
int N = int(src.dimension(1));
for (int i = 0; i < M; ++i) {
int jcount = k + i < N ? k + i : N - 1;
for (int j = 0; j <= jcount; ++j) {
out(i,j) = src.template eval_s<T>(i,j);
}
}
return out;
}
/* Get the upper triangular matrix from a 2D expression
*/
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type triu(const AbstractTensor<Derived,DIMS> &_src, int k = 0) {
static_assert(DIMS==2,"TENSOR HAS TO BE 2D FOR TRIU");
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out(src);
return triu(out,k);
}
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::result_type triu(const AbstractTensor<Derived,DIMS> &_src, int k = 0) {
static_assert(DIMS==2,"TENSOR HAS TO BE 2D FOR TRIU");
const Derived &src = _src.self();
using T = typename Derived::scalar_type;
typename Derived::result_type out(0);
int M = int(src.dimension(0));
int N = int(src.dimension(1));
for (int i = 0; i < M; ++i) {
int jcount = k + i < 0 ? 0 : k + i;
for (int j = jcount; j < N; ++j) {
out(i,j) = src.template eval_s<T>(i,j);
}
}
return out;
}
//----------------------------------------------------------------------------------------------------------//
// Boolean functions
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<class Derived, size_t DIMS, enable_if_t_<is_boolean_expression_v<Derived> && requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool all_of(const AbstractTensor<Derived,DIMS> &_src) {
using result_type = typename Derived::result_type;
const result_type tmp(_src.self());
return all_of(tmp);
}
template<class Derived, size_t DIMS, enable_if_t_<is_boolean_expression_v<Derived> && !requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool all_of(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
bool val = true;
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
if (src.template eval_s<bool>(i) == false) {
val = false;
break;
}
}
return val;
}
template<class Derived, size_t DIMS, enable_if_t_<is_boolean_expression_v<Derived> && requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool any_of(const AbstractTensor<Derived,DIMS> &_src) {
using result_type = typename Derived::result_type;
const result_type tmp(_src.self());
return any_of(tmp);
}
template<class Derived, size_t DIMS, enable_if_t_<is_boolean_expression_v<Derived> && !requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool any_of(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
bool val = false;
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
if (src.template eval_s<bool>(i) == true) {
val = true;
break;
}
}
return val;
}
template<class Derived, size_t DIMS, enable_if_t_<is_boolean_expression_v<Derived> && requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool none_of(const AbstractTensor<Derived,DIMS> &_src) {
using result_type = typename Derived::result_type;
const result_type tmp(_src.self());
return none_of(tmp);
}
template<class Derived, size_t DIMS, enable_if_t_<is_boolean_expression_v<Derived> && !requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool none_of(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
bool val = false;
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
if (src.template eval_s<bool>(i) == true) {
val = true;
break;
}
}
return val;
}
/* Is a second order tensor expression a uniform
A tensor expression is uniform if it spans equally in all dimensions,
i.e. generalisation of square matrix to N-dimensions
*/
template<class Derived, size_t DIMS>
constexpr FASTOR_INLINE bool isuniform(const AbstractTensor<Derived,DIMS> &_src) {
return is_tensor_uniform_v<typename Derived::result_type>;
}
/* Is a second order tensor expression a square matrix
*/
template<class Derived, size_t DIMS, enable_if_t_<DIMS==2,bool> = false>
constexpr FASTOR_INLINE bool issquare(const AbstractTensor<Derived,DIMS> &_src) {
return is_tensor_uniform_v<typename Derived::result_type>;
}
/* Is a second order tensor expression orthogonal
*/
template<class Derived, size_t DIMS, enable_if_t_<DIMS==2,bool> = false>
FASTOR_INLINE bool isorthogonal(const AbstractTensor<Derived,DIMS> &_src, const double Tol=PRECI_TOL) {
typename Derived::result_type tmp1(_src.self());
typename Derived::result_type tmp2(matmul(transpose(tmp1),tmp1));
typename Derived::result_type I; I.eye2();
return isequal(tmp2,I,Tol);
}
/* Is a tensor expression symmetric - for higher order tensor two axes can defining a plane
provided to determine if a tensor expression is symmertric in that plane
*/
template<size_t axis0 = 0, size_t axis1 = 1, class Derived, size_t DIMS,
enable_if_t_<DIMS==2 && requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool issymmetric(const AbstractTensor<Derived,DIMS> &_src, const double Tol=PRECI_TOL) {
if (!issquare(_src.self())) return false;
return all_of( abs(evaluate(trans(_src.self()) - _src.self())) < Tol);
}
template<size_t axis0 = 0, size_t axis1 = 1, class Derived, size_t DIMS,
enable_if_t_<DIMS==2 && !requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE bool issymmetric(const AbstractTensor<Derived,DIMS> &_src, const double Tol=PRECI_TOL) {
if (!issquare(_src.self())) return false;
// Avoid copies
const Derived& src = _src.self();
using T = typename Derived::scalar_type;
using result_type = typename Derived::result_type;
constexpr size_t M = get_tensor_dimension_v<0,result_type>;
constexpr size_t N = get_tensor_dimension_v<1,result_type>;
bool _issym = true;
for (size_t i=0; i<M; ++i) {
for (size_t j=0; j<N; ++j) {
if (std::abs( src.template eval_s<T>(i*N+j) - src.template eval_s<T>(j*N+i) ) > Tol ) {
_issym = false;
break;
}
}
}
return _issym;
}
/* Is a second order tensor expression deviatoric - a 2D tensor expression is deviatoric if it is
trace free
*/
template<class Derived, size_t DIMS, enable_if_t_<DIMS==2,bool> = false>
constexpr FASTOR_INLINE bool isdeviatoric(const AbstractTensor<Derived,DIMS> &_src, const double Tol=PRECI_TOL) {
return std::abs( trace(_src.self()) ) < Tol ? true : false;
}
/* Is a second order tensor expression volumetric - a 2D tensor expression is volumetric if 1/3*[A:I]*I = A
*/
template<class Derived, size_t DIMS, enable_if_t_<DIMS==2,bool> = false>
constexpr FASTOR_INLINE bool isvolumetric(const AbstractTensor<Derived,DIMS> &_src, const double Tol=PRECI_TOL) {
typename Derived::result_type I; I.eye2();
typename Derived::result_type tmp = trace(_src.self()) * I;
return all_of( abs(tmp - _src.self()) < Tol);
}
/* A second order tensor expression belongs to the special linear group if
it's determinant is +1
*/
template<class Derived, size_t DIMS, enable_if_t_<DIMS==2,bool> = false>
FASTOR_INLINE bool doesbelongtoSL3(const AbstractTensor<Derived,DIMS> &_src, const double Tol=PRECI_TOL) {
// Expression must be square
if ( !issquare(_src.self()) ) return false;
return std::abs(determinant(_src.self()) - 1) < Tol ? true : false;
}
/* A second order tensor/expression belongs to the special orthogonal group if
it is orthogonal and it's determinant is +1
*/
template<class Derived, size_t DIMS, enable_if_t_<DIMS==2,bool> = false>
FASTOR_INLINE bool doesbelongtoSO3(const AbstractTensor<Derived,DIMS> &_src, const double Tol=PRECI_TOL) {
// Expression must be square and orthogonal
return issquare(_src.self()) && isorthogonal(_src.self()) ? true : false;
}
/* Are two tensor expressions approximately equal
*/
template<class Derived0, size_t DIMS0, class Derived1, size_t DIMS1,
enable_if_t_<!requires_evaluation_v<Derived0> && !requires_evaluation_v<Derived1>,bool> = false>
FASTOR_INLINE bool isequal(
const AbstractTensor<Derived0,DIMS0> &_src0,
const AbstractTensor<Derived1,DIMS1> &_src1,
const double Tol=PRECI_TOL) {
if ( DIMS0 != DIMS1) return false;
if ( _src0.self().size() != _src1.self().size()) return false;
return all_of( abs(_src0.self() - _src1.self()) < Tol);
}
template<class Derived0, size_t DIMS0, class Derived1, size_t DIMS1,
enable_if_t_<requires_evaluation_v<Derived0> || requires_evaluation_v<Derived1>,bool> = false>
FASTOR_INLINE bool isequal(
const AbstractTensor<Derived0,DIMS0> &_src0,
const AbstractTensor<Derived1,DIMS1> &_src1,
const double Tol=PRECI_TOL) {
if ( DIMS0 != DIMS1) return false;
if ( _src0.self().size() != _src1.self().size()) return false;
return all_of( abs(evaluate(_src0.self() - _src1.self())) < Tol);
}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
} // end of namespace Fastor
#endif // #ifndef TENSOR_FUNCTIONS_H

View File

@@ -0,0 +1,67 @@
#ifndef ALIASING_H_
#define ALIASING_H_
#include "Fastor/tensor/ForwardDeclare.h"
#include "Fastor/tensor/Tensor.h"
namespace Fastor {
// template<typename T, size_t ...Rest0, size_t ... Rest1>
// FASTOR_INLINE bool does_alias(const Tensor<T,Rest0...> &dst, const Tensor<T,Rest1...> &src) {
// return dst.data() == src.data() ? true : false;
// }
template<typename Derived, size_t DIM, typename T, size_t ... Rest>
FASTOR_INLINE bool does_alias(const AbstractTensor<Derived,DIM> &dst, const Tensor<T,Rest...> &src) {
return dst.self().data() == src.data() ? true : false;
}
// template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM>
// FASTOR_INLINE bool does_alias(const AbstractTensor<Derived,DIM> &dst, const AbstractTensor<OtherDerived,OtherDIM> &src) {
// return does_alias(dst.self(),src.self());
// }
#define FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(NAME)\
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM>\
FASTOR_INLINE bool does_alias(const AbstractTensor<Derived,DIM> &dst, const Unary ##NAME ## Op<OtherDerived,OtherDIM> &src) {\
return does_alias(dst.self(),src.expr().self());\
}\
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Add )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Sub )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Abs )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Sqrt)
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Exp )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Log )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Sin )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Cos )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Tan )
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Asin)
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Acos)
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Atan)
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Sinh)
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Cosh)
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Tanh)
// FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Det )
// FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Norm)
// FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Trace)
FASTOR_MAKE_ALIAS_FUNC_UNARY_OPS(Trans)
#define FASTOR_MAKE_ALIAS_FUNC_BINARY_OPS(NAME)\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM>\
FASTOR_INLINE bool does_alias(const AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs,TRhs,OtherDIM> &src) {\
return does_alias(dst.self(),src.lhs().self()) || does_alias(dst.self(),src.rhs().self());\
}\
FASTOR_MAKE_ALIAS_FUNC_BINARY_OPS(Add)
FASTOR_MAKE_ALIAS_FUNC_BINARY_OPS(Sub)
FASTOR_MAKE_ALIAS_FUNC_BINARY_OPS(Mul)
FASTOR_MAKE_ALIAS_FUNC_BINARY_OPS(Div)
FASTOR_MAKE_ALIAS_FUNC_BINARY_OPS(MatMul)
}
#endif // ALIASING_H_

View File

@@ -0,0 +1,502 @@
#ifndef BLOCK_INDEXING_H
#define BLOCK_INDEXING_H
//----------------------------------------------------------------------------------------------------------//
// Block indexing
//----------------------------------------------------------------------------------------------------------//
// Calls scalar indexing so they are fully bounds checked.
template<size_t F, size_t L, size_t S>
FASTOR_INLINE Tensor<T,range_detector<F,L,S>::value> operator()(const iseq<F,L,S>& idx) {
static_assert(1==dimension_t::value, "INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<T,range_detector<F,L,S>::value> out;
FASTOR_INDEX counter = 0;
for (FASTOR_INDEX i=F; i<L; i+=S) {
out(counter) = this->operator()(i);
counter++;
}
return out;
}
template<size_t F0, size_t L0, size_t S0, size_t F1, size_t L1, size_t S1>
FASTOR_INLINE Tensor<T,range_detector<F0,L0,S0>::value,range_detector<F1,L1,S1>::value>
operator()(iseq<F0,L0,S0>, iseq<F1,L1,S1>) {
static_assert(2==dimension_t::value, "INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<T,range_detector<F0,L0,S0>::value,range_detector<F1,L1,S1>::value> out;
FASTOR_INDEX counter_i = 0;
for (FASTOR_INDEX i=F0; i<L0; i+=S0) {
FASTOR_INDEX counter_j = 0;
for (FASTOR_INDEX j=F1; j<L1; j+=S1) {
out(counter_i,counter_j) = this->operator()(i,j);
counter_j++;
}
counter_i++;
}
return out;
}
template<size_t F0, size_t L0, size_t S0, size_t F1, size_t L1, size_t S1, size_t F2, size_t L2, size_t S2>
FASTOR_INLINE Tensor<T,range_detector<F0,L0,S0>::value,range_detector<F1,L1,S1>::value,range_detector<F2,L2,S2>::value>
operator()(iseq<F0,L0,S0>, iseq<F1,L1,S1>, iseq<F2,L2,S2>) const {
static_assert(3==dimension_t::value, "INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<T,range_detector<F0,L0,S0>::value,
range_detector<F1,L1,S1>::value,
range_detector<F2,L2,S2>::value> out;
FASTOR_INDEX counter_i = 0;
for (FASTOR_INDEX i=F0; i<L0; i+=S0) {
FASTOR_INDEX counter_j = 0;
for (FASTOR_INDEX j=F1; j<L1; j+=S1) {
FASTOR_INDEX counter_k = 0;
for (FASTOR_INDEX k=F2; k<L2; k+=S2) {
out(counter_i,counter_j,counter_k) = this->operator()(i,j,k);
counter_k++;
}
counter_j++;
}
counter_i++;
}
return out;
}
template<size_t F0, size_t L0, size_t S0,
size_t F1, size_t L1, size_t S1,
size_t F2, size_t L2, size_t S2,
size_t F3, size_t L3, size_t S3>
FASTOR_INLINE Tensor<T,range_detector<F0,L0,S0>::value,
range_detector<F1,L1,S1>::value,
range_detector<F2,L2,S2>::value,
range_detector<F3,L3,S3>::value>
operator ()(iseq<F0,L0,S0>, iseq<F1,L1,S1>,
iseq<F2,L2,S2>, iseq<F3,L3,S3>) {
static_assert(4==dimension_t::value, "INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<T,range_detector<F0,L0,S0>::value,
range_detector<F1,L1,S1>::value,
range_detector<F2,L2,S2>::value,
range_detector<F3,L3,S3>::value> out;
FASTOR_INDEX counter_i = 0;
for (FASTOR_INDEX i=F0; i<L0; i+=S0) {
FASTOR_INDEX counter_j = 0;
for (FASTOR_INDEX j=F1; j<L1; j+=S1) {
FASTOR_INDEX counter_k = 0;
for (FASTOR_INDEX k=F2; k<L2; k+=S2) {
FASTOR_INDEX counter_l = 0;
for (FASTOR_INDEX l=F3; l<L3; l+=S3) {
out(counter_i,counter_j,counter_k,counter_l) = this->operator()(i,j,k,l);
counter_l++;
}
counter_k++;
}
counter_j++;
}
counter_i++;
}
return out;
}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,1> operator()(seq _s) {
static_assert(dimension_t::value==1,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,1>(*this,_s);
}
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2> operator()(seq _s0, seq _s1) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,2>(*this,_s0,_s1);
}
template<int F0, int L0, int S0>
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2>
operator()(fseq<F0,L0,S0> _s0, seq _s1) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,2>(*this,_s0,_s1);
}
template<int F0, int L0, int S0>
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2>
operator()(seq _s0, fseq<F0,L0,S0> _s1) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,2>(*this,_s0,_s1);
}
template<typename Int, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2> operator()(seq _s0, Int num) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,2>(*this,_s0,seq(num));
}
template<typename Int, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2> operator()(Int num, seq _s1) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,2>(*this,seq(num),_s1);
}
template<typename ... Seq, enable_if_t_<!is_arithmetic_pack_v<Seq...> && !is_fixed_sequence_pack_v<Seq...>,bool> = false>
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,sizeof...(Seq)> operator()(Seq ... _seqs) {
static_assert(dimension_t::value==sizeof...(Seq),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,sizeof...(Seq)>(*this, {_seqs...});
}
template<typename ...Fseq, enable_if_t_<is_fixed_sequence_pack_v<Fseq...>,bool> = false>
FASTOR_INLINE TensorFixedViewExprnD<Tensor<T,Rest...>,Fseq...> operator()(Fseq... ) {
static_assert(dimension_t::value==sizeof...(Fseq),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorFixedViewExprnD<Tensor<T,Rest...>,Fseq...>(*this);
}
// if fseq == fall - then just return a reference to the tensor
template<int F0, int L0, int S0,
typename std::enable_if<
internal::fseq_range_detector<typename to_positive<fseq<F0,L0,S0>,
get_value<1,Rest...>::value>::type>::value == get_value<1,Rest...>::value,
bool>::type =0>
FASTOR_INLINE Tensor<T,Rest...>&
operator()(fseq<F0,L0,S0>) {
static_assert(dimension_t::value==1,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return (*this);
}
// if fseq != fall - return a view
template<int F0, int L0, int S0,
typename std::enable_if<
internal::fseq_range_detector<typename to_positive<fseq<F0,L0,S0>,
get_value<1,Rest...>::value>::type>::value != get_value<1,Rest...>::value,
bool>::type =0>
FASTOR_INLINE TensorFixedViewExpr1D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,pack_prod<Rest...>::value>::type,1>
operator()(fseq<F0,L0,S0>) {
static_assert(dimension_t::value==1,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorFixedViewExpr1D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,pack_prod<Rest...>::value>::type,1>(*this);
}
// if fseq == fall - then just return a reference to the tensor
template<int F0, int L0, int S0, int F1, int L1, int S1,
typename std::enable_if<
internal::fseq_range_detector<typename to_positive<fseq<F0,L0,S0>,get_value<1,Rest...>::value>::type>::value == get_value<1,Rest...>::value &&
internal::fseq_range_detector<typename to_positive<fseq<F1,L1,S1>,get_value<2,Rest...>::value>::type>::value == get_value<2,Rest...>::value,
bool>::type =0>
FASTOR_INLINE Tensor<T,Rest...>&
operator()(fseq<F0,L0,S0>, fseq<F1,L1,S1>) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return (*this);
}
// if fseq != fall - return a view
template<int F0, int L0, int S0, int F1, int L1, int S1,
typename std::enable_if<
internal::fseq_range_detector<typename to_positive<fseq<F0,L0,S0>,get_value<1,Rest...>::value>::type>::value != get_value<1,Rest...>::value ||
internal::fseq_range_detector<typename to_positive<fseq<F1,L1,S1>,get_value<2,Rest...>::value>::type>::value != get_value<2,Rest...>::value,
bool>::type =0>
FASTOR_INLINE TensorFixedViewExpr2D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,get_value<1,Rest...>::value>::type,
typename to_positive<fseq<F1,L1,S1>,get_value<2,Rest...>::value>::type,2>
operator()(fseq<F0,L0,S0>, fseq<F1,L1,S1>) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorFixedViewExpr2D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,get_value<1,Rest...>::value>::type,
typename to_positive<fseq<F1,L1,S1>,get_value<2,Rest...>::value>::type,2>(*this);
}
template<int F0, int L0, int S0, typename Int, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2> operator()(fseq<F0,L0,S0> _s, Int num) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,2>(*this,seq(_s),seq(num));
}
template<int F0, int L0, int S0, typename Int,
typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2> operator()(Int num, fseq<F0,L0,S0> _s) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<Tensor<T,Rest...>,2>(*this,seq(num),seq(_s));
}
// Selecting a row and returning a TensorMap - does not seem to speed up the code
//----------------------------------------------------------------------------------------------------------//
// template<int F0, int L0, int S0, typename Int,
// typename std::enable_if<std::is_integral<Int>::value &&
// internal::fseq_range_detector<typename to_positive<fseq<F0,L0,S0>,
// get_value<2,Rest...>::value>::type>::value != get_value<2,Rest...>::value,bool>::type=0>
// FASTOR_INLINE TensorViewExpr<Tensor<T,Rest...>,2> operator()(Int num, fseq<F0,L0,S0> _s) {
// static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
// return TensorViewExpr<Tensor<T,Rest...>,2>(*this,seq(num),seq(_s));
// }
// // Selecting a row from a 2D tensor returns a TensorMap
// template<typename Int, int F0, int L0, int S0,
// typename std::enable_if<std::is_integral<Int>::value &&
// internal::fseq_range_detector<typename to_positive<fseq<F0,L0,S0>,
// get_value<2,Rest...>::value>::type>::value == get_value<2,Rest...>::value,bool>::type=0>
// FASTOR_INLINE TensorMap<T,get_value<2,Rest...>::value> operator()(Int num, fseq<F0,L0,S0> _s) {
// static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
// constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
// return TensorMap<T,N>(&_data[num*N]);
// }
//----------------------------------------------------------------------------------------------------------//
template<typename Int, size_t N, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,N>,1> operator()(const Tensor<Int,N> &_it) {
static_assert(dimension_t::value==1,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,N>,1>(*this,_it);
}
template<typename Int, size_t ... IterSizes, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,IterSizes...>,sizeof...(Rest)>
operator()(const Tensor<Int,IterSizes...> &_it) {
static_assert(dimension_t::value==sizeof...(IterSizes),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,IterSizes...>,sizeof...(Rest)>(*this,_it);
}
template<typename Int0, typename Int1, size_t M, size_t N,
typename std::enable_if<std::is_integral<Int0>::value && std::is_integral<Int1>::value,bool>::type=0>
FASTOR_INLINE TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,N>,2>
operator()(const Tensor<Int0,M> &_it0, const Tensor<Int1,N> &_it1) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<Int0,M,N> tmp_it;
constexpr int NCols = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i<M; ++i) {
for (FASTOR_INDEX j=0; j<N; ++j) {
tmp_it(i,j) = _it0(i)*NCols + _it1(j);
}
}
return TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,N>,2>(*this,tmp_it);
}
template<typename Int0, typename Int1, size_t M,
typename std::enable_if<std::is_integral<Int0>::value && std::is_integral<Int1>::value,bool>::type=0>
FASTOR_INLINE TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>
operator()(const Tensor<Int0,M> &_it0, Int1 num) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<Int0,M,1> tmp_it;
constexpr int NCols = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i<M; ++i) {
tmp_it(i,0) = _it0(i)*NCols + num;
}
return TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>(*this,tmp_it);
}
template<typename Int0, typename Int1, size_t M,
typename std::enable_if<std::is_integral<Int0>::value && std::is_integral<Int1>::value,bool>::type=0>
FASTOR_INLINE TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>
operator()(Int1 num, const Tensor<Int0,M> &_it0) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<Int0,M,1> tmp_it;
constexpr int NCols = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i<M; ++i) {
tmp_it(i,0) = num*NCols + _it0(i);
}
return TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>(*this,tmp_it);
}
template<typename Int, size_t M, int F, int L, int S,
typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,M,
to_positive<fseq<F,L,S>,get_value<2,Rest...>::value>::type::Size>,2>
operator()(const Tensor<Int,M> &_it0, fseq<F,L,S>) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
constexpr int NCols = get_value<2,Rest...>::value;
using _seq = typename to_positive<fseq<F,L,S>,NCols>::type;
constexpr int ColSize = _seq::Size;
Tensor<Int,M,ColSize> tmp_it;
for (FASTOR_INDEX i = 0; i<M; ++i) {
for (FASTOR_INDEX j=0; j<ColSize; ++j) {
tmp_it(i,j) = _it0(i)*NCols + _seq::_step*j + _seq::_first;
}
}
return TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,M,
to_positive<fseq<F,L,S>,get_value<2,Rest...>::value>::type::Size>,2> (*this,tmp_it);
}
template<typename Int, size_t N, int F, int L, int S,
typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,
to_positive<fseq<F,L,S>,get_value<1,Rest...>::value>::type::Size,N>,2>
operator()(fseq<F,L,S>, const Tensor<Int,N> &_it0) {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
constexpr int NRows = get_value<1,Rest...>::value;
constexpr int NCols = get_value<2,Rest...>::value;
using _seq = typename to_positive<fseq<F,L,S>,NRows>::type;
constexpr int RowSize = _seq::Size;
Tensor<Int,RowSize,N> tmp_it;
for (FASTOR_INDEX i = 0; i<RowSize; ++i) {
for (FASTOR_INDEX j=0; j<N; ++j) {
tmp_it(i,j) = (_seq::_step*i + _seq::_first)*NCols + _it0(j);
}
}
return TensorRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,
to_positive<fseq<F,L,S>,get_value<1,Rest...>::value>::type::Size,N>,2> (*this,tmp_it);
}
//----------------------------------------------------------------------------------------------------------//
// Filter views
FASTOR_INLINE TensorFilterViewExpr<Tensor<T,Rest...>,Tensor<bool,Rest...>,sizeof...(Rest)>
operator()(const Tensor<bool,Rest...> &_fl) {
return TensorFilterViewExpr<Tensor<T,Rest...>,Tensor<bool,Rest...>,sizeof...(Rest)>(*this,_fl);
}
FASTOR_INLINE TensorFilterViewExpr<Tensor<T,Rest...>,TensorMap<bool,Rest...>,sizeof...(Rest)>
operator()(const TensorMap<bool,Rest...> &_fl) {
return TensorFilterViewExpr<Tensor<T,Rest...>,TensorMap<bool,Rest...>,sizeof...(Rest)>(*this,_fl);
}
//----------------------------------------------------------------------------------------------------------//
FASTOR_INLINE TensorConstViewExpr<Tensor<T,Rest...>,1> operator()(seq _s) const {
static_assert(dimension_t::value==1,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstViewExpr<Tensor<T,Rest...>,1>(*this,_s);
}
FASTOR_INLINE TensorConstViewExpr<Tensor<T,Rest...>,2> operator()(seq _s0, seq _s1) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstViewExpr<Tensor<T,Rest...>,2>(*this,_s0,_s1);
}
template<typename Int, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstViewExpr<Tensor<T,Rest...>,2> operator()(seq _s0, Int num) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstViewExpr<Tensor<T,Rest...>,2>(*this,_s0,seq(num));
}
template<typename Int, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstViewExpr<Tensor<T,Rest...>,2> operator()(Int num, seq _s1) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstViewExpr<Tensor<T,Rest...>,2>(*this,seq(num),_s1);
}
template<typename ... Seq, enable_if_t_<!is_arithmetic_pack_v<Seq...> && !is_fixed_sequence_pack_v<Seq...>,bool> = false>
FASTOR_INLINE TensorConstViewExpr<Tensor<T,Rest...>,sizeof...(Seq)> operator()(Seq ... _seqs) const {
static_assert(dimension_t::value==sizeof...(Seq),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstViewExpr<Tensor<T,Rest...>,sizeof...(Seq)>(*this, {_seqs...});
}
template<typename ...Fseq, enable_if_t_<is_fixed_sequence_pack_v<Fseq...>,bool> = false>
FASTOR_INLINE TensorConstFixedViewExprnD<Tensor<T,Rest...>,Fseq...> operator()(Fseq... ) const {
static_assert(dimension_t::value==sizeof...(Fseq),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstFixedViewExprnD<Tensor<T,Rest...>,Fseq...>(*this);
}
template<int F0, int L0, int S0>
FASTOR_INLINE TensorConstFixedViewExpr1D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,pack_prod<Rest...>::value>::type,1> operator()(fseq<F0,L0,S0>) const {
static_assert(dimension_t::value==1,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstFixedViewExpr1D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,pack_prod<Rest...>::value>::type,1>(*this);
}
template<int F0, int L0, int S0, int F1, int L1, int S1>
FASTOR_INLINE TensorConstFixedViewExpr2D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,get_value<1,Rest...>::value>::type,
typename to_positive<fseq<F1,L1,S1>,get_value<2,Rest...>::value>::type,2>
operator()(fseq<F0,L0,S0>, fseq<F1,L1,S1>) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstFixedViewExpr2D<Tensor<T,Rest...>,
typename to_positive<fseq<F0,L0,S0>,get_value<1,Rest...>::value>::type,
typename to_positive<fseq<F1,L1,S1>,get_value<2,Rest...>::value>::type,2>(*this);
}
template<int F0, int L0, int S0, typename Int, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstViewExpr<Tensor<T,Rest...>,2> operator()(fseq<F0,L0,S0> _s, Int num) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstViewExpr<Tensor<T,Rest...>,2>(*this,seq(_s),seq(num));
}
template<int F0, int L0, int S0, typename Int, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstViewExpr<Tensor<T,Rest...>,2> operator()(Int num, fseq<F0,L0,S0> _s) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstViewExpr<Tensor<T,Rest...>,2>(*this,seq(num),seq(_s));
}
template<typename Int, size_t N, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,N>,1>
operator()(const Tensor<Int,N> &_it) const {
static_assert(dimension_t::value==1,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,N>,1>(*this,_it);
}
template<typename Int, size_t ... IterSizes, typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,IterSizes...>,sizeof...(Rest)>
operator()(const Tensor<Int,IterSizes...> &_it) const {
static_assert(dimension_t::value==sizeof...(IterSizes),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,IterSizes...>,sizeof...(Rest)>(*this,_it);
}
template<typename Int0, typename Int1, size_t M, size_t N,
typename std::enable_if<std::is_integral<Int0>::value && std::is_integral<Int1>::value,bool>::type=0>
FASTOR_INLINE TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,N>,2>
operator()(const Tensor<Int0,M> &_it0, const Tensor<Int1,N> &_it1) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<Int0,M,N> tmp_it;
constexpr int NCols = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i<M; ++i) {
for (FASTOR_INDEX j=0; j<N; ++j) {
tmp_it(i,j) = _it0(i)*NCols + _it1(j);
}
}
return TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,N>,2>(*this,tmp_it);
}
template<typename Int0, typename Int1, size_t M,
typename std::enable_if<std::is_integral<Int0>::value && std::is_integral<Int1>::value,bool>::type=0>
FASTOR_INLINE TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>
operator()(const Tensor<Int0,M> &_it0, Int1 num) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<Int0,M,1> tmp_it;
constexpr int NCols = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i<M; ++i) {
tmp_it(i,0) = _it0(i)*NCols + num;
}
return TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>(*this,tmp_it);
}
template<typename Int0, typename Int1, size_t M,
typename std::enable_if<std::is_integral<Int0>::value && std::is_integral<Int1>::value,bool>::type=0>
FASTOR_INLINE TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>
operator()(Int1 num, const Tensor<Int0,M> &_it0) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
Tensor<Int0,M,1> tmp_it;
constexpr int NCols = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i<M; ++i) {
tmp_it(i,0) = num*NCols + _it0(i);
}
return TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int0,M,1>,2>(*this,tmp_it);
}
template<typename Int, size_t M, int F, int L, int S,
typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,M,
to_positive<fseq<F,L,S>,get_value<2,Rest...>::value>::type::Size>,2>
operator()(const Tensor<Int,M> &_it0, fseq<F,L,S>) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
constexpr int NCols = get_value<2,Rest...>::value;
using _seq = typename to_positive<fseq<F,L,S>,NCols>::type;
constexpr int ColSize = _seq::Size;
Tensor<Int,M,ColSize> tmp_it;
for (FASTOR_INDEX i = 0; i<M; ++i) {
for (FASTOR_INDEX j=0; j<ColSize; ++j) {
tmp_it(i,j) = _it0(i)*NCols + _seq::_step*j + _seq::_first;
}
}
return TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,M,
to_positive<fseq<F,L,S>,get_value<2,Rest...>::value>::type::Size>,2> (*this,tmp_it);
}
template<typename Int, size_t N, int F, int L, int S,
typename std::enable_if<std::is_integral<Int>::value,bool>::type=0>
FASTOR_INLINE TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,
to_positive<fseq<F,L,S>,get_value<1,Rest...>::value>::type::Size,N>,2>
operator()(fseq<F,L,S>, const Tensor<Int,N> &_it0) const {
static_assert(dimension_t::value==2,"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
constexpr int NRows = get_value<1,Rest...>::value;
constexpr int NCols = get_value<2,Rest...>::value;
using _seq = typename to_positive<fseq<F,L,S>,NRows>::type;
constexpr int RowSize = _seq::Size;
Tensor<Int,RowSize,N> tmp_it;
for (FASTOR_INDEX i = 0; i<RowSize; ++i) {
for (FASTOR_INDEX j=0; j<N; ++j) {
tmp_it(i,j) = (_seq::_step*i + _seq::_first)*NCols + _it0(j);
}
}
return TensorConstRandomViewExpr<Tensor<T,Rest...>,Tensor<Int,
to_positive<fseq<F,L,S>,get_value<1,Rest...>::value>::type::Size,N>,2> (*this,tmp_it);
}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
#endif // BLOCK_INDEXING_H

View File

@@ -0,0 +1,154 @@
#ifndef FORWARD_DECLARE_H
#define FORWARD_DECLARE_H
namespace Fastor {
// FORWARD DECLARATIONS
//----------------------------------------------------------------
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryAddOp;
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinarySubOp;
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryMulOp;
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryDivOp;
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryMatMulOp;
template<typename Expr, size_t DIMS>
struct UnaryAddOp;
template<typename Expr, size_t DIMS>
struct UnarySubOp;
template<typename Expr, size_t DIMS>
struct UnaryAbsOp;
template<typename Expr, size_t DIMS>
struct UnarySqrtOp;
template<typename Expr, size_t DIMS>
struct UnaryExpOp;
template<typename Expr, size_t DIMS>
struct UnaryLogOp;
template<typename Expr, size_t DIMS>
struct UnarySinOp;
template<typename Expr, size_t DIMS>
struct UnaryCosOp;
template<typename Expr, size_t DIMS>
struct UnaryTanOp;
template<typename Expr, size_t DIMS>
struct UnaryAsinOp;
template<typename Expr, size_t DIMS>
struct UnaryAcosOp;
template<typename Expr, size_t DIMS>
struct UnaryAtanOp;
template<typename Expr, size_t DIMS>
struct UnarySinhOp;
template<typename Expr, size_t DIMS>
struct UnaryCoshOp;
template<typename Expr, size_t DIMS>
struct UnaryTanhOp;
template<typename Expr, size_t DIMS>
struct UnaryTransOp;
template<typename Expr, size_t DIMS>
struct TensorViewExpr;
template<typename Expr, size_t DIMS>
struct TensorConstViewExpr;
template<typename Expr, typename IterExpr, size_t DIMS>
struct TensorRandomViewExpr;
template<typename Expr, typename IterExpr, size_t DIMS>
struct TensorFilterViewExpr;
template<typename Expr, typename IterExpr, size_t DIMS>
struct TensorConstRandomViewExpr;
template<typename Expr, typename Seq0, size_t DIMS>
struct TensorFixedViewExpr1D;
template<typename Expr, typename Seq0, size_t DIMS>
struct TensorConstFixedViewExpr1D;
template<typename Expr, typename Seq0, typename Seq1, size_t DIMS>
struct TensorFixedViewExpr2D;
template<typename Expr, typename Seq0, typename Seq1, size_t DIMS>
struct TensorConstFixedViewExpr2D;
template<class TensorType, typename ... Fseqs>
struct TensorConstFixedViewExprnD;
template<class TensorType, typename ... Fseqs>
struct TensorFixedViewExprnD;
template<typename Expr, size_t DIM>
struct TensorDiagViewExpr;
template <FASTOR_INDEX ... All>
struct Index;
template<class Idx, class Seq>
struct nprods;
template<class Idx, class Seq>
struct nprods_views;
#define FASTOR_MAKE_UNARY_BOOL_OP_FORWARD_DECLARATION(NAME)\
template<typename Expr, size_t DIM0>\
struct Unary ##NAME ## Op;\
FASTOR_MAKE_UNARY_BOOL_OP_FORWARD_DECLARATION(Not)
FASTOR_MAKE_UNARY_BOOL_OP_FORWARD_DECLARATION(Isinf)
FASTOR_MAKE_UNARY_BOOL_OP_FORWARD_DECLARATION(Isnan)
FASTOR_MAKE_UNARY_BOOL_OP_FORWARD_DECLARATION(Isfinite)
template<typename Derived>
struct is_unary_bool_op;
#define FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(NAME)\
template<typename TLhs, typename TRhs, size_t DIM0>\
struct BinaryCmpOp##NAME ;\
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(EQ)
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(NEQ)
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(LT)
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(GT)
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(LE)
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(GE)
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(AND)
FASTOR_MAKE_BINARY_CMP_OP_FORWARD_DECLARATION(OR)
template<typename Derived>
struct is_binary_cmp_op;
//----------------------------------------------------------------
}
#endif // FORWARD_DECLARE_H

View File

@@ -0,0 +1,120 @@
#ifndef INDEX_RETRIEVER_H
#define INDEX_RETRIEVER_H
// Retrieving index
// Given a flat index get the flat index in to the tensor - note that for tensor class the incoming index is
// the out-going index but it may not be the same for special tensors for instance for SingleValueTensor and
// views and such the index may be different
//----------------------------------------------------------------------------------------------------------//
template<typename U>
FASTOR_INLINE U get_mem_index(U index) const {
#if FASTOR_BOUNDS_CHECK
FASTOR_ASSERT((index>=0 && index < size()), "INDEX OUT OF BOUNDS");
#endif
return index;
}
// Retrieving index for nD tensors
// Given a multi-dimensional index get the flat index in to the tensor
//----------------------------------------------------------------------------------------------------------//
template<typename... Args, typename std::enable_if<sizeof...(Args)==1
&& sizeof...(Args)==dimension_t::value && is_arithmetic_pack<Args...>::value,bool>::type =0>
FASTOR_INLINE size_t get_flat_index(Args ... args) const {
constexpr size_t M = get_value<1,Rest...>::value;
const size_t i = get_index<0>(args...) < 0 ? M + get_index<0>(args...) : get_index<0>(args...);
#if FASTOR_BOUNDS_CHECK
FASTOR_ASSERT( ( (i>=0 && i<M)), "INDEX OUT OF BOUNDS");
#endif
return i;
}
template<typename... Args, typename std::enable_if<sizeof...(Args)==2
&& sizeof...(Args)==dimension_t::value && is_arithmetic_pack<Args...>::value,bool>::type =0>
FASTOR_INLINE size_t get_flat_index(Args ... args) const {
constexpr size_t M = get_value<1,Rest...>::value;
constexpr size_t N = get_value<2,Rest...>::value;
const size_t i = get_index<0>(args...) < 0 ? M + get_index<0>(args...) : get_index<0>(args...);
const size_t j = get_index<1>(args...) < 0 ? N + get_index<1>(args...) : get_index<1>(args...);
#if FASTOR_BOUNDS_CHECK
FASTOR_ASSERT( ( (i>=0 && i<M) && (j>=0 && j<N)), "INDEX OUT OF BOUNDS");
#endif
return i*N+j;
}
template<typename... Args, typename std::enable_if<sizeof...(Args)==3
&& sizeof...(Args)==dimension_t::value && is_arithmetic_pack<Args...>::value,bool>::type =0>
FASTOR_INLINE size_t get_flat_index(Args ... args) const {
constexpr size_t M = get_value<1,Rest...>::value;
constexpr size_t N = get_value<2,Rest...>::value;
constexpr size_t P = get_value<3,Rest...>::value;
const size_t i = get_index<0>(args...) < 0 ? M + get_index<0>(args...) : get_index<0>(args...);
const size_t j = get_index<1>(args...) < 0 ? N + get_index<1>(args...) : get_index<1>(args...);
const size_t k = get_index<2>(args...) < 0 ? P + get_index<2>(args...) : get_index<2>(args...);
#if FASTOR_BOUNDS_CHECK
FASTOR_ASSERT( ( (i>=0 && i<M) && (j>=0 && j<N) && (k>=0 && k<P)), "INDEX OUT OF BOUNDS");
#endif
return i*N*P+j*P+k;
}
template<typename... Args, typename std::enable_if<sizeof...(Args)==4
&& sizeof...(Args)==dimension_t::value && is_arithmetic_pack<Args...>::value,bool>::type =0>
FASTOR_INLINE size_t get_flat_index(Args ... args) const {
constexpr size_t M = get_value<1,Rest...>::value;
constexpr size_t N = get_value<2,Rest...>::value;
constexpr size_t P = get_value<3,Rest...>::value;
constexpr size_t Q = get_value<4,Rest...>::value;
const size_t i = get_index<0>(args...) < 0 ? M + get_index<0>(args...) : get_index<0>(args...);
const size_t j = get_index<1>(args...) < 0 ? N + get_index<1>(args...) : get_index<1>(args...);
const size_t k = get_index<2>(args...) < 0 ? P + get_index<2>(args...) : get_index<2>(args...);
const size_t l = get_index<3>(args...) < 0 ? Q + get_index<3>(args...) : get_index<3>(args...);
#if FASTOR_BOUNDS_CHECK
FASTOR_ASSERT( ( (i>=0 && i<M) && (j>=0 && j<N)
&& (k>=0 && k<P) && (l>=0 && l<Q)), "INDEX OUT OF BOUNDS");
#endif
return i*N*P*Q+j*P*Q+k*Q+l;
}
template<typename... Args, typename std::enable_if<sizeof...(Args)>=5
&& sizeof...(Args)==dimension_t::value && is_arithmetic_pack<Args...>::value,bool>::type =0>
FASTOR_INLINE size_t get_flat_index(Args ... args) const {
/* The type of largs needs to be the type of incoming pack i.e.
whatever the tensor is indexed with
*/
get_nth_type<0,Args...> largs[sizeof...(Args)] = {args...};
constexpr std::array<size_t,dimension_t::value> products_ = nprods_views<Index<Rest...>,
typename std_ext::make_index_sequence<dimension_t::value>::type>::values;
constexpr size_t DimensionHolder[dimension_t::value] = {Rest...};
for (size_t i=0; i<dimension_t::value; ++i) {
if ( largs[i] < 0 ) largs[i] += DimensionHolder[i];
#if FASTOR_BOUNDS_CHECK
FASTOR_ASSERT( (largs[i]>=0 && largs[i]<DimensionHolder[i]), "INDEX OUT OF BOUNDS");
#endif
}
size_t index = 0;
for (size_t i=0; i<dimension_t::value; ++i) {
index += products_[i]*largs[i];
}
return index;
}
//----------------------------------------------------------------------------------------------------------//
FASTOR_INLINE int get_flat_index(const std::array<int, dimension_t::value> &as) const {
constexpr std::array<size_t,dimension_t::value> products_ = nprods_views<Index<Rest...>,
typename std_ext::make_index_sequence<dimension_t::value>::type>::values;
size_t index = 0;
for (size_t i=0; i<dimension_t::value; ++i) {
index += products_[i]*as[i];
}
#if FASTOR_BOUNDS_CHECK
FASTOR_ASSERT((index>=0 && index<size()), "INDEX OUT OF BOUNDS");
#endif
return index;
}
//----------------------------------------------------------------------------------------------------------//
#endif // INDEX_RETRIEVER_H

View File

@@ -0,0 +1,111 @@
#ifndef INITIALIZER_LIST_CONSTRUCTORS_H
#define INITIALIZER_LIST_CONSTRUCTORS_H
// Initialiser list constructors
//----------------------------------------------------------------------------------------------------------//
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false >
constexpr
FASTOR_INLINE Tensor(const std::initializer_list<U> &lst) {
static_assert(sizeof...(Rest)==1,"TENSOR RANK MISMATCH WITH LIST-INITIALISER");
#if (!defined(NDEBUG) && !defined(FASTOR_ZERO_INITIALISE))
FASTOR_ASSERT(pack_prod<Rest...>::value==lst.size(), "TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
#endif
auto counter = 0;
for (const auto &i: lst) {_data[counter] = i; counter++;}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false >
constexpr
FASTOR_INLINE Tensor(const std::initializer_list<std::initializer_list<U>> &lst2d) {
static_assert(sizeof...(Rest)==2,"TENSOR RANK MISMATCH WITH LIST-INITIALISER");
#if (!defined(NDEBUG) && !defined(FASTOR_ZERO_INITIALISE))
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
auto size_ = 0;
FASTOR_ASSERT(M==lst2d.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
for (auto &lst: lst2d) {
auto curr_size = lst.size();
FASTOR_ASSERT(N==lst.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
size_ += curr_size;
}
FASTOR_ASSERT(pack_prod<Rest...>::value==size_, "TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
#endif
auto counter = 0;
for (const auto &lst1d: lst2d) {
for (const auto &i: lst1d) {
_data[counter] = T(i);
counter++;
}
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false >
constexpr
FASTOR_INLINE Tensor(const std::initializer_list<std::initializer_list<std::initializer_list<U>>> &lst3d) {
static_assert(sizeof...(Rest)==3,"TENSOR RANK MISMATCH WITH LIST-INITIALISER");
#if (!defined(NDEBUG) && !defined(FASTOR_ZERO_INITIALISE))
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
constexpr FASTOR_INDEX P = get_value<3,Rest...>::value;
auto size_ = 0;
FASTOR_ASSERT(M==lst3d.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
for (const auto &lst2d: lst3d) {
FASTOR_ASSERT(N==lst2d.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
for (const auto &lst: lst2d) {
const auto curr_size = lst.size();
FASTOR_ASSERT(P==lst.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
size_ += curr_size;
}
}
FASTOR_ASSERT(pack_prod<Rest...>::value==size_, "TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
#endif
auto counter = 0;
for (const auto &lst2d: lst3d) {
for (const auto &lst1d: lst2d) {
for (const auto &i: lst1d) {
_data[counter] = i;
counter++;
}
}
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false >
constexpr
FASTOR_INLINE Tensor(const std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<U>>>> &lst4d) {
static_assert(sizeof...(Rest)==4,"TENSOR RANK MISMATCH WITH LIST-INITIALISER");
#if (!defined(NDEBUG) && !defined(FASTOR_ZERO_INITIALISE))
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
constexpr FASTOR_INDEX P = get_value<3,Rest...>::value;
constexpr FASTOR_INDEX Q = get_value<4,Rest...>::value;
auto size_ = 0;
FASTOR_ASSERT(M==lst4d.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
for (const auto &lst3d: lst4d) {
FASTOR_ASSERT(N==lst3d.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
for (const auto &lst2d: lst3d) {
FASTOR_ASSERT(P==lst2d.size(),"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
for (const auto &lst: lst2d) {
const auto curr_size = lst.size();
FASTOR_ASSERT(Q==curr_size,"TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
size_ += curr_size;
}
}
}
FASTOR_ASSERT(pack_prod<Rest...>::value==size_, "TENSOR SIZE MISMATCH WITH LIST-INITIALISER");
#endif
auto counter = 0;
for (const auto &lst3d: lst4d) {
for (const auto &lst2d: lst3d) {
for (const auto &lst1d: lst2d) {
for (const auto &i: lst1d) {
_data[counter] = i;
counter++;
}
}
}
}
}
//----------------------------------------------------------------------------------------------------------//
#endif // INITIALIZER_LIST_CONSTRUCTORS_H

View File

@@ -0,0 +1,24 @@
#ifndef PODCONVERTERS_H
#define PODCONVERTERS_H
FASTOR_INLINE T toscalar() const {
//! Returns a scalar
static_assert(size()==1,"ONLY TENSORS OF SIZE 1 CAN BE CONVERTED TO A SCALAR");
return (*_data);
}
FASTOR_INLINE std::array<T,size()> toarray() const {
//! Returns std::array
std::array<T,size()> out;
std::copy(_data,_data+size(),out.begin());
return out;
}
FASTOR_INLINE std::vector<T> tovector() const {
//! Returns std::vector
std::vector<T> out(size());
std::copy(_data,_data+size(),out.begin());
return out;
}
#endif //PODCONVERTERS_H

View File

@@ -0,0 +1,210 @@
#ifndef RANGES_H
#define RANGES_H
#include "Fastor/config/config.h"
#include "Fastor/meta/meta.h"
#include <initializer_list>
namespace Fastor {
// range detector for fseq
//----------------------------------------------------------------------------------------------------------//
template<int first, int last, int step>
struct range_detector {
static constexpr int range = last - first;
static constexpr int value = range % step==0 ? range/step : range/step+1;
};
namespace internal {
template<class Seq>
struct fseq_range_detector;
template<template<int,int,int> class Seq, int first, int last, int step>
struct fseq_range_detector<Seq<first,last,step>> {
static constexpr int range = last - first;
static constexpr int value = range % step==0 ? range/step : range/step+1;
};
} // internal
//----------------------------------------------------------------------------------------------------------//
// Immediate sequence
//----------------------------------------------------------------------------------------------------------//
template<size_t F, size_t L, size_t S=1>
struct iseq {
static constexpr size_t _first = F;
static constexpr size_t _last= L;
static constexpr size_t _step = S;
};
//----------------------------------------------------------------------------------------------------------//
// Fixed sequence
//----------------------------------------------------------------------------------------------------------//
template<int F, int L, int S=1>
struct fseq {
static constexpr int _first = F;
static constexpr int _last= L;
static constexpr int _step = S;
static constexpr int Size = range_detector<F,L,S>::value;
constexpr FASTOR_INLINE int size() const {return range_detector<F,L,S>::value;}
};
static constexpr fseq<0,-1,1> fall;
template<int F>
static constexpr fseq<F,F+1,1> fix{};
static constexpr fseq<0 ,1 ,1> ffirst;
static constexpr fseq<-1,-1,1> flast;
//----------------------------------------------------------------------------------------------------------//
// Dynamic sequence
//----------------------------------------------------------------------------------------------------------//
struct seq {
int _first;
int _last;
int _step = 1;
constexpr FASTOR_INLINE seq(int _f, int _l, int _s=1) : _first(_f), _last(_l), _step(_s) {}
constexpr FASTOR_INLINE seq(int num) : _first(num), _last(num+1), _step(1) {}
template<int F, int L, int S=1>
constexpr FASTOR_INLINE seq(fseq<F,L,S>) : _first(F), _last(L), _step(S) {}
// Do not allow construction of seq using std::initializer_list, as it happens
// implicitly. Overloading operator() with std::initializer_list should imply
// TensorRandomView, not TensorView
template<typename T>
constexpr FASTOR_INLINE seq(std::initializer_list<T> _s1) = delete;
// Do not provide this overload as it is meaningless [iseq stands for immediate evaluation]
// template<size_t F, size_t L, size_t S=1>
// constexpr FASTOR_INLINE seq(iseq<F,L,S>) : _first(F), _last(L), _step(S) {}
FASTOR_INLINE int size() const {
int range = _last - _first;
return range % _step==0 ? range/_step : range/_step+1;
}
constexpr FASTOR_INLINE bool operator==(seq other) const {
return (_first==other._first && _last==other._last && _step==other._step) ? true : false;
}
constexpr FASTOR_INLINE bool operator!=(seq other) const {
return (_first!=other._first || _last!=other._last || _step!=other._step) ? true : false;
}
};
static constexpr int first = 0;
static constexpr int last = -1;
// static constexpr seq all = seq(0,-1,1);
// why not this?
static constexpr fseq<0,-1,1> all;
//----------------------------------------------------------------------------------------------------------//
// traits
//----------------------------------------------------------------------------------------------------------//
template<typename T>
struct is_fixed_sequence {
static constexpr bool value = false;
};
template<int F, int L, int S>
struct is_fixed_sequence<fseq<F,L,S>> {
static constexpr bool value = true;
};
template<int F, int L>
struct is_fixed_sequence<fseq<F,L,1>> {
static constexpr bool value = true;
};
template<typename T>
static constexpr bool is_fixed_sequence_v = is_fixed_sequence<T>::value;
template<typename ... T>
struct is_fixed_sequence_pack;
template<typename T, typename ... Ts>
struct is_fixed_sequence_pack<T,Ts...> {
static constexpr bool value = is_fixed_sequence<T>::value && is_fixed_sequence_pack<Ts...>::value;
};
template<typename T>
struct is_fixed_sequence_pack<T> {
static constexpr bool value = is_fixed_sequence<T>::value;
};
template<typename ... Ts>
static constexpr bool is_fixed_sequence_pack_v = is_fixed_sequence_pack<Ts...>::value;
//----------------------------------------------------------------------------------------------------------//
// Transform sequence with negative indices to positive indices;
//----------------------------------------------------------------------------------------------------------//
template<class Seq, int N>
struct to_positive;
template<int F, int L, int S, int N>
struct to_positive<fseq<F,L,S>,N> {
// Same logic as seq used in the constructor of dynamic tensor views
static constexpr int _first = (L==0 && F==-1) ? N-1 : ( L < 0 && F < 0 ? F + N + 1 : F);
static constexpr int _last = (L < 0 && F >=0) ? L + N + 1 : ( (L==0 && F==-1) ? N : ( L < 0 && F < 0 ? L + N + 1 : L) );
using type = fseq<_first,_last,S>;
};
template<int F, int L, int S, int N>
struct to_positive<iseq<F,L,S>,N> {
// Same logic as seq used in the constructor of dynamic tensor views
static constexpr int _first = (L==0 && F==-1) ? N-1 : ( L < 0 && F < 0 ? F + N + 1 : F);
static constexpr int _last = (L < 0 && F >=0) ? L + N + 1 : ( (L==0 && F==-1) ? N : ( L < 0 && F < 0 ? L + N + 1 : L) );
using type = iseq<_first,_last,S>;
};
template<class Seq, int N>
using to_positive_t = typename to_positive<Seq,N>::type;
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<typename Derived, class Seq, typename ... Fseqs>
struct get_fixed_sequence_pack_dimensions;
template<template<typename,size_t...> class Derived, typename T, size_t ...Rest, size_t... ss, typename ... Fseqs>
struct get_fixed_sequence_pack_dimensions<Derived<T, Rest...>, std_ext::index_sequence<ss...>, Fseqs...>{
static constexpr std::array<int,sizeof...(Fseqs)> dims = { internal::fseq_range_detector<to_positive_t<Fseqs,Rest>>::value... };
// using type = Derived<T,internal::fseq_range_detector<Fseqs>::value...>;
using type = Derived<T,internal::fseq_range_detector<to_positive_t<Fseqs,Rest>>::value...>;
static constexpr size_t Size = pack_prod<dims[ss]...>::value;
};
template<template<typename,size_t...> class Derived, typename T, size_t ...Rest, size_t... ss, typename ... Fseqs>
constexpr std::array<int,sizeof...(Fseqs)> get_fixed_sequence_pack_dimensions<Derived<T, Rest...>, std_ext::index_sequence<ss...>, Fseqs...>::dims;
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<size_t F0, size_t L0, size_t S0, size_t F1, size_t L1, size_t S1, size_t Ncol, class Y>
struct ravel_2d_indices;
template<size_t F0, size_t L0, size_t S0, size_t F1, size_t L1, size_t S1, size_t Ncol, size_t ... ss>
struct ravel_2d_indices<F0,L0,S0,F1,L1,S1,Ncol,std_ext::index_sequence<ss...>> {
static constexpr size_t size_1 = range_detector<F1,L1,S1>::value;
static constexpr std::array<size_t,sizeof...(ss)> idx = {(S0*(ss/size_1)*Ncol + S1*(ss%size_1) + F0*Ncol + F1)...};
};
template<size_t F0, size_t L0, size_t S0, size_t F1, size_t L1, size_t S1, size_t Ncol, size_t ... ss>
constexpr std::array<size_t,sizeof...(ss)>
ravel_2d_indices<F0,L0,S0,F1,L1,S1,Ncol,std_ext::index_sequence<ss...>>::idx;
//----------------------------------------------------------------------------------------------------------//
}
#endif // RANGES_H

View File

@@ -0,0 +1,39 @@
#ifndef SCALAR_INDEXING_NONCONST_H
#define SCALAR_INDEXING_NONCONST_H
// Scalar indexing non-const
//----------------------------------------------------------------------------------------------------------//
template<typename... Args, typename std::enable_if<sizeof...(Args)==dimension_t::value &&
is_arithmetic_pack<Args...>::value,bool>::type =0>
FASTOR_INLINE T& operator()(Args ... args) {
return _data[get_flat_index(args...)];
}
template<typename Arg, typename std::enable_if<1==dimension_t::value &&
is_arithmetic_pack<Arg>::value,bool>::type =0>
FASTOR_INLINE T& operator[](Arg arg) {
return _data[get_flat_index(arg)];
}
//----------------------------------------------------------------------------------------------------------//
#endif // SCALAR_INDEXING_NONCONST_H
#ifndef SCALAR_INDEXING_CONST_H
#define SCALAR_INDEXING_CONST_H
// Scalar indexing const
//----------------------------------------------------------------------------------------------------------//
template<typename... Args, typename std::enable_if<sizeof...(Args)==dimension_t::value &&
is_arithmetic_pack<Args...>::value,bool>::type =0>
constexpr FASTOR_INLINE const T& operator()(Args ... args) const {
return _data[get_flat_index(args...)];
}
template<typename Arg, typename std::enable_if<1==dimension_t::value &&
is_arithmetic_pack<Arg>::value,bool>::type =0>
constexpr FASTOR_INLINE const T& operator[](Arg arg) const {
return _data[get_flat_index(arg)];
}
//----------------------------------------------------------------------------------------------------------//
#endif // SCALAR_INDEXING_CONST_H

View File

@@ -0,0 +1,374 @@
#ifndef SPECIALISED_CONSTRUCTORS_H
#define SPECIALISED_CONSTRUCTORS_H
//----------------------------------------------------------------------------------------------------------//
template<size_t ...Rest1, typename Seq0, typename Seq1,
typename std::enable_if<sizeof...(Rest)==sizeof...(Rest1),bool>::type=0>
FASTOR_INLINE Tensor(const TensorFixedViewExpr2D<Tensor<T,Rest1...>,Seq0,Seq1,2>& src) {
using scalar_type_ = T;
constexpr FASTOR_INDEX Stride_ = simd_size_v<scalar_type_>;
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
for (FASTOR_INDEX i = 0; i<sizeof...(Rest); ++i) {
FASTOR_ASSERT(src.dimension(i)==this->dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i <M; ++i) {
FASTOR_INDEX j;
for (j = 0; j <ROUND_DOWN(N,Stride_); j+=Stride_) {
src.template eval<scalar_type_>(i,j).store(&_data[i*N+j], false);
}
for (; j < N; ++j) {
_data[i*N+j] = src.template eval_s<scalar_type_>(i,j);
}
}
}
template<size_t ...Rest1, typename ... Fseqs, enable_if_t_<sizeof...(Rest1)==sizeof...(Rest),bool> = false>
FASTOR_INLINE Tensor(const TensorFixedViewExprnD<Tensor<T,Rest1...>,Fseqs...>& src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
constexpr int DimensionHolder[dimension_t::value] = {Rest...};
std::array<int,dimension_t::value> as = {};
int jt, counter=0;
if (src.is_vectorisable() || src.is_strided_vectorisable())
{
using V = SIMDVector<T,simd_abi_type>;
V _vec;
while(counter < size())
{
_vec = src.template teval<T>(as);
_vec.store(&_data[counter],false);
counter+=V::Size;
for(jt = dimension_t::value-1; jt>=0; jt--)
{
if (jt == dimension_t::value-1) as[jt]+=V::Size;
else as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
}
else {
while(counter < size())
{
_data[counter] = src.template teval_s<T>(as);
counter++;
for(jt = dimension_t::value-1; jt>=0; jt--)
{
as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
}
}
#ifndef FASTOR_DISABLE_SPECIALISED_CTR
template<typename Derived, size_t DIMS,
enable_if_t_<!has_tensor_view_v<Derived> && !has_tensor_fixed_view_nd_v<Derived> && has_tensor_fixed_view_2d_v<Derived>
&& DIMS==sizeof...(Rest)
&& requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
// const typename Derived::result_type& tmp = evaluate(src_.self());
FASTOR_ASSERT(src_.self().size()==this->size(), "TENSOR SIZE MISMATCH");
assign(*this,src_.self());
}
template<typename Derived, size_t DIMS,
enable_if_t_<!has_tensor_view_v<Derived> && !has_tensor_fixed_view_nd_v<Derived> && has_tensor_fixed_view_2d_v<Derived>
&& DIMS==sizeof...(Rest)
&& !requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
using scalar_type_ = typename scalar_type_finder<Derived>::type;
constexpr FASTOR_INDEX Stride_ = simd_size_v<scalar_type_>;
const Derived &src = src_.self();
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
for (FASTOR_INDEX i = 0; i<sizeof...(Rest); ++i) {
FASTOR_ASSERT(src.dimension(i)==this->dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
FASTOR_IF_CONSTEXPR(!is_boolean_expression_v<Derived>) {
for (FASTOR_INDEX i = 0; i <M; ++i) {
FASTOR_INDEX j;
for (j = 0; j <ROUND_DOWN(N,Stride_); j+=Stride_) {
src.template eval<T>(i,j).store(&_data[i*N+j], false);
}
for (; j <N; ++j) {
_data[i*N+j] = src.template eval_s<T>(i,j);
}
}
}
else {
for (FASTOR_INDEX i = 0; i <M; ++i) {
for (FASTOR_INDEX j = 0; j <N; ++j) {
_data[i*N+j] = src.template eval_s<T>(i,j);
}
}
}
}
template<typename Derived, size_t DIMS, enable_if_t_<!has_tensor_view_v<Derived> && has_tensor_fixed_view_nd_v<Derived>
&& DIMS!=2 && DIMS==sizeof...(Rest) &&
requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
FASTOR_ASSERT(src_.self().size()==this->size(), "TENSOR SIZE MISMATCH");
assign(*this,src_.self());
}
template<typename Derived, size_t DIMS, enable_if_t_<!has_tensor_view_v<Derived> && has_tensor_fixed_view_nd_v<Derived>
&& DIMS!=2 && DIMS==sizeof...(Rest) &&
!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
const Derived &src = src_.self();
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
for (FASTOR_INDEX i = 0; i<sizeof...(Rest); ++i) {
FASTOR_ASSERT(src.dimension(i)==this->dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
constexpr int DimensionHolder[dimension_t::value] = {Rest...};
std::array<int,dimension_t::value> as = {};
int jt, counter=0;
while(counter < size())
{
_data[counter] = src.template teval_s<T>(as);
counter++;
for(jt = dimension_t::value-1; jt>=0; jt--)
{
as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
}
#endif // FASTOR_DISABLE_SPECIALISED_CTR
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<size_t ...Rest1, enable_if_t_<sizeof...(Rest)==sizeof...(Rest1),bool> = false>
FASTOR_INLINE Tensor(const TensorViewExpr<Tensor<T,Rest1...>,2>& src) {
using scalar_type_ = T;
constexpr FASTOR_INDEX Stride_ = simd_size_v<scalar_type_>;
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
for (FASTOR_INDEX i = 0; i<sizeof...(Rest); ++i) {
FASTOR_ASSERT(src.dimension(i)==this->dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
for (FASTOR_INDEX i = 0; i <M; ++i) {
FASTOR_INDEX j;
for (j = 0; j <ROUND_DOWN(N,Stride_); j+=Stride_) {
src.template eval<scalar_type_>(i,j).store(&_data[i*N+j], false);
}
for (; j < N; ++j) {
_data[i*N+j] = src.template eval_s<scalar_type_>(i,j);
}
}
}
template<size_t ...Rest1, enable_if_t_<is_greater<sizeof...(Rest1),2>::value,bool> = false>
FASTOR_INLINE Tensor(const TensorViewExpr<Tensor<T,Rest1...>,sizeof...(Rest)>& src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
for (FASTOR_INDEX i = 0; i<sizeof...(Rest); ++i) {
FASTOR_ASSERT(src.dimension(i)==this->dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
constexpr int DimensionHolder[dimension_t::value] = {Rest...};
std::array<int,dimension_t::value> as = {};
int jt, counter=0;
if (src.is_vectorisable() || src.is_strided_vectorisable())
{
using V = SIMDVector<T,simd_abi_type>;
V _vec;
while(counter < size())
{
_vec = src.template teval<T>(as);
_vec.store(&_data[counter],false);
counter+=V::Size;
for(jt = dimension_t::value-1; jt>=0; jt--)
{
if (jt == dimension_t::value-1) as[jt]+=V::Size;
else as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
}
else {
while(counter < size())
{
_data[counter] = src.template teval_s<T>(as);
counter++;
for(jt = dimension_t::value-1; jt>=0; jt--)
{
as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
}
}
#ifndef FASTOR_DISABLE_SPECIALISED_CTR
template<typename Derived, size_t DIMS, enable_if_t_<has_tensor_view_v<Derived> && DIMS==2 && DIMS==sizeof...(Rest) &&
requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
FASTOR_ASSERT(src_.self().size()==this->size(), "TENSOR SIZE MISMATCH");
assign(*this,src_.self());
}
template<typename Derived, size_t DIMS, enable_if_t_<has_tensor_view_v<Derived> && DIMS==2 && DIMS==sizeof...(Rest) &&
!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
using scalar_type_ = typename scalar_type_finder<Derived>::type;
constexpr FASTOR_INDEX Stride_ = simd_size_v<scalar_type_>;
const Derived &src = src_.self();
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
for (FASTOR_INDEX i = 0; i<sizeof...(Rest); ++i) {
FASTOR_ASSERT(src.dimension(i)==this->dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
FASTOR_IF_CONSTEXPR(!is_boolean_expression_v<Derived>) {
for (FASTOR_INDEX i = 0; i <M; ++i) {
FASTOR_INDEX j;
for (j = 0; j <ROUND_DOWN(N,Stride_); j+=Stride_) {
src.template eval<T>(i,j).store(&_data[i*N+j], false);
}
for (; j < N; ++j) {
_data[i*N+j] = src.template eval_s<T>(i,j);
}
}
}
else {
for (FASTOR_INDEX i = 0; i <M; ++i) {
for (FASTOR_INDEX j = 0; j < N; ++j) {
_data[i*N+j] = src.template eval_s<T>(i,j);
}
}
}
}
template<typename Derived, size_t DIMS, enable_if_t_<has_tensor_view_v<Derived> && DIMS!=2 && DIMS==sizeof...(Rest) &&
requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
FASTOR_ASSERT(src_.self().size()==this->size(), "TENSOR SIZE MISMATCH");
assign(*this,src_.self());
}
template<typename Derived, size_t DIMS, enable_if_t_<has_tensor_view_v<Derived> && DIMS!=2 && DIMS==sizeof...(Rest) &&
!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src_) {
// using scalar_type_ = typename scalar_type_finder<Derived>::type;
// constexpr FASTOR_INDEX Stride_ = simd_size_v<scalar_type_>;
const Derived &src = src_.self();
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
for (FASTOR_INDEX i = 0; i<sizeof...(Rest); ++i) {
FASTOR_ASSERT(src.dimension(i)==this->dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
constexpr int DimensionHolder[dimension_t::value] = {Rest...};
std::array<int,dimension_t::value> as = {};
int jt, counter=0;
while(counter < size())
{
_data[counter] = src.template teval_s<T>(as);
counter++;
for(jt = dimension_t::value-1; jt>=0; jt--)
{
as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
// // Generic vectorised version that takes care of the remainder scalar ops
// using V=SIMDVector<T,simd_abi_type>;
// while(counter < size())
// {
// const FASTOR_INDEX remainder = DimensionHolder[dimension_t::value-1] - as[dimension_t::value-1];
// if (remainder > V::Size) {
// // V _vec = src.template eval<T>(counter);
// V _vec = src.template teval<T>(as);
// _vec.store(&_data[counter],false);
// counter+=V::Size;
// }
// else {
// // _data[counter] = src.template eval_s<T>(counter);
// _data[counter] = src.template teval_s<T>(as);
// counter++;
// }
// for(jt = dimension_t::value-1; jt>=0; jt--)
// {
// if (jt == dimension_t::value-1 && remainder > V::Size) as[jt]+=V::Size;
// else as[jt] +=1;
// if(as[jt]<DimensionHolder[jt])
// break;
// else
// as[jt]=0;
// }
// if(jt<0)
// break;
// }
}
#endif // FASTOR_DISABLE_SPECIALISED_CTR
//----------------------------------------------------------------------------------------------------------//
#endif // SPECIALISED_CONSTRUCTORS_H

View File

@@ -0,0 +1,203 @@
#ifndef TENSOR_H
#define TENSOR_H
#include "Fastor/config/config.h"
#include "Fastor/util/util.h"
#include "Fastor/backend/backend.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/ForwardDeclare.h"
#include "Fastor/expressions/linalg_ops/linalg_ops.h"
#include <array>
#include <vector>
namespace Fastor {
template<typename T, size_t ... Rest>
class Tensor: public AbstractTensor<Tensor<T,Rest...>,sizeof...(Rest)> {
public:
using scalar_type = T;
using simd_vector_type = choose_best_simd_vector_t<T>;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<T,Rest...>;
using dimension_t = std::integral_constant<FASTOR_INDEX, sizeof...(Rest)>;
static constexpr FASTOR_INLINE FASTOR_INDEX rank() {return sizeof...(Rest);}
static constexpr FASTOR_INLINE FASTOR_INDEX size() {return pack_prod<Rest...>::value;}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX dim) const {
#if FASTOR_SHAPE_CHECK
FASTOR_ASSERT(dim>=0 && dim < sizeof...(Rest), "TENSOR SHAPE MISMATCH");
#endif
constexpr FASTOR_INDEX DimensionHolder[sizeof...(Rest)] = {Rest...};
return DimensionHolder[dim];
}
FASTOR_INLINE Tensor<T,Rest...>& noalias() {return *this;}
// Classic constructors
//----------------------------------------------------------------------------------------------------------//
// Default constructor
constexpr FASTOR_INLINE Tensor() = default;
// Copy constructor
FASTOR_INLINE Tensor(const Tensor<T,Rest...> &other) {
// This constructor cannot be default
if (_data == other.data()) return;
// fast memcopy
std::copy(other.data(),other.data()+size(),_data);
};
// Constructor from a scalar
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
constexpr FASTOR_INLINE Tensor(U num) {
#ifdef FASTOR_ZERO_INITIALISE
// This is for compile time initialisation, so it is fine
scalar_type cnum = (scalar_type)num;
FASTOR_INDEX i = 0;
for (; i<size(); ++i) {
_data[i] = cnum;
}
#else
assign(*this, num);
#endif
}
// Initialiser list constructors
//----------------------------------------------------------------------------------------------------------//
#include "Fastor/tensor/InitializerListConstructors.h"
//----------------------------------------------------------------------------------------------------------//
// Classic array wrappers
//----------------------------------------------------------------------------------------------------------//
FASTOR_INLINE Tensor(const T *arr, int layout=RowMajor) {
std::copy(arr,arr+size(),_data);
if (layout == RowMajor)
return;
else
*this = tocolumnmajor(*this);
}
FASTOR_INLINE Tensor(const std::array<T,pack_prod<Rest...>::value> &arr, int layout=RowMajor) {
std::copy(arr.data(),arr.data()+pack_prod<Rest...>::value,_data);
if (layout == RowMajor)
return;
else
*this = tocolumnmajor(*this);
}
FASTOR_INLINE Tensor(const std::vector<T> &arr, int layout=RowMajor) {
std::copy(arr.data(),arr.data()+pack_prod<Rest...>::value,_data);
if (layout == RowMajor)
return;
else
*this = tocolumnmajor(*this);
}
//----------------------------------------------------------------------------------------------------------//
// CRTP constructors
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
// Generic AbstractTensors
#ifndef FASTOR_DISABLE_SPECIALISED_CTR
template<typename Derived, size_t DIMS,
enable_if_t_<(!has_tensor_view_v<Derived> && !has_tensor_fixed_view_2d_v<Derived> &&
!has_tensor_fixed_view_nd_v<Derived>) || DIMS!=sizeof...(Rest),bool> = false>
#else
template<typename Derived, size_t DIMS>
#endif
FASTOR_INLINE Tensor(const AbstractTensor<Derived,DIMS>& src) {
FASTOR_ASSERT(src.self().size()==size(), "TENSOR SIZE MISMATCH");
assign(*this, src.self());
}
//----------------------------------------------------------------------------------------------------------//
// Specialised constructors
//----------------------------------------------------------------------------------------------------------//
#include "Fastor/tensor/SpecialisedConstructors.h"
//----------------------------------------------------------------------------------------------------------//
// AbstractTensor and scalar in-place operators
//----------------------------------------------------------------------------------------------------------//
#include "Fastor/tensor/TensorInplaceOperators.h"
//----------------------------------------------------------------------------------------------------------//
// Raw pointer providers
//----------------------------------------------------------------------------------------------------------//
#ifdef FASTOR_ZERO_INITIALISE
constexpr FASTOR_INLINE T* data() const { return const_cast<T*>(this->_data);}
#else
FASTOR_INLINE T* data() const { return const_cast<T*>(this->_data);}
#endif
FASTOR_INLINE T* data() {return this->_data;}
//----------------------------------------------------------------------------------------------------------//
// Scalar & block indexing
//----------------------------------------------------------------------------------------------------------//
#include "Fastor/tensor/IndexRetriever.h"
#include "Fastor/tensor/ScalarIndexing.h"
#include "Fastor/tensor/BlockIndexing.h"
//----------------------------------------------------------------------------------------------------------//
// Expression templates evaluators
//----------------------------------------------------------------------------------------------------------//
#include "Fastor/tensor/TensorEvaluator.h"
//----------------------------------------------------------------------------------------------------------//
// Tensor methods
//----------------------------------------------------------------------------------------------------------//
#include "Fastor/tensor/TensorMethods.h"
//----------------------------------------------------------------------------------------------------------//
// Converters
//----------------------------------------------------------------------------------------------------------//
#include "Fastor/tensor/PODConverters.h"
//----------------------------------------------------------------------------------------------------------//
// Cast method
//----------------------------------------------------------------------------------------------------------//
template<typename U>
FASTOR_INLINE Tensor<U,Rest...> cast() const {
Tensor<U,Rest...> out;
U *out_data = out.data();
for (FASTOR_INDEX i=0; i<size(); ++i) {
out_data[get_mem_index(i)] = static_cast<U>(_data[i]);
}
return out;
}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
protected:
template<typename Derived, size_t DIMS>
FASTOR_INLINE void verify_dimensions(const AbstractTensor<Derived,DIMS>& src_) const {
static_assert(DIMS==dimension_t::value, "TENSOR RANK MISMATCH");
#ifndef NDEBUG
const Derived &src = src_.self();
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<dimension_t::value; ++i) {
FASTOR_ASSERT(src.dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
private:
#ifdef FASTOR_ZERO_INITIALISE
FASTOR_ALIGN T _data[pack_prod<Rest...>::value] = {};
#else
FASTOR_ALIGN T _data[pack_prod<Rest...>::value];
#endif
//----------------------------------------------------------------------------------------------------------//
};
} // end of namespace Fastor
#include "Fastor/tensor/TensorAssignment.h"
#endif // TENSOR_H

View File

@@ -0,0 +1,299 @@
#ifndef TENSOR_ASSIGNMENT_H
#define TENSOR_ASSIGNMENT_H
namespace Fastor {
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM>
FASTOR_INLINE void trivial_assign(AbstractTensor<Derived,DIM> &dst, const AbstractTensor<OtherDerived,OtherDIM> &src_) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
const OtherDerived &src = src_.self();
FASTOR_ASSERT(src.size()==dst.self().size(), "TENSOR SIZE MISMATCH");
T* _data = dst.self().data();
FASTOR_IF_CONSTEXPR(!is_boolean_expression_v<OtherDerived>) {
FASTOR_INDEX i = 0;
for (; i <ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
src.template eval<T>(i).store(&_data[i], FASTOR_ALIGNED);
}
for (; i < src.size(); ++i) {
_data[i] = src.template eval_s<T>(i);
}
}
else {
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
_data[i] = src.template eval_s<T>(i);
}
}
}
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM>
FASTOR_INLINE void trivial_assign_add(AbstractTensor<Derived,DIM> &dst, const AbstractTensor<OtherDerived,OtherDIM> &src_) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
const OtherDerived &src = src_.self();
FASTOR_ASSERT(src.size()==dst.self().size(), "TENSOR SIZE MISMATCH");
T* _data = dst.self().data();
FASTOR_IF_CONSTEXPR(!is_boolean_expression_v<OtherDerived>) {
FASTOR_INDEX i = 0;
for (; i <ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
V _vec = V(&_data[i], FASTOR_ALIGNED) + src.template eval<T>(i);
_vec.store(&_data[i], FASTOR_ALIGNED);
}
for (; i < src.size(); ++i) {
_data[i] += src.template eval_s<T>(i);
}
}
else {
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
_data[i] += src.template eval_s<T>(i);
}
}
}
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM>
FASTOR_INLINE void trivial_assign_sub(AbstractTensor<Derived,DIM> &dst, const AbstractTensor<OtherDerived,OtherDIM> &src_) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
const OtherDerived &src = src_.self();
FASTOR_ASSERT(src.size()==dst.self().size(), "TENSOR SIZE MISMATCH");
T* _data = dst.self().data();
FASTOR_IF_CONSTEXPR(!is_boolean_expression_v<OtherDerived>) {
FASTOR_INDEX i = 0;
for (; i <ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
V _vec = V(&_data[i], FASTOR_ALIGNED) - src.template eval<T>(i);
_vec.store(&_data[i], FASTOR_ALIGNED);
}
for (; i < src.size(); ++i) {
_data[i] -= src.template eval_s<T>(i);
}
}
else {
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
_data[i] -= src.template eval_s<T>(i);
}
}
}
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM>
FASTOR_INLINE void trivial_assign_mul(AbstractTensor<Derived,DIM> &dst, const AbstractTensor<OtherDerived,OtherDIM> &src_) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
const OtherDerived &src = src_.self();
FASTOR_ASSERT(src.size()==dst.self().size(), "TENSOR SIZE MISMATCH");
T* _data = dst.self().data();
FASTOR_IF_CONSTEXPR(!is_boolean_expression_v<OtherDerived>) {
FASTOR_INDEX i = 0;
for (; i <ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
V _vec = V(&_data[i], FASTOR_ALIGNED) * src.template eval<T>(i);
_vec.store(&_data[i], FASTOR_ALIGNED);
}
for (; i < src.size(); ++i) {
_data[i] *= src.template eval_s<T>(i);
}
}
else {
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
_data[i] *= src.template eval_s<T>(i);
}
}
}
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM>
FASTOR_INLINE void trivial_assign_div(AbstractTensor<Derived,DIM> &dst, const AbstractTensor<OtherDerived,OtherDIM> &src_) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
const OtherDerived &src = src_.self();
FASTOR_ASSERT(src.size()==dst.self().size(), "TENSOR SIZE MISMATCH");
T* _data = dst.self().data();
FASTOR_IF_CONSTEXPR(!is_boolean_expression_v<OtherDerived>) {
FASTOR_INDEX i = 0;
for (; i <ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
V _vec = V(&_data[i], FASTOR_ALIGNED) / src.template eval<T>(i);
_vec.store(&_data[i], FASTOR_ALIGNED);
}
for (; i < src.size(); ++i) {
_data[i] /= src.template eval_s<T>(i);
}
}
else {
for (FASTOR_INDEX i = 0; i < src.size(); ++i) {
_data[i] /= src.template eval_s<T>(i);
}
}
}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>, bool> = false>
FASTOR_INLINE void trivial_assign(AbstractTensor<Derived,DIM> &dst, U num) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
T* _data = dst.self().data();
T cnum = (T)num;
V _vec(cnum);
FASTOR_INDEX i = 0;
for (; i< ROUND_DOWN(dst.self().size(),V::Size); i+=V::Size) {
_vec.store(&_data[i], FASTOR_ALIGNED);
}
for (; i<dst.self().size(); ++i) {
_data[i] = cnum;
}
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>, bool> = false>
FASTOR_INLINE void trivial_assign_add(AbstractTensor<Derived,DIM> &dst, U num) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
T* _data = dst.self().data();
T cnum = (T)num;
V _vec(cnum);
FASTOR_INDEX i = 0;
for (; i< ROUND_DOWN(dst.self().size(),V::Size); i+=V::Size) {
V _vec_out(&_data[i], FASTOR_ALIGNED);
_vec_out += _vec;
_vec_out.store(&_data[i], FASTOR_ALIGNED);
}
for (; i<dst.self().size(); ++i) {
_data[i] += cnum;
}
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>, bool> = false>
FASTOR_INLINE void trivial_assign_sub(AbstractTensor<Derived,DIM> &dst, U num) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
T* _data = dst.self().data();
T cnum = (T)num;
V _vec(cnum);
FASTOR_INDEX i = 0;
for (; i< ROUND_DOWN(dst.self().size(),V::Size); i+=V::Size) {
V _vec_out(&_data[i], FASTOR_ALIGNED);
_vec_out -= _vec;
_vec_out.store(&_data[i], FASTOR_ALIGNED);
}
for (; i<dst.self().size(); ++i) {
_data[i] -= cnum;
}
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>, bool> = false>
FASTOR_INLINE void trivial_assign_mul(AbstractTensor<Derived,DIM> &dst, U num) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
T* _data = dst.self().data();
T cnum = (T)num;
V _vec(cnum);
FASTOR_INDEX i = 0;
for (; i< ROUND_DOWN(dst.self().size(),V::Size); i+=V::Size) {
V _vec_out(&_data[i], FASTOR_ALIGNED);
_vec_out *= _vec;
_vec_out.store(&_data[i], FASTOR_ALIGNED);
}
for (; i<dst.self().size(); ++i) {
_data[i] *= cnum;
}
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U> && !is_integral_v_<U>, bool> = false>
FASTOR_INLINE void trivial_assign_div(AbstractTensor<Derived,DIM> &dst, U num) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
T* _data = dst.self().data();
T cnum = T(1) / (T)num;
V _vec(cnum);
FASTOR_INDEX i = 0;
for (; i< ROUND_DOWN(dst.self().size(),V::Size); i+=V::Size) {
V _vec_out(&_data[i], FASTOR_ALIGNED);
_vec_out *= _vec;
_vec_out.store(&_data[i], FASTOR_ALIGNED);
}
for (; i<dst.self().size(); ++i) {
_data[i] *= cnum;
}
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U> && is_integral_v_<U>, bool> = false>
FASTOR_INLINE void trivial_assign_div(AbstractTensor<Derived,DIM> &dst, U num) {
using T = typename Derived::scalar_type;
using V = typename Derived::simd_vector_type;
T* _data = dst.self().data();
T cnum = (T)num;
V _vec(cnum);
FASTOR_INDEX i = 0;
for (; i< ROUND_DOWN(dst.self().size(),V::Size); i+=V::Size) {
V _vec_out(&_data[i], FASTOR_ALIGNED);
_vec_out /= _vec;
_vec_out.store(&_data[i], FASTOR_ALIGNED);
}
for (; i<dst.self().size(); ++i) {
_data[i] /= cnum;
}
}
//----------------------------------------------------------------------------------------------------------//
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
constexpr FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const Tensor<T,Rest...> &src) {
if (dst.self().data()==src.data()) return;
trivial_assign(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
constexpr FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const Tensor<T,Rest...> &src) {
trivial_assign_add(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
constexpr FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const Tensor<T,Rest...> &src) {
trivial_assign_sub(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
constexpr FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const Tensor<T,Rest...> &src) {
trivial_assign_mul(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
constexpr FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const Tensor<T,Rest...> &src) {
trivial_assign_div(dst.self(),src);
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>,bool> = false>
constexpr FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, U num) {
trivial_assign(dst.self(),num);
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>,bool> = false>
constexpr FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, U num) {
trivial_assign_add(dst.self(),num);
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>,bool> = false>
constexpr FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, U num) {
trivial_assign_sub(dst.self(),num);
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>,bool> = false>
constexpr FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, U num) {
trivial_assign_mul(dst.self(),num);
}
template<typename Derived, size_t DIM, typename U,
enable_if_t_<is_primitive_v_<U>,bool> = false>
constexpr FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, U num) {
trivial_assign_div(dst.self(),num);
}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
} // end of namespace Fastor
#endif // TENSOR_ASSIGNMENT_H

View File

@@ -0,0 +1,39 @@
#ifndef TENSOR_EVALUATOR_H
#define TENSOR_EVALUATOR_H
// Expression templates evaluators
//----------------------------------------------------------------------------------------------------------//
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
SIMDVector<U,simd_abi_type> _vec;
_vec.load(&_data[get_mem_index(i)],false);
return _vec;
}
template<typename U=T>
FASTOR_INLINE T eval_s(FASTOR_INDEX i) const {
return _data[get_mem_index(i)];
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
SIMDVector<U,simd_abi_type> _vec;
_vec.load(&_data[get_flat_index(i,j)],false);
return _vec;
}
template<typename U=T>
FASTOR_INLINE T eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _data[get_flat_index(i,j)];
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int, dimension_t::value> &as) const {
SIMDVector<U,simd_abi_type> _vec;
_vec.load(&_data[get_flat_index(as)],false);
return _vec;
}
template<typename U=T>
FASTOR_INLINE T teval_s(const std::array<int, dimension_t::value> &as) const {
return _data[get_flat_index(as)];
}
//----------------------------------------------------------------------------------------------------------//
#endif // end of TENSOR_EVALUATOR_H

View File

@@ -0,0 +1,215 @@
#ifndef TENSOR_FUNCTIONS_H
#define TENSOR_FUNCTIONS_H
#include "Fastor/meta/meta.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/TensorMap.h"
#include "Fastor/tensor/TensorTraits.h"
namespace Fastor {
/* Turns a row-major tensor to column-major */
template<template<typename,size_t...> class TensorType, typename T, size_t ... Rest>
FASTOR_INLINE Tensor<T,Rest...> tocolumnmajor(const TensorType<T,Rest...> &a) {
constexpr int Dimension = sizeof...(Rest);
if (Dimension < 2) {
return a;
}
else {
Tensor<T,Rest...> out;
T *arr_out = out.data();
const T *a_data = a.data();
if (Dimension == 2) {
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
for (FASTOR_INDEX i=0; i<M; ++i) {
for (FASTOR_INDEX j=0; j<N; ++j) {
arr_out[i*N+j] = a_data[j*M+i];
}
}
}
else {
constexpr int Size = pack_prod<Rest...>::value;
std::array<size_t,Dimension> products_ = nprods_views<Index<Rest...>,
typename std_ext::make_index_sequence<Dimension>::type>::values;
FASTOR_INDEX DimensionHolder[Dimension] = {Rest...};
std::reverse(DimensionHolder,DimensionHolder+Dimension);
std::reverse(products_.begin(),products_.end());
std::array<int,Dimension> as = {};
int jt;
FASTOR_INDEX counter=0;
while(counter < Size)
{
FASTOR_INDEX index = 0;
for (int ii=0; ii<Dimension; ++ii) {
index += products_[ii]*as[ii];
}
arr_out[index] = a_data[counter];
counter++;
for(jt = Dimension-1; jt>=0; jt--)
{
as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
}
return out;
}
}
/* Turns a column-major tensor to row-major */
template<template<typename,size_t...> class TensorType, typename T, size_t ... Rest>
FASTOR_INLINE Tensor<T,Rest...> torowmajor(const TensorType<T,Rest...> &a) {
constexpr int Dimension = sizeof...(Rest);
if (Dimension < 2) {
return a;
}
else {
Tensor<T,Rest...> out;
T *arr_out = out.data();
const T *a_data = a.data();
if (Dimension == 2) {
constexpr FASTOR_INDEX M = get_value<1,Rest...>::value;
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
for (FASTOR_INDEX i=0; i<M; ++i) {
for (FASTOR_INDEX j=0; j<N; ++j) {
arr_out[j*M+i] = a_data[i*N+j];
}
}
}
else {
constexpr int Size = pack_prod<Rest...>::value;
std::array<size_t,Dimension> products_ = nprods_views<Index<Rest...>,
typename std_ext::make_index_sequence<Dimension>::type>::values;
FASTOR_INDEX DimensionHolder[Dimension] = {Rest...};
std::reverse(DimensionHolder,DimensionHolder+Dimension);
std::reverse(products_.begin(),products_.end());
std::array<int,Dimension> as = {};
int jt;
FASTOR_INDEX counter=0;
while(counter < Size)
{
FASTOR_INDEX index = 0;
for (int ii=0; ii<Dimension; ++ii) {
index += products_[ii]*as[ii];
}
arr_out[counter] = a_data[index];
counter++;
for(jt = Dimension-1; jt>=0; jt--)
{
as[jt] +=1;
if(as[jt]<DimensionHolder[jt])
break;
else
as[jt]=0;
}
if(jt<0)
break;
}
}
return out;
}
}
/* squeeze - removes dimenions of 1 from a tensor and returns a TensorMap
A TensorMap is a view in to an existing tensor so modifying the squeezed
tensor will modify the original tensor and vice versa
Note that you cannot call this function on tensor expressions as this is
a view in to a concrete tensor type holding storage
*/
template<template <typename,size_t...> class TensorType, typename T, size_t ... Rest>
FASTOR_INLINE
index_to_tensor_map_t<T,filter_t<1,Rest...>>
squeeze(const TensorType<T,Rest...> &a) {
return index_to_tensor_map_t<T,filter_t<1,Rest...>>(a.data());
}
/* reshape - reshapes a tensor to a tensor of different shape and returns a TensorMap
A TensorMap is a view in to an existing tensor so modifying the reshaped
tensor will modify the original tensor and vice versa
Note that you cannot call this function on tensor expressions as this is
a view in to a concrete tensor type holding storage
example:
auto b = reshape<shapes...>(a);
*/
template<size_t ... shapes,typename T, size_t ... Rest>
FASTOR_INLINE TensorMap<T,shapes...> reshape(const Tensor<T,Rest...> &a) {
static_assert(pack_prod<shapes...>::value==pack_prod<Rest...>::value, "SIZE OF TENSOR SHOULD REMAIN THE SAME DURING RESHAPE");
return TensorMap<T,shapes...>(a.data());
}
/* flatten - creates a flattened 1D view of a tensor and returns a TensorMap
A TensorMap is a view in to an existing tensor so modifying the reshaped
tensor will modify the original tensor and vice versa
Note that you cannot call this function on tensor expressions as this is
a view in to a concrete tensor type holding storage
example:
auto b = flatten(a);
*/
template<typename T, size_t ... Rest>
FASTOR_INLINE TensorMap<T,pack_prod<Rest...>::value> flatten(const Tensor<T,Rest...> &a) {
return TensorMap<T,pack_prod<Rest...>::value>(a.data());
}
#if FASTOR_NIL
// Constant tensors
static FASTOR_INLINE
Tensor<float,3,3,3> levi_civita_ps() {
Tensor<float,3,3,3> LeCi_ps;
LeCi_ps(0,1,2) = 1.f;
LeCi_ps(1,2,0) = 1.f;
LeCi_ps(2,0,1) = 1.f;
LeCi_ps(1,0,2) = -1.f;
LeCi_ps(2,1,0) = -1.f;
LeCi_ps(0,2,1) = -1.f;
return LeCi_ps;
}
static FASTOR_INLINE
Tensor<double,3,3,3> levi_civita_pd() {
Tensor<double,3,3,3> LeCi_pd;
LeCi_pd(0,1,2) = 1.;
LeCi_pd(1,2,0) = 1.;
LeCi_pd(2,0,1) = 1.;
LeCi_pd(1,0,2) = -1.;
LeCi_pd(2,1,0) = -1.;
LeCi_pd(0,2,1) = -1.;
return LeCi_pd;
}
template<typename T, size_t ... Rest>
static FASTOR_INLINE
Tensor<T,Rest...> kronecker_delta() {
Tensor<T,Rest...> out; out.eye();
return out;
}
#endif
}
#endif // TENSOR_FUNCTIONS_H

View File

@@ -0,0 +1,180 @@
#ifndef TENSOR_PRINT_H
#define TENSOR_PRINT_H
#include "Fastor/tensor/Tensor.h"
namespace Fastor {
namespace internal {
template<typename T>
using std_matrix = typename std::vector<std::vector<T>>::type;
// Generate combinations
template<size_t M, size_t N, size_t ... Rest>
FASTOR_INLINE std::vector<std::vector<int>> index_generator() {
// Do NOT change int to size_t, comparison overflows
std::vector<std::vector<int>> idx; idx.resize(pack_prod<M,N,Rest...>::value);
std::array<int,sizeof...(Rest)+2> maxes = {M,N,Rest...};
std::array<int,sizeof...(Rest)+2> a;
int i,j;
std::fill(a.begin(),a.end(),0);
auto counter=0;
while(1)
{
std::vector<int> current_idx; //current_idx.reserve(sizeof...(Rest)+2);
for(i = 0; i< sizeof...(Rest)+2; i++) {
current_idx.push_back(a[i]);
}
idx[counter] = current_idx;
counter++;
for(j = sizeof...(Rest)+2-1 ; j>=0 ; j--)
{
if(++a[j]<maxes[j])
break;
else
a[j]=0;
}
if(j<0)
break;
}
return idx;
}
template<typename T>
int get_row_width(const std::ostream &os, const T *a_data, size_t size) {
// compute the largest width
int width = 0;
for(size_t j = 0; j < size; ++j)
{
std::stringstream sstr;
sstr.copyfmt(os);
sstr << a_data[j];
width = std::max<int>(width, int(sstr.str().length()));
}
return width;
}
template<template<typename,size_t...> class t_type, typename T, size_t ...Rest>
int get_row_width(const std::ostream &os, const t_type<T,Rest...>& a) {
int width = 0;
for(size_t j = 0; j < pack_prod<Rest...>::value; ++j)
{
std::stringstream sstr;
sstr.copyfmt(os);
sstr << a.eval_s(j);
width = std::max<int>(width, int(sstr.str().length()));
}
return width;
}
} // end of namespace internal
#define FASTOR_MAKE_OS_STREAM_TENSOR0(t_type) \
template<typename T>\
FASTOR_HINT_INLINE std::ostream& operator<<(std::ostream &os, const t_type<T> &a) {\
IOFormat fmt = FASTOR_DEFINE_IO_FORMAT;\
os.precision(fmt._precision);\
os << *a.data();\
return os;\
}\
#define FASTOR_MAKE_OS_STREAM_TENSOR1(t_type) \
template<typename T, size_t M> \
FASTOR_HINT_INLINE std::ostream& operator<<(std::ostream &os, const t_type<T,M> &a) {\
IOFormat fmt = FASTOR_DEFINE_IO_FORMAT;\
os.precision(fmt._precision);\
int width = internal::get_row_width(os, a);\
for(size_t i = 0; i < M; ++i)\
{\
os << fmt._rowprefix;\
if(width) os.width(width);\
os << a(i);\
os << fmt._rowsuffix;\
os << fmt._rowsep;\
}\
return os;\
}\
#define FASTOR_MAKE_OS_STREAM_TENSOR2(t_type) \
template<typename T, size_t M, size_t N> \
FASTOR_HINT_INLINE std::ostream& operator<<(std::ostream &os, const t_type<T,M,N> &a) { \
IOFormat fmt = FASTOR_DEFINE_IO_FORMAT; \
os.precision(fmt._precision); \
int width = internal::get_row_width(os, a); \
for(size_t i = 0; i < M; ++i) \
{\
os << fmt._rowprefix;\
if(width) os.width(width);\
os << a(i, 0);\
for(size_t j = 1; j < N; ++j)\
{\
os << fmt._colsep;\
if(width) os.width(width);\
os << a(i, j);\
}\
os << fmt._rowsuffix;\
if( i < M - 1)\
os << fmt._rowsep;\
}\
return os;\
}\
#define FASTOR_MAKE_OS_STREAM_TENSORn(t_type) \
template<typename T, size_t ... Rest, typename std::enable_if<sizeof...(Rest)>=3,bool>::type=0> \
FASTOR_HINT_INLINE std::ostream& operator<<(std::ostream &os, const t_type<T,Rest...> &a) {\
IOFormat fmt = FASTOR_DEFINE_IO_FORMAT;\
constexpr std::array<int,sizeof...(Rest)> DimensionHolder = {Rest...};\
constexpr int M = get_value<sizeof...(Rest)-1,Rest...>::value;\
constexpr int N = get_value<sizeof...(Rest),Rest...>::value;\
constexpr int lastrowcol = M*N;\
constexpr size_t prods = pack_prod<Rest...>::value;\
std::vector<std::vector<int>> combs = internal::index_generator<Rest...>();\
os.precision(fmt._precision);\
int width = internal::get_row_width(os, a);\
for (size_t dims=0; dims<prods/M/N; ++dims) {\
if (fmt._print_dimensions)\
{\
os << "[";\
for (size_t kk=0; kk<sizeof...(Rest)-2; ++kk) {\
os << combs[lastrowcol*dims][kk] << ",";\
}\
os << ":,:]\n";\
}\
else {\
if (dims)\
os << "\n";\
}\
for(size_t i = 0; i < DimensionHolder[a.Dimension-2]; ++i)\
{\
os << fmt._rowprefix;\
if(width) os.width(width);\
os << a.eval_s(i*DimensionHolder[a.Dimension-1]+0+lastrowcol*dims);\
for(int j = 1; j < DimensionHolder[a.Dimension-1]; ++j)\
{\
os << fmt._colsep;\
if(width) os.width(width);\
os << a.eval_s(i*DimensionHolder[a.Dimension-1]+j+lastrowcol*dims);\
}\
os << fmt._rowsuffix + fmt._rowsep;\
}\
}\
return os;\
}\
FASTOR_MAKE_OS_STREAM_TENSOR0(Tensor)
FASTOR_MAKE_OS_STREAM_TENSOR1(Tensor)
FASTOR_MAKE_OS_STREAM_TENSOR2(Tensor)
FASTOR_MAKE_OS_STREAM_TENSORn(Tensor)
}
#endif // TENSOR_PRINT_H

View File

@@ -0,0 +1,58 @@
#ifndef TENSOR_INPLACE_OPERATORS_H
#define TENSOR_INPLACE_OPERATORS_H
// CRTP Overloads for nth rank Tensors
//---------------------------------------------------------------------------------------------//
template<typename Derived, size_t DIMS>
FASTOR_INLINE auto& operator +=(const AbstractTensor<Derived,DIMS>& src_) {
assign_add(*this, src_.self());
return *this;
}
template<typename Derived, size_t DIMS>
FASTOR_INLINE auto& operator -=(const AbstractTensor<Derived,DIMS>& src_) {
assign_sub(*this, src_.self());
return *this;
}
template<typename Derived, size_t DIMS>
FASTOR_INLINE auto& operator *=(const AbstractTensor<Derived,DIMS>& src_) {
assign_mul(*this, src_.self());
return *this;
}
template<typename Derived, size_t DIMS>
FASTOR_INLINE auto& operator /=(const AbstractTensor<Derived,DIMS>& src_) {
assign_div(*this, src_.self());
return *this;
}
//---------------------------------------------------------------------------------------------//
// Scalar overloads for in-place operators
//---------------------------------------------------------------------------------------------//
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = 0 >
FASTOR_INLINE auto& operator +=(U num) {
trivial_assign_add(*this, num);
return *this;
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = 0 >
FASTOR_INLINE auto& operator -=(U num) {
trivial_assign_sub(*this, num);
return *this;
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = 0 >
FASTOR_INLINE auto& operator *=(U num) {
trivial_assign_mul(*this, num);
return *this;
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = 0 >
FASTOR_INLINE auto& operator /=(U num) {
trivial_assign_div(*this, num);
return *this;
}
//---------------------------------------------------------------------------------------------//
#endif // TENSOR_INPLACE_OPERATORS_H

View File

@@ -0,0 +1,170 @@
#ifndef TENSOR_MAP_H
#define TENSOR_MAP_H
#include "Fastor/config/config.h"
#include "Fastor/backend/backend.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/ForwardDeclare.h"
#include "Fastor/expressions/linalg_ops/linalg_ops.h"
#include "Fastor/tensor/TensorIO.h"
namespace Fastor {
template<typename T, size_t ... Rest>
class TensorMap: public AbstractTensor<TensorMap<T, Rest...>,sizeof...(Rest)> {
public:
using scalar_type = T;
using simd_vector_type = choose_best_simd_vector_t<T>;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<remove_all_t<T>,Rest...>;
using dimension_t = std::integral_constant<FASTOR_INDEX, sizeof...(Rest)>;
static constexpr FASTOR_INLINE FASTOR_INDEX rank() {return sizeof...(Rest);}
static constexpr FASTOR_INLINE FASTOR_INDEX size() {return pack_prod<Rest...>::value;}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX dim) const {
#if FASTOR_SHAPE_CHECK
FASTOR_ASSERT(dim>=0 && dim < sizeof...(Rest), "TENSOR SHAPE MISMATCH");
#endif
const FASTOR_INDEX DimensionHolder[sizeof...(Rest)] = {Rest...};
return DimensionHolder[dim];
}
FASTOR_INLINE Tensor<T,Rest...>& noalias() {return *this;}
// Constructors
//----------------------------------------------------------------------------------------------------------//
constexpr TensorMap(scalar_type* data) : _data(data) {}
template<size_t ... RestOther> constexpr TensorMap(Tensor<T,RestOther...> &a) : _data(a.data()) {}
//----------------------------------------------------------------------------------------------------------//
// Raw pointer providers
//----------------------------------------------------------------------------------------------------------//
FASTOR_INLINE T* data() const { return const_cast<T*>(this->_data);}
FASTOR_INLINE T* data() {return this->_data;}
//----------------------------------------------------------------------------------------------------------//
// Scalar indexing
//----------------------------------------------------------------------------------------------------------//
#undef SCALAR_INDEXING_NONCONST_H
#undef SCALAR_INDEXING_CONST_H
#undef INDEX_RETRIEVER_H
#include "Fastor/tensor/IndexRetriever.h"
#include "Fastor/tensor/ScalarIndexing.h"
#define INDEX_RETRIEVER_H
#define SCALAR_INDEXING_NONCONST_H
#define SCALAR_INDEXING_CONST_H
// Block indexing (all variants excluding iseq)
//----------------------------------------------------------------------------------------------------------//
template<typename ... Seq, enable_if_t_<!is_arithmetic_pack_v<Seq...> && !is_fixed_sequence_pack_v<Seq...>,bool> = false>
FASTOR_INLINE TensorViewExpr<TensorMap<T,Rest...>,sizeof...(Seq)> operator()(Seq ... _seqs) {
static_assert(dimension_t::value==sizeof...(Seq),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorViewExpr<TensorMap<T,Rest...>,sizeof...(Seq)>(*this, {_seqs...});
}
template<typename ...Fseq, enable_if_t_<is_fixed_sequence_pack_v<Fseq...>,bool> = false>
FASTOR_INLINE TensorFixedViewExprnD<TensorMap<T,Rest...>,Fseq...> operator()(Fseq... ) {
static_assert(dimension_t::value==sizeof...(Fseq),"INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
return TensorFixedViewExprnD<TensorMap<T,Rest...>,Fseq...>(*this);
}
FASTOR_INLINE TensorFilterViewExpr<TensorMap<T,Rest...>,Tensor<bool,Rest...>,sizeof...(Rest)>
operator()(const Tensor<bool,Rest...> &_fl) {
return TensorFilterViewExpr<TensorMap<T,Rest...>,Tensor<bool,Rest...>,sizeof...(Rest)>(*this,_fl);
}
FASTOR_INLINE TensorFilterViewExpr<TensorMap<T,Rest...>,TensorMap<bool,Rest...>,sizeof...(Rest)>
operator()(const TensorMap<bool,Rest...> &_fl) {
return TensorFilterViewExpr<TensorMap<T,Rest...>,TensorMap<bool,Rest...>,sizeof...(Rest)>(*this,_fl);
}
//----------------------------------------------------------------------------------------------------------//
// Expression templates evaluators
//----------------------------------------------------------------------------------------------------------//
#undef TENSOR_EVALUATOR_H
#include "Fastor/tensor/TensorEvaluator.h"
#define TENSOR_EVALUATOR_H
//----------------------------------------------------------------------------------------------------------//
// No constructor should be added
// Provide generic AbstractTensors copy constructor though
//----------------------------------------------------------------------------------------------------------//
template<typename Derived, size_t DIMS>
FASTOR_INLINE void operator=(const AbstractTensor<Derived,DIMS>& src) {
FASTOR_ASSERT(src.self().size()==size(), "TENSOR SIZE MISMATCH");
assign(*this, src.self());
}
// AbstractTensor and scalar in-place operators
//----------------------------------------------------------------------------------------------------------//
#undef TENSOR_INPLACE_OPERATORS_H
#include "Fastor/tensor/TensorInplaceOperators.h"
#define TENSOR_INPLACE_OPERATORS_H
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
#undef TENSOR_METHODS_CONST_H
#undef TENSOR_METHODS_NONCONST_H
#include "Fastor/tensor/TensorMethods.h"
#define TENSOR_METHODS_CONST_H
#define TENSOR_METHODS_NONCONST_H
//----------------------------------------------------------------------------------------------------------//
// Converters
//----------------------------------------------------------------------------------------------------------//
#undef PODCONVERTERS_H
#include "Fastor/tensor/PODConverters.h"
#define PODCONVERTERS_H
//----------------------------------------------------------------------------------------------------------//
// Cast method
//----------------------------------------------------------------------------------------------------------//
template<typename U>
FASTOR_INLINE Tensor<U,Rest...> cast() const {
Tensor<U,Rest...> out;
U *out_data = out.data();
for (FASTOR_INDEX i=0; i<size(); ++i) {
out_data[get_mem_index(i)] = static_cast<U>(_data[i]);
}
return out;
}
//----------------------------------------------------------------------------------------------------------//
private:
scalar_type* _data;
};
FASTOR_MAKE_OS_STREAM_TENSOR0(TensorMap)
FASTOR_MAKE_OS_STREAM_TENSOR1(TensorMap)
FASTOR_MAKE_OS_STREAM_TENSOR2(TensorMap)
FASTOR_MAKE_OS_STREAM_TENSORn(TensorMap)
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const TensorMap<T,Rest...> &src) {
if (dst.self().data()==src.data()) return;
trivial_assign(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const TensorMap<T,Rest...> &src) {
trivial_assign_add(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const TensorMap<T,Rest...> &src) {
trivial_assign_sub(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const TensorMap<T,Rest...> &src) {
trivial_assign_mul(dst.self(),src);
}
template<typename Derived, size_t DIM, typename T, size_t ...Rest>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const TensorMap<T,Rest...> &src) {
trivial_assign_div(dst.self(),src);
}
}
#endif // TENSOR_MAP_H

View File

@@ -0,0 +1,167 @@
#ifndef TENSOR_METHODS_NONCONST_H
#define TENSOR_METHODS_NONCONST_H
FASTOR_INLINE void fill(T num0) {
FASTOR_INDEX i = 0UL;
using V = simd_vector_type;
V _vec(num0);
for (; i<ROUND_DOWN(size(),V::Size); i+=V::Size) {
_vec.store(&_data[i],false);
}
for (; i<size(); ++i) _data[i] = num0;
}
FASTOR_INLINE void iota(T num0=0) {
iota_impl(_data, &_data[size()], num0);
}
FASTOR_INLINE void arange(T num0=0) {
iota_impl(_data, &_data[size()], num0);
// T num = static_cast<T>(num0);
// using V = SIMDVector<T,simd_abi_type>;
// V _vec;
// FASTOR_INDEX i=0;
// for (; i<ROUND_DOWN(size(),V::Size); i+=V::Size) {
// _vec.set_sequential(T(i)+num);
// _vec.store(&_data[i],false);
// }
// for (; i<size(); ++i) _data[i] = T(i)+num;
}
FASTOR_INLINE void zeros() {
using V = simd_vector_type;
V _zeros;
FASTOR_INDEX i=0;
for (; i<ROUND_DOWN(size(),V::Size); i+=V::Size) {
_zeros.store(&_data[i],false);
}
for (; i<size(); ++i) _data[i] = 0;
}
FASTOR_INLINE void ones() {
this->fill(static_cast<T>(1));
}
FASTOR_INLINE void eye2() {
// Second order identity tensor (identity matrices)
static_assert(sizeof...(Rest)==2, "CANNOT BUILD AN IDENTITY TENSOR");
static_assert(no_of_unique<Rest...>::value==1, "TENSOR MUST BE UNIFORM");
constexpr FASTOR_INDEX N = get_value<2,Rest...>::value;
zeros();
for (FASTOR_INDEX i=0; i<N; ++i) {
_data[i*N+i] = (T)1;
}
}
FASTOR_INLINE void eye() {
// Arbitrary order identity tensor
static_assert(sizeof...(Rest)>=2, "CANNOT BUILD AN IDENTITY TENSOR");
static_assert(no_of_unique<Rest...>::value==1, "TENSOR MUST BE UNIFORM");
zeros();
constexpr int ndim = sizeof...(Rest);
constexpr std::array<int,ndim> maxes_a = {Rest...};
std::array<int,ndim> products;
std::fill(products.begin(),products.end(),0);
for (int j=ndim-1; j>0; --j) {
int num = maxes_a[ndim-1];
for (int k=0; k<j-1; ++k) {
num *= maxes_a[ndim-1-k-1];
}
products[j] = num;
}
std::reverse(products.begin(),products.end());
for (FASTOR_INDEX i=0; i<dimension(0); ++i) {
int index_a = i;
for(int it = 0; it< ndim; it++) {
index_a += products[it]*i;
}
_data[index_a] = static_cast<T>(1);
}
}
FASTOR_INLINE void random() {
//! Populate tensor with random FP numbers
for (FASTOR_INDEX i=0; i<size(); ++i) {
_data[get_mem_index(i)] = (T)rand()/RAND_MAX;
}
}
FASTOR_INLINE void randint() {
//! Populate tensor with random integer numbers
for (FASTOR_INDEX i=0; i<size(); ++i) {
_data[get_mem_index(i)] = (T)rand();
}
}
FASTOR_INLINE void reverse() {
// in-place reverse
if ((size()==0) || (size()==1)) return;
// std::reverse(_data,_data+Size); return;
// This requires copying the data to avoid aliasing
// Despite that this method seems to be faster than
// std::reverse for big _data both on GCC and Clang
FASTOR_ARCH_ALIGN T tmp[size()];
std::copy(_data,_data+size(),tmp);
// Although SSE register reversing is faster
// The AVX one outperforms it
using V = SIMDVector<T,simd_abi_type>;
V vec;
FASTOR_INDEX i = 0;
for (; i< ROUND_DOWN(size(),V::Size); i+=V::Size) {
vec.load(&tmp[size() - i - V::Size],false);
vec.reverse().store(&_data[i],false);
}
for (; i< size(); ++i) {
_data[i] = tmp[size()-i-1];
}
}
#endif // TENSOR_METHODS_NONCONST_H
#ifndef TENSOR_METHODS_CONST_H
#define TENSOR_METHODS_CONST_H
FASTOR_INLINE T sum() const {
if ((size()==0) || (size()==1)) return _data[0];
using V = SIMDVector<T,simd_abi_type>;
V vec = static_cast<T>(0);
V _vec_in;
FASTOR_INDEX i = 0;
for (; i<ROUND_DOWN(size(),V::Size); i+=V::Size) {
_vec_in.load(&_data[i],false);
vec += _vec_in;
}
T scalar = static_cast<T>(0);
for (; i< size(); ++i) {
scalar += _data[i];
}
return vec.sum() + scalar;
}
FASTOR_INLINE T product() const {
if ((size()==0) || (size()==1)) return _data[0];
using V = SIMDVector<T,simd_abi_type>;
FASTOR_INDEX i = 0;
V vec = static_cast<T>(1);
for (; i< ROUND_DOWN(size(),V::Size); i+=V::Size) {
vec *= V(&_data[i],false);
}
T scalar = static_cast<T>(1);
for (; i< size(); ++i) {
scalar *= _data[i];
}
return vec.product()*scalar;
}
#endif // TENSOR_METHODS_CONST_H

View File

@@ -0,0 +1,303 @@
#ifndef TENSOR_POST_META_H
#define TENSOR_POST_META_H
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor_algebra/indicial.h"
namespace Fastor {
/* Classify/specialise Tensor<primitive> as primitive if needed.
This specialisation hurts the performance of some specialised
kernels like matmul/norm/LU/inv that unroll aggressively unless
Tensor<T> is specialised to wrap T only
*/
//--------------------------------------------------------------------------------------------------------------------//
// template<typename T>
// struct is_primitive<Tensor<T>> {
// static constexpr bool value = is_primitive_v_<T> ? true : false;
// };
//--------------------------------------------------------------------------------------------------------------------//
/* Find the underlying scalar type of an expression */
//--------------------------------------------------------------------------------------------------------------------//
template<class T>
struct scalar_type_finder {
using type = T;
};
template<typename T, size_t ... Rest>
struct scalar_type_finder<Tensor<T,Rest...>> {
using type = T;
};
// This specific specialisation is needed to avoid ambiguity for vectors
template<typename T, size_t N>
struct scalar_type_finder<Tensor<T,N>> {
using type = T;
};
template<typename T, size_t ... Rest>
struct scalar_type_finder<TensorMap<T,Rest...>> {
using type = T;
};
// This specific specialisation is needed to avoid ambiguity for vectors
template<typename T, size_t N>
struct scalar_type_finder<TensorMap<T,N>> {
using type = T;
};
template<template <class,size_t> class UnaryExpr, typename Expr, size_t DIMS>
struct scalar_type_finder<UnaryExpr<Expr,DIMS>> {
using type = typename scalar_type_finder<Expr>::type;
};
template<template <class,class,size_t> class Expr, typename TLhs, typename TRhs, size_t DIMS>
struct scalar_type_finder<Expr<TLhs,TRhs,DIMS>> {
using type = typename std::conditional<is_primitive_v_<TLhs>,
typename scalar_type_finder<TRhs>::type, typename scalar_type_finder<TLhs>::type>::type;
};
template<template<typename,typename,typename,size_t> class TensorFixedViewExpr,
typename Expr, typename Seq0, typename Seq1, size_t DIMS>
struct scalar_type_finder<TensorFixedViewExpr<Expr,Seq0,Seq1,DIMS>> {
using type = typename scalar_type_finder<Expr>::type;
};
template<template<typename,size_t...> class TensorType, typename T, size_t ...Rest, typename ... Fseqs>
struct scalar_type_finder<TensorConstFixedViewExprnD<TensorType<T,Rest...>,Fseqs...>> {
using type = T;
};
template<template<typename,size_t...> class TensorType, typename T, size_t ...Rest, typename ... Fseqs>
struct scalar_type_finder<TensorFixedViewExprnD<TensorType<T,Rest...>,Fseqs...>> {
using type = T;
};
//--------------------------------------------------------------------------------------------------------------------//
/* Find the underlying tensor type of an expression */
//--------------------------------------------------------------------------------------------------------------------//
template<class X>
struct tensor_type_finder {
using type = Tensor<X>;
};
template<typename T, size_t ... Rest>
struct tensor_type_finder<Tensor<T,Rest...>> {
using type = Tensor<T,Rest...>;
};
// This specific specialisation is needed to avoid ambiguity for vectors
template<typename T, size_t N>
struct tensor_type_finder<Tensor<T,N>> {
using type = Tensor<T,N>;
};
template<typename T, size_t ... Rest>
struct tensor_type_finder<TensorMap<T,Rest...>> {
using type = Tensor<T,Rest...>;
};
// This specific specialisation is needed to avoid ambiguity for vectors
template<typename T, size_t N>
struct tensor_type_finder<TensorMap<T,N>> {
using type = Tensor<T,N>;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct tensor_type_finder<UnaryExpr<Expr,DIM>> {
using type = typename tensor_type_finder<Expr>::type;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct tensor_type_finder<BinaryExpr<TLhs,TRhs,DIMS>> {
using type = typename std::conditional<is_primitive_v_<TLhs>,
typename tensor_type_finder<TRhs>::type, typename tensor_type_finder<TLhs>::type>::type;
};
template<template<typename,typename,typename,size_t> class TensorFixedViewExpr,
typename Expr, typename Seq0, typename Seq1, size_t DIMS>
struct tensor_type_finder<TensorFixedViewExpr<Expr,Seq0,Seq1,DIMS>> {
using type = typename tensor_type_finder<Expr>::type;
};
template<template<typename,size_t...> class TensorType, typename T, size_t ...Rest, typename ... Fseqs>
struct tensor_type_finder<TensorConstFixedViewExprnD<TensorType<T,Rest...>,Fseqs...>> {
using type = TensorType<T,Rest...>;
};
template<template<typename,size_t...> class TensorType, typename T, size_t ...Rest, typename ... Fseqs>
struct tensor_type_finder<TensorFixedViewExprnD<TensorType<T,Rest...>,Fseqs...>> {
using type = TensorType<T,Rest...>;
};
//--------------------------------------------------------------------------------------------------------------------//
/* Is an expression a tensor */
//--------------------------------------------------------------------------------------------------------------------//
template<class T>
struct is_tensor {
static constexpr bool value = false;
};
template<class T, size_t ...Rest>
struct is_tensor<Tensor<T,Rest...>> {
static constexpr bool value = true;
};
template<typename T>
constexpr bool is_tensor_v = is_tensor<T>::value;
//--------------------------------------------------------------------------------------------------------------------//
/* Is an expression a abstract tensor */
//--------------------------------------------------------------------------------------------------------------------//
template<class T>
struct is_abstracttensor {
static constexpr bool value = false;
};
template<class T, size_t DIMS>
struct is_abstracttensor<AbstractTensor<T,DIMS>> {
static constexpr bool value = true;
};
template<typename T>
constexpr bool is_abstracttensor_v = is_abstracttensor<T>::value;
//--------------------------------------------------------------------------------------------------------------------//
/* Convert a tensor to a bool tensor */
//--------------------------------------------------------------------------------------------------------------------//
template <class Tens>
struct to_bool_tensor;
template <typename T, size_t ... Rest>
struct to_bool_tensor<Tensor<T,Rest...>> {
using type = Tensor<bool,Rest...>;
};
template <class Tens>
using to_bool_tensor_t = typename to_bool_tensor<Tens>::type;
//--------------------------------------------------------------------------------------------------------------------//
/* Concatenate two tensor and make a new tensor type */
//--------------------------------------------------------------------------------------------------------------------//
// Do not generalise this, as it leads to all kinds of problems
// with binary operator expression involving std::arithmetic
template <class X, class Y, class ... Z>
struct concat_tensor;
template<template<typename,size_t...> class Derived0,
template<typename,size_t...> class Derived1,
typename T, size_t ... Rest0, size_t ... Rest1>
struct concat_tensor<Derived0<T,Rest0...>,Derived1<T,Rest1...>> {
using type = Tensor<T,Rest0...,Rest1...>;
};
template<template<typename,size_t...> class Derived0,
template<typename,size_t...> class Derived1,
template<typename,size_t...> class Derived2,
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2>
struct concat_tensor<Derived0<T,Rest0...>,Derived1<T,Rest1...>,Derived2<T,Rest2...>> {
using type = Tensor<T,Rest0...,Rest1...,Rest2...>;
};
template<template<typename,size_t...> class Derived0,
template<typename,size_t...> class Derived1,
template<typename,size_t...> class Derived2,
template<typename,size_t...> class Derived3,
typename T, size_t ... Rest0, size_t ... Rest1, size_t ... Rest2, size_t ... Rest3>
struct concat_tensor<Derived0<T,Rest0...>,Derived1<T,Rest1...>,Derived2<T,Rest2...>,Derived3<T,Rest3...>> {
using type = Tensor<T,Rest0...,Rest1...,Rest2...,Rest3...>;
};
template <class X, class Y, class ... Z>
using concatenated_tensor_t = typename concat_tensor<X,Y,Z...>::type;
//--------------------------------------------------------------------------------------------------------------------//
/* Extract the tensor dimension(s) */
//--------------------------------------------------------------------------------------------------------------------//
// Return dimensions of tensor as a std::array and Index<Rest...>
template<class X>
struct get_tensor_dimensions;
template<typename T, size_t ... Rest>
struct get_tensor_dimensions<Tensor<T,Rest...>> {
static constexpr std::array<size_t,sizeof...(Rest)> dims = {Rest...};
static constexpr std::array<int,sizeof...(Rest)> dims_int = {Rest...};
using tensor_to_index = Index<Rest...>;
};
template<typename T, size_t ... Rest>
constexpr std::array<size_t,sizeof...(Rest)> get_tensor_dimensions<Tensor<T,Rest...>>::dims;
template<typename T, size_t ... Rest>
constexpr std::array<int,sizeof...(Rest)> get_tensor_dimensions<Tensor<T,Rest...>>::dims_int;
// Conditional get tensor dimension
// Return tensor dimension if Idx is within range else return Dim
template<size_t Idx, size_t Dim, class X>
struct if_get_tensor_dimension;
template<size_t Idx, size_t Dim, typename T, size_t ... Rest>
struct if_get_tensor_dimension<Idx,Dim,Tensor<T,Rest...>> {
static constexpr size_t value = (Idx < sizeof...(Rest)) ? get_value<Idx+1,Rest...>::value : 1;
};
template<size_t Idx, size_t Dim, class X>
static constexpr size_t if_get_tensor_dimension_v = if_get_tensor_dimension<Idx,Dim,X>::value;
// Gives one if Idx is outside range
template<size_t Idx, class X>
static constexpr size_t get_tensor_dimension_v = if_get_tensor_dimension<Idx,1,X>::value;
//--------------------------------------------------------------------------------------------------------------------//
/* Find if a tensor is uniform */
//--------------------------------------------------------------------------------------------------------------------//
template<class T>
struct is_tensor_uniform;
template<typename T, size_t ... Rest>
struct is_tensor_uniform<Tensor<T,Rest...>> {
static constexpr bool value = no_of_unique<Rest...>::value == 1 ? true : false;
};
// helper function
template<class T>
static constexpr bool is_tensor_uniform_v = is_tensor_uniform<T>::value;
//--------------------------------------------------------------------------------------------------------------------//
/* Extract a matrix from a high order tensor */
//--------------------------------------------------------------------------------------------------------------------//
// This is used in functions like determinant/inverse of high order tensors
// where the last square matrix (last two dimensions) is needed. If Seq is
// is the same size as dimensions of tensor, this could also be used as
// generic tensor dimension extractor
template<class Tens, class Seq>
struct last_matrix_extracter;
template<typename T, size_t ... Rest, size_t ... ss>
struct last_matrix_extracter<Tensor<T,Rest...>,std_ext::index_sequence<ss...>>
{
static constexpr std::array<size_t,sizeof...(Rest)> dims = {Rest...};
static constexpr std::array<size_t,sizeof...(ss)> values = {dims[ss]...};
static constexpr size_t remaining_product = pack_prod<dims[ss]...>::value;
using type = Tensor<T,dims[ss]...>;
};
template<typename T, size_t ... Rest, size_t ... ss>
constexpr std::array<size_t,sizeof...(ss)>
last_matrix_extracter<Tensor<T,Rest...>,std_ext::index_sequence<ss...>>::values;
//--------------------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
template <typename T, typename Idx> struct index_to_tensor;
template <typename T, size_t ...Idx> struct index_to_tensor <T, Index<Idx...>> { using type = Tensor<T,Idx...>; };
// helper
template <typename T, typename Idx>
using index_to_tensor_t = typename index_to_tensor<T,Idx>::type;
template <typename T, typename Idx> struct index_to_tensor_map;
template <typename T, size_t ...Idx> struct index_to_tensor_map <T, Index<Idx...>> { using type = TensorMap<T,Idx...>; };
// helper
template <typename T, typename Idx>
using index_to_tensor_map_t = typename index_to_tensor_map<T,Idx>::type;
//-----------------------------------------------------------------------------------------------------------//
}
#endif // TENSOR_POST_META_H