Add Fastor library
This commit is contained in:
33
noarch/include/Fastor/tensor/AbstractTensor.h
Normal file
33
noarch/include/Fastor/tensor/AbstractTensor.h
Normal 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
|
||||
393
noarch/include/Fastor/tensor/AbstractTensorFunctions.h
Normal file
393
noarch/include/Fastor/tensor/AbstractTensorFunctions.h
Normal 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
|
||||
67
noarch/include/Fastor/tensor/Aliasing.h
Normal file
67
noarch/include/Fastor/tensor/Aliasing.h
Normal 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_
|
||||
502
noarch/include/Fastor/tensor/BlockIndexing.h
Normal file
502
noarch/include/Fastor/tensor/BlockIndexing.h
Normal 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
|
||||
154
noarch/include/Fastor/tensor/ForwardDeclare.h
Normal file
154
noarch/include/Fastor/tensor/ForwardDeclare.h
Normal 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
|
||||
120
noarch/include/Fastor/tensor/IndexRetriever.h
Normal file
120
noarch/include/Fastor/tensor/IndexRetriever.h
Normal 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
|
||||
111
noarch/include/Fastor/tensor/InitializerListConstructors.h
Normal file
111
noarch/include/Fastor/tensor/InitializerListConstructors.h
Normal 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
|
||||
24
noarch/include/Fastor/tensor/PODConverters.h
Normal file
24
noarch/include/Fastor/tensor/PODConverters.h
Normal 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
|
||||
210
noarch/include/Fastor/tensor/Ranges.h
Normal file
210
noarch/include/Fastor/tensor/Ranges.h
Normal 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
|
||||
|
||||
39
noarch/include/Fastor/tensor/ScalarIndexing.h
Normal file
39
noarch/include/Fastor/tensor/ScalarIndexing.h
Normal 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
|
||||
374
noarch/include/Fastor/tensor/SpecialisedConstructors.h
Normal file
374
noarch/include/Fastor/tensor/SpecialisedConstructors.h
Normal 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
|
||||
203
noarch/include/Fastor/tensor/Tensor.h
Normal file
203
noarch/include/Fastor/tensor/Tensor.h
Normal 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
|
||||
|
||||
299
noarch/include/Fastor/tensor/TensorAssignment.h
Normal file
299
noarch/include/Fastor/tensor/TensorAssignment.h
Normal 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
|
||||
39
noarch/include/Fastor/tensor/TensorEvaluator.h
Normal file
39
noarch/include/Fastor/tensor/TensorEvaluator.h
Normal 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
|
||||
215
noarch/include/Fastor/tensor/TensorFunctions.h
Normal file
215
noarch/include/Fastor/tensor/TensorFunctions.h
Normal 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
|
||||
|
||||
180
noarch/include/Fastor/tensor/TensorIO.h
Normal file
180
noarch/include/Fastor/tensor/TensorIO.h
Normal 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
|
||||
|
||||
58
noarch/include/Fastor/tensor/TensorInplaceOperators.h
Normal file
58
noarch/include/Fastor/tensor/TensorInplaceOperators.h
Normal 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
|
||||
170
noarch/include/Fastor/tensor/TensorMap.h
Normal file
170
noarch/include/Fastor/tensor/TensorMap.h
Normal 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
|
||||
167
noarch/include/Fastor/tensor/TensorMethods.h
Normal file
167
noarch/include/Fastor/tensor/TensorMethods.h
Normal 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
|
||||
303
noarch/include/Fastor/tensor/TensorTraits.h
Normal file
303
noarch/include/Fastor/tensor/TensorTraits.h
Normal 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
|
||||
Reference in New Issue
Block a user