Add Fastor library

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

View File

@@ -0,0 +1,247 @@
#ifndef BINARY_ADD_OP_H
#define BINARY_ADD_OP_H
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryAddOp: public AbstractTensor<BinaryAddOp<TLhs, TRhs, DIM0>,DIM0> {
private:
expression_t<TLhs> _lhs;
expression_t<TRhs> _rhs;
public:
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<BinaryAddOp<TLhs, TRhs, DIM0>>::type;
using simd_vector_type = binary_op_simd_vector_t<BinaryAddOp<TLhs, TRhs, DIM0> >;
using simd_abi_type = typename simd_vector_type::abi_type;
FASTOR_INLINE BinaryAddOp(expression_t<TLhs> inlhs, expression_t<TRhs> inrhs) : _lhs((inlhs)), _rhs((inrhs)) {}
FASTOR_INLINE FASTOR_INDEX size() const {return helper_size<TLhs,TRhs>();}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _rhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _lhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.size()==_lhs.size(),"EXPRESSION SIZE MISMATCH");
#endif
return _rhs.size();
}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return helper_dimension<TLhs,TRhs>(i);}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _rhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _lhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.dimension(i)==_lhs.dimension(i),"EXPRESSION SHAPE MISMATCH");
#endif
return _rhs.dimension(i);
}
constexpr FASTOR_INLINE expression_t<TLhs> lhs() const {return _lhs;}
constexpr FASTOR_INLINE expression_t<TRhs> rhs() const {return _rhs;}
// Generic version of eval
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
// Delay evaluation using a helper function to fully inform BinaryOp about _lhs and _rhs
return helper<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return _lhs.template eval<U>(i) + _rhs.template eval<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return (U)_lhs + _rhs.template eval<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return _lhs.template eval<U>(i) + (U)_rhs;
}
// scalar based
template<typename U>
FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return helper_s<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<U>(i) + _rhs.template eval_s<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return (U)_lhs + _rhs.template eval_s<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<U>(i) + (U)_rhs;
}
// for 2D tensors
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval<U>(i,j) + _rhs.template eval<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return (U)_lhs + _rhs.template eval<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval<U>(i,j) + (U)_rhs;
}
// scalar based (for 2D tensors)
template<typename U>
FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper_s<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<U>(i,j) + _rhs.template eval_s<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return (U)_lhs + _rhs.template eval_s<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<U>(i,j) + (U)_rhs;
}
// for nD tensors
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,DIM0> &as) const {
return thelper<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<U>(as) + _rhs.template teval<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return (U)_lhs + _rhs.template teval<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<U>(as) + (U)_rhs;
}
// scalar based (for nD tensors)
template<typename U>
FASTOR_INLINE U teval_s(const std::array<int,DIM0> &as) const {
return thelper_s<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<U>(as) + _rhs.template teval_s<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return (U)_lhs + _rhs.template teval_s<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<U>(as) + (U)_rhs;
}
};
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryAddOp<TLhs, TRhs, DIM0> operator+(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryAddOp<TLhs, TRhs, DIM0>(_lhs.self(), _rhs.self());
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryAddOp<TLhs, TRhs, DIM0> operator+(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {
return BinaryAddOp<TLhs, TRhs, DIM0>(_lhs.self(), bb);
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryAddOp<TLhs, TRhs, DIM0> operator+(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryAddOp<TLhs, TRhs, DIM0>(bb,_rhs.self());
}
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value &&
DIM0!=DIM1,bool>::type = 0 >
FASTOR_INLINE BinaryAddOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>
operator+(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM1> &_rhs) {
return BinaryAddOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(_lhs.self(), _rhs.self());
}
} // end of namespace Fastor
#endif // BINARY_ADD_OP_H

View File

@@ -0,0 +1,156 @@
#ifndef BINARY_ARITHMETIC_ASSIGNMENT_H
#define BINARY_ARITHMETIC_ASSIGNMENT_H
#include "Fastor/expressions/binary_ops/binary_arithmetic_ops.h"
#include "Fastor/tensor/Aliasing.h"
namespace Fastor {
// Create assign for all binrary arithmetic ops
#define FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_0(NAME, ASSIGN_TYPE, OP_ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && !(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>), bool> = false >\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && (requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>), bool> = false >\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
assign ##ASSIGN_TYPE (dst.self(), src.lhs().self());\
assign ##OP_ASSIGN_TYPE (dst.self(), src.rhs().self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && !requires_evaluation_v<TRhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && requires_evaluation_v<TRhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
assign ##ASSIGN_TYPE (dst.self(), src.lhs());\
assign ##OP_ASSIGN_TYPE (dst.self(), src.rhs().self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && is_primitive_v_<TRhs> && !requires_evaluation_v<TLhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && is_primitive_v_<TRhs> && requires_evaluation_v<TLhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
assign ##ASSIGN_TYPE (dst.self(), src.lhs().self());\
assign ##OP_ASSIGN_TYPE (dst.self(), src.rhs());\
}\
// Create assign_add, assign_sub for BinaryAddOp and BinarySubOp
#define FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_1(NAME, ASSIGN_TYPE, OP_ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && !(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>), bool> = false >\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && (requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>), bool> = false >\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
if (!does_alias(dst.self(),src.rhs().self())) {\
assign ##ASSIGN_TYPE (dst.self(), src.lhs().self());\
assign ##OP_ASSIGN_TYPE (dst.self(), src.rhs().self());\
}\
else{\
const Derived tmp(dst.self());\
assign ##ASSIGN_TYPE (dst.self(), src.lhs().self());\
assign ##OP_ASSIGN_TYPE (dst.self(), tmp);\
}\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && !requires_evaluation_v<TRhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<is_primitive_v_<TLhs> && !is_primitive_v_<TRhs> && requires_evaluation_v<TRhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
assign ##ASSIGN_TYPE (dst.self(), src.lhs());\
assign ##OP_ASSIGN_TYPE (dst.self(), src.rhs().self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && is_primitive_v_<TRhs> && !requires_evaluation_v<TLhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!is_primitive_v_<TLhs> && is_primitive_v_<TRhs> && requires_evaluation_v<TLhs>, bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
assign ##ASSIGN_TYPE (dst.self(), src.lhs().self());\
assign ##OP_ASSIGN_TYPE (dst.self(), src.rhs());\
}\
// Create assign_add, assign_sub for BinaryMulOp and BinaryDivOp
// Create assign_mul, assign_div for all binary ops
#define FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(NAME, ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>),bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>),bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
using result_type = typename Binary ##NAME ## Op<TLhs, TRhs, OtherDIM>::result_type;\
const result_type a(src.self());\
trivial_assign ##ASSIGN_TYPE (dst.self(), a);\
}\
// assign
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_0(Add, , _add)
// assign_add
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_1(Add, _add, _add)
// assign_sub
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_1(Add, _sub, _sub)
// assign_mul
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Add, _mul)
// assign_div
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Add, _div)
// assign
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_0(Sub, , _sub)
// assign_add
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_1(Sub, _add, _sub)
// assign_sub
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_1(Sub, _sub, _add)
// assign_mul
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Sub, _mul)
// assign_div
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Sub, _div)
// assign
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_0(Mul, , _mul)
// assign_add
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Mul, _add)
// assign_sub
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Mul, _sub)
// assign_mul
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Mul, _mul)
// assign_div
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Mul, _div)
// assign
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_0(Div, , _div)
// assign_add
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Div, _add)
// assign_sub
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Div, _sub)
// assign_mul
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Div, _mul)
// assign_div
FASTOR_MAKE_BINARY_ARITHMETIC_ASSIGNMENT_2(Div, _div)
} // end of namespace Fastor
#endif // BINARY_ARITHMETIC_ASSIGNMENT_H

View File

@@ -0,0 +1,229 @@
#ifndef BINARY_ARITHMETIC_OP_H
#define BINARY_ARITHMETIC_OP_H
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
#define FASTOR_MAKE_BINARY_ARITHMETIC_OPS(OP, NAME, EVAL_TYPE) \
template<typename TLhs, typename TRhs, size_t DIM0>\
struct Binary ##NAME ## Op: public AbstractTensor<Binary ##NAME ## Op<TLhs, TRhs, DIM0>,DIM0> {\
expression_t<TLhs> _lhs;\
expression_t<TRhs> _rhs;\
public:\
static constexpr FASTOR_INDEX Dimension = DIM0;\
static constexpr FASTOR_INDEX rank() {return DIM0;}\
using scalar_type = typename scalar_type_finder<Binary ##NAME ## Op<TLhs, TRhs, DIM0>>::type;\
using simd_vector_type = binary_op_simd_vector_t< Binary ##NAME ## Op<TLhs, TRhs, DIM0> >;\
using simd_abi_type = typename simd_vector_type::abi_type;\
using result_type = binary_arithmetic_result_t< Binary ##NAME ## Op<TLhs, TRhs, DIM0> >;\
FASTOR_INLINE Binary ##NAME ## Op(expression_t<TLhs> inlhs, expression_t<TRhs> inrhs) : _lhs(inlhs), _rhs(inrhs) {}\
FASTOR_INLINE FASTOR_INDEX size() const {return helper_size<TLhs,TRhs>();}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<LExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _rhs.size();}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _lhs.size();}\
template<class LExpr, class RExpr,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {\
FASTOR_ASSERT(_rhs.size()==_lhs.size(),"EXPRESSION SIZE MISMATCH");\
return _rhs.size();\
}\
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return helper_dimension<TLhs,TRhs>(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<LExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _rhs.dimension(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _lhs.dimension(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {\
FASTOR_ASSERT(_rhs.dimension(i)==_lhs.dimension(i),"EXPRESSION SHAPE MISMATCH");\
return _rhs.dimension(i);\
}\
FASTOR_INLINE expression_t<TLhs> lhs() const {return _lhs;}\
FASTOR_INLINE expression_t<TRhs> rhs() const {return _rhs;}\
template<typename U>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i) const {\
return helper<TLhs,TRhs,U>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {\
return _lhs.template eval<EVAL_TYPE>(i) OP _rhs.template eval<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {\
return _lhs.template eval<EVAL_TYPE>(i) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE EVAL_TYPE eval_s(FASTOR_INDEX i) const {\
return helper_s<TLhs,TRhs,U>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i) const {\
return _lhs.template eval_s<EVAL_TYPE>(i) OP _rhs.template eval_s<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval_s<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i) const {\
return _lhs.template eval_s<EVAL_TYPE>(i) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return helper<TLhs,TRhs,U>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval<EVAL_TYPE>(i,j) OP _rhs.template eval<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval<EVAL_TYPE>(i,j) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE EVAL_TYPE eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return helper_s<TLhs,TRhs,U>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval_s<EVAL_TYPE>(i,j) OP _rhs.template eval_s<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval_s<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval_s<EVAL_TYPE>(i,j) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> teval(const std::array<int,DIM0> &as) const {\
return thelper<TLhs,TRhs,U>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return _lhs.template teval<EVAL_TYPE>(as) OP _rhs.template teval<EVAL_TYPE>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return (EVAL_TYPE)_lhs OP _rhs.template teval<EVAL_TYPE>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return _lhs.template teval<EVAL_TYPE>(as) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE EVAL_TYPE teval_s(const std::array<int,DIM0> &as) const {\
return thelper_s<TLhs,TRhs,U>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {\
return _lhs.template teval_s<EVAL_TYPE>(as) OP _rhs.template teval_s<EVAL_TYPE>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {\
return (EVAL_TYPE)_lhs OP _rhs.template teval_s<U>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {\
return _lhs.template teval_s<EVAL_TYPE>(as) OP (EVAL_TYPE)_rhs;\
}\
};\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<!is_primitive_v_<TLhs> &&\
!is_primitive_v_<TRhs>,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, DIM0> operator OP(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM0> &_rhs) {\
return Binary ##NAME ## Op<TLhs, TRhs, DIM0>(_lhs.self(), _rhs.self());\
}\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<!is_primitive_v_<TLhs> &&\
is_primitive_v_<TRhs>,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, DIM0> operator OP(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {\
return Binary ##NAME ## Op<TLhs, TRhs, DIM0>(_lhs.self(), bb);\
}\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<is_primitive_v_<TLhs> &&\
!is_primitive_v_<TRhs>,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, DIM0> operator OP(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {\
return Binary ##NAME ## Op<TLhs, TRhs, DIM0>(bb,_rhs.self());\
}\
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,\
typename std::enable_if<!is_primitive_v_<TLhs> &&\
!is_primitive_v_<TRhs> &&\
DIM0!=DIM1,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, meta_min<DIM0,DIM1>::value>\
operator OP(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM1> &_rhs) {\
return Binary ##NAME ## Op<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(_lhs.self(), _rhs.self());\
}\
// Dispatch based on type of expressions not the tensor
FASTOR_MAKE_BINARY_ARITHMETIC_OPS(+, Add, scalar_type)
FASTOR_MAKE_BINARY_ARITHMETIC_OPS(-, Sub, scalar_type)
FASTOR_MAKE_BINARY_ARITHMETIC_OPS(*, Mul, scalar_type)
// FASTOR_MAKE_BINARY_ARITHMETIC_OPS(/, Div, scalar_type) // Dont create div as it is a special case
// Dispatch based on the type of tensor and not the expression
// FASTOR_MAKE_BINARY_ARITHMETIC_OPS(+, Add, U)
// FASTOR_MAKE_BINARY_ARITHMETIC_OPS(-, Sub, U)
// FASTOR_MAKE_BINARY_ARITHMETIC_OPS(*, Mul, U)
// FASTOR_MAKE_BINARY_ARITHMETIC_OPS(/, Div, U)
}
#endif // BINARY_ARITHMETIC_OP_H

View File

@@ -0,0 +1,262 @@
#ifndef BINARY_CMP_OPS
#define BINARY_CMP_OPS
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
#define FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(OP, NAME, EVAL_TYPE) \
template<typename TLhs, typename TRhs, size_t DIM0>\
struct BinaryCmpOp##NAME: public AbstractTensor<BinaryCmpOp##NAME<TLhs, TRhs, DIM0>,DIM0> {\
expression_t<TLhs> _lhs;\
expression_t<TRhs> _rhs;\
static constexpr FASTOR_INDEX Dimension = DIM0;\
static constexpr FASTOR_INDEX rank() {return DIM0;}\
using scalar_type = typename scalar_type_finder<BinaryCmpOp##NAME<TLhs, TRhs, DIM0>>::type;\
using result_type = to_bool_tensor_t<binary_arithmetic_result_t<BinaryCmpOp##NAME<TLhs, TRhs, DIM0>>>;\
using simd_vector_type = binary_op_simd_vector_t<BinaryCmpOp##NAME<TLhs, TRhs, DIM0> >;\
using simd_abi_type = typename simd_vector_type::abi_type;\
using ABI = simd_abi::fixed_size<SIMDVector<scalar_type,simd_abi_type>::Size>;\
using UU = bool /*this needs to change to U once masks are implemented*/;\
FASTOR_INLINE BinaryCmpOp##NAME(expression_t<TLhs> inlhs, expression_t<TRhs> inrhs) : _lhs(inlhs), _rhs(inrhs) {}\
FASTOR_INLINE FASTOR_INDEX size() const {return helper_size<TLhs,TRhs>();}\
template<class LExpr, class RExpr,\
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _rhs.size();}\
template<class LExpr, class RExpr,\
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _lhs.size();}\
template<class LExpr, class RExpr,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {\
return _rhs.size();\
}\
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return helper_dimension<TLhs,TRhs>(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _rhs.dimension(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _lhs.dimension(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {\
return _rhs.dimension(i);\
}\
FASTOR_INLINE expression_t<TLhs> lhs() const {return _lhs;}\
FASTOR_INLINE expression_t<TRhs> rhs() const {return _rhs;}\
template<typename U>\
FASTOR_INLINE SIMDVector<UU,ABI> eval(FASTOR_INDEX i) const {\
return helper<TLhs,TRhs,U>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,ABI> helper(FASTOR_INDEX i) const {\
return _lhs.template eval<EVAL_TYPE>(i) OP _rhs.template eval<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,ABI> helper(FASTOR_INDEX i) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,ABI> helper(FASTOR_INDEX i) const {\
return _lhs.template eval<EVAL_TYPE>(i) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE UU eval_s(FASTOR_INDEX i) const {\
return helper_s<TLhs,TRhs,U>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU helper_s(FASTOR_INDEX i) const {\
return _lhs.template eval_s<EVAL_TYPE>(i) OP _rhs.template eval_s<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU helper_s(FASTOR_INDEX i) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval_s<EVAL_TYPE>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU helper_s(FASTOR_INDEX i) const {\
return _lhs.template eval_s<EVAL_TYPE>(i) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<UU,ABI> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return helper<TLhs,TRhs,U>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,ABI> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval<EVAL_TYPE>(i,j) OP _rhs.template eval<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,ABI> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,ABI> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval<EVAL_TYPE>(i,j) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE UU eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return helper_s<TLhs,TRhs,U>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval_s<EVAL_TYPE>(i,j) OP _rhs.template eval_s<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return (EVAL_TYPE)_lhs OP _rhs.template eval_s<EVAL_TYPE>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return _lhs.template eval_s<EVAL_TYPE>(i,j) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<UU,simd_abi_type> teval(const std::array<int,DIM0> &as) const {\
return thelper<TLhs,TRhs,U>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return _lhs.template teval<EVAL_TYPE>(as) OP _rhs.template teval<EVAL_TYPE>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return (EVAL_TYPE)_lhs OP _rhs.template teval<EVAL_TYPE>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE SIMDVector<UU,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return _lhs.template teval<EVAL_TYPE>(as) OP (EVAL_TYPE)_rhs;\
}\
template<typename U>\
FASTOR_INLINE UU teval_s(const std::array<int,DIM0> &as) const {\
return thelper_s<TLhs,TRhs,U>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU thelper_s(const std::array<int,DIM0> &as) const {\
return _lhs.template teval_s<EVAL_TYPE>(as) OP _rhs.template teval_s<EVAL_TYPE>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<std::is_arithmetic<LExpr>::value &&\
!std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU thelper_s(const std::array<int,DIM0> &as) const {\
return (EVAL_TYPE)_lhs OP _rhs.template teval_s<EVAL_TYPE>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&\
std::is_arithmetic<RExpr>::value,bool>::type = 0>\
FASTOR_INLINE UU thelper_s(const std::array<int,DIM0> &as) const {\
return _lhs.template teval_s<EVAL_TYPE>(as) OP (EVAL_TYPE)_rhs;\
}\
};\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&\
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >\
FASTOR_INLINE BinaryCmpOp##NAME<TLhs, TRhs, DIM0> operator OP(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM0> &_rhs) {\
return BinaryCmpOp##NAME<TLhs, TRhs, DIM0>(_lhs.self(), _rhs.self());\
}\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&\
std::is_arithmetic<TRhs>::value,bool>::type = 0 >\
FASTOR_INLINE BinaryCmpOp##NAME<TLhs, TRhs, DIM0> operator OP(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {\
return BinaryCmpOp##NAME<TLhs, TRhs, DIM0>(_lhs.self(), bb);\
}\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<std::is_arithmetic<TLhs>::value &&\
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >\
FASTOR_INLINE BinaryCmpOp##NAME<TLhs, TRhs, DIM0> operator OP(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {\
return BinaryCmpOp##NAME<TLhs, TRhs, DIM0>(bb,_rhs.self());\
}\
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,\
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&\
!std::is_arithmetic<TRhs>::value &&\
DIM0!=DIM1,bool>::type = 0 >\
FASTOR_INLINE BinaryCmpOp##NAME<TLhs, TRhs, meta_min<DIM0,DIM1>::value>\
operator OP(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM1> &_rhs) {\
return BinaryCmpOp##NAME<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(_lhs.self(), _rhs.self());\
}\
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(== ,EQ, scalar_type)
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(!= ,NEQ,scalar_type)
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(< ,LT, scalar_type)
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(> ,GT, scalar_type)
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(<= ,LE, scalar_type)
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(>= ,GE, scalar_type)
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(&& ,AND,scalar_type)
FASTOR_MAKE_BINARY_CMP_TENSOR_OPS_(|| ,OR, scalar_type)
#define FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(NAME, ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>),bool> = false >\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const BinaryCmpOp ##NAME <TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>),bool> = false >\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const BinaryCmpOp ##NAME <TLhs, TRhs, OtherDIM> &src) {\
using lhs_type = typename get_binary_arithmetic_result_type<TLhs>::type;\
using rhs_type = typename get_binary_arithmetic_result_type<TRhs>::type;\
const lhs_type a(src.lhs());\
const rhs_type b(src.rhs());\
trivial_assign ##ASSIGN_TYPE (dst.self(), BinaryCmpOp ##NAME <lhs_type, rhs_type, OtherDIM>(a,b));\
}\
#define FASTOR_MAKE_BINARY_CMP_ASSIGNMENTS(ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(EQ, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(NEQ, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(LT, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(GT, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(LE, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(GE, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(AND, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENT(OR, ASSIGN_TYPE)\
FASTOR_MAKE_BINARY_CMP_ASSIGNMENTS( )
FASTOR_MAKE_BINARY_CMP_ASSIGNMENTS( _add)
FASTOR_MAKE_BINARY_CMP_ASSIGNMENTS( _sub)
FASTOR_MAKE_BINARY_CMP_ASSIGNMENTS( _mul)
FASTOR_MAKE_BINARY_CMP_ASSIGNMENTS( _div)
} // end of namespace Fastor
#endif // BINARY_CMP_OPS

View File

@@ -0,0 +1,306 @@
#ifndef BINARY_DIV_OP_H
#define BINARY_DIV_OP_H
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
// Dispatch based on type of expressions not the tensor
#define FASTOR_BD_OP_EVAL_TYPE scalar_type
// Dispatch based on the type of tensor and not the expression
// #define FASTOR_BD_OP_EVAL_TYPE U
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryDivOp: public AbstractTensor<BinaryDivOp<TLhs, TRhs, DIM0>,DIM0> {
private:
expression_t<TLhs> _lhs;
expression_t<TRhs> _rhs;
public:
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<BinaryDivOp<TLhs, TRhs, DIM0>>::type;
using simd_vector_type = binary_op_simd_vector_t<BinaryDivOp<TLhs, TRhs, DIM0> >;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = binary_arithmetic_result_t< BinaryDivOp<TLhs, TRhs, DIM0> >;
FASTOR_INLINE BinaryDivOp(expression_t<TLhs> inlhs, expression_t<TRhs> inrhs) : _lhs((inlhs)), _rhs((inrhs)) {}
FASTOR_INLINE FASTOR_INDEX size() const {return helper_size<TLhs,TRhs>();}
template<class LExpr, class RExpr,
typename std::enable_if<is_primitive_v_<LExpr>,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _rhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<is_primitive_v_<RExpr>,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _lhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.size()==_lhs.size(),"EXPRESSION SIZE MISMATCH");
#endif
return _rhs.size();
}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return helper_dimension<TLhs,TRhs>(i);}
template<class LExpr, class RExpr,
typename std::enable_if<is_primitive_v_<LExpr>,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _rhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<is_primitive_v_<RExpr>,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _lhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.dimension(i)==_lhs.dimension(i),"EXPRESSION SHAPE MISMATCH");
#endif
return _rhs.dimension(i);
}
constexpr FASTOR_INLINE expression_t<TLhs> lhs() const {return _lhs;}
constexpr FASTOR_INLINE expression_t<TRhs> rhs() const {return _rhs;}
template<typename U>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i) const {
return helper<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {
#ifndef FASTOR_UNSAFE_MATH
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i) / _rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i);
#else
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i) * rcp(_rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i));
#endif
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {
#ifndef FASTOR_UNSAFE_MATH
return (FASTOR_BD_OP_EVAL_TYPE)_lhs / _rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i);
#else
return (FASTOR_BD_OP_EVAL_TYPE)_lhs * rcp(_rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i));
#endif
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {
#ifndef FASTOR_UNSAFE_MATH
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i) / (FASTOR_BD_OP_EVAL_TYPE)_rhs;
#else
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i) * rcp(SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type>(_rhs));
#endif
}
// scalar based
template<typename U>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE eval_s(FASTOR_INDEX i) const {
return helper_s<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i) / _rhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE helper_s(FASTOR_INDEX i) const {
return (FASTOR_BD_OP_EVAL_TYPE)_lhs / _rhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i) / (FASTOR_BD_OP_EVAL_TYPE)_rhs;
}
// for 2D tensors
template<typename U>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
#ifndef FASTOR_UNSAFE_MATH
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j) / _rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j);
#else
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j) * rcp(_rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j));
#endif
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
#ifndef FASTOR_UNSAFE_MATH
return (FASTOR_BD_OP_EVAL_TYPE)_lhs / _rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j);
#else
return (FASTOR_BD_OP_EVAL_TYPE)_lhs * rcp(_rhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j));
#endif
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
#ifndef FASTOR_UNSAFE_MATH
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j) / (FASTOR_BD_OP_EVAL_TYPE)_rhs;
#else
return _lhs.template eval<FASTOR_BD_OP_EVAL_TYPE>(i,j) * rcp(SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type>(_rhs));
#endif
}
// scalar based (for 2D tensors)
template<typename U>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper_s<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i,j) / _rhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return (FASTOR_BD_OP_EVAL_TYPE)_lhs / _rhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<FASTOR_BD_OP_EVAL_TYPE>(i,j) / (FASTOR_BD_OP_EVAL_TYPE)_rhs;
}
// for nD tensors
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,DIM0> &as) const {
return thelper<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<FASTOR_BD_OP_EVAL_TYPE>(as) / _rhs.template teval<FASTOR_BD_OP_EVAL_TYPE>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return (FASTOR_BD_OP_EVAL_TYPE)_lhs / _rhs.template teval<FASTOR_BD_OP_EVAL_TYPE>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE SIMDVector<FASTOR_BD_OP_EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<FASTOR_BD_OP_EVAL_TYPE>(as) / (FASTOR_BD_OP_EVAL_TYPE)_rhs;
}
// scalar based (for nD tensors)
template<typename U>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE teval_s(const std::array<int,DIM0> &as) const {
return thelper_s<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<FASTOR_BD_OP_EVAL_TYPE>(as) / _rhs.template teval_s<FASTOR_BD_OP_EVAL_TYPE>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<is_primitive_v_<LExpr> &&
!is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {
return (FASTOR_BD_OP_EVAL_TYPE)_lhs / _rhs.template teval_s<FASTOR_BD_OP_EVAL_TYPE>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!is_primitive_v_<LExpr> &&
is_primitive_v_<RExpr>,bool>::type = 0>
FASTOR_INLINE FASTOR_BD_OP_EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<FASTOR_BD_OP_EVAL_TYPE>(as) / (FASTOR_BD_OP_EVAL_TYPE)_rhs;
}
};
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!is_primitive_v_<TLhs> &&
!is_primitive_v_<TRhs>,bool>::type = 0 >
FASTOR_INLINE BinaryDivOp<TLhs, TRhs, DIM0> operator/(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryDivOp<TLhs, TRhs, DIM0>(_lhs.self(), _rhs.self());
}
#ifndef FASTOR_DISPATCH_DIV_TO_MUL_EXPR
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!is_primitive_v_<TLhs> &&
is_primitive_v_<TRhs>,bool>::type = 0 >
FASTOR_INLINE BinaryDivOp<TLhs, TRhs, DIM0> operator/(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {
return BinaryDivOp<TLhs, TRhs, DIM0>(_lhs.self(), bb);
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<is_primitive_v_<TLhs> &&
!is_primitive_v_<TRhs>,bool>::type = 0 >
FASTOR_INLINE BinaryDivOp<TLhs, TRhs, DIM0> operator/(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryDivOp<TLhs, TRhs, DIM0>(bb,_rhs.self());
}
#else
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!is_primitive_v_<TLhs> &&
is_primitive_v_<TRhs> && !std::is_integral<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryMulOp<TLhs, TRhs, DIM0> operator/(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {
return BinaryMulOp<TLhs, TRhs, DIM0>(
_lhs.self(),
static_cast<typename scalar_type_finder<TLhs>::type>(1)/static_cast<typename scalar_type_finder<TLhs>::type>(bb));
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<is_primitive_v_<TLhs> && !std::is_integral<TRhs>::value &&
!is_primitive_v_<TRhs>,bool>::type = 0 >
FASTOR_INLINE BinaryMulOp<TLhs, TRhs, DIM0> operator/(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryMulOp<TLhs, TRhs, DIM0>(
static_cast<typename scalar_type_finder<TLhs>::type>(1)/static_cast<typename scalar_type_finder<TLhs>::type>(bb),
_rhs.self());
}
// Special case for integral types
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!is_primitive_v_<TLhs> &&
is_primitive_v_<TRhs> && std::is_integral<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryDivOp<TLhs, TRhs, DIM0> operator/(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {
return BinaryDivOp<TLhs, TRhs, DIM0>(_lhs.self(), bb);
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<is_primitive_v_<TLhs> && std::is_integral<TRhs>::value &&
!is_primitive_v_<TRhs>,bool>::type = 0 >
FASTOR_INLINE BinaryDivOp<TLhs, TRhs, DIM0> operator/(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryDivOp<TLhs, TRhs, DIM0>(bb,_rhs.self());
}
#endif
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
enable_if_t_<!is_arithmetic_v_<TLhs> &&
!is_arithmetic_v_<TRhs> &&
DIM0!=DIM1,bool> = false >
FASTOR_INLINE BinaryDivOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>
operator/(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM1> &_rhs) {
return BinaryDivOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(_lhs.self(), _rhs.self());
}
}
#endif // BINARY_DIV_OP_H

View File

@@ -0,0 +1,261 @@
#ifndef BINARY_MATH_OP_H
#define BINARY_MATH_OP_H
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
#define FASTOR_MAKE_BINARY_MATH_OPS(OP_NAME, SIMD_OP, OP, NAME, EVAL_TYPE) \
template<typename TLhs, typename TRhs, size_t DIM0>\
struct Binary ##NAME ## Op: public AbstractTensor<Binary ##NAME ## Op<TLhs, TRhs, DIM0>,DIM0> {\
expression_t<TLhs> _lhs;\
expression_t<TRhs> _rhs;\
public:\
static constexpr FASTOR_INDEX Dimension = DIM0;\
static constexpr FASTOR_INDEX rank() {return DIM0;}\
using scalar_type = typename scalar_type_finder<Binary ##NAME ## Op<TLhs, TRhs, DIM0>>::type;\
using simd_vector_type = binary_op_simd_vector_t< Binary ##NAME ## Op<TLhs, TRhs, DIM0> >;\
using simd_abi_type = typename simd_vector_type::abi_type;\
using result_type = binary_arithmetic_result_t< Binary ##NAME ## Op<TLhs, TRhs, DIM0> >;\
FASTOR_INLINE Binary ##NAME ## Op(expression_t<TLhs> inlhs, expression_t<TRhs> inrhs) : _lhs(inlhs), _rhs(inrhs) {}\
FASTOR_INLINE FASTOR_INDEX size() const {return helper_size<TLhs,TRhs>();}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<LExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _rhs.size();}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _lhs.size();}\
template<class LExpr, class RExpr,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_size() const {\
FASTOR_ASSERT(_rhs.size()==_lhs.size(),"EXPRESSION SIZE MISMATCH");\
return _rhs.size();\
}\
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return helper_dimension<TLhs,TRhs>(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<LExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _rhs.dimension(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _lhs.dimension(i);}\
template<class LExpr, class RExpr,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type =0 >\
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {\
FASTOR_ASSERT(_rhs.dimension(i)==_lhs.dimension(i),"EXPRESSION SHAPE MISMATCH");\
return _rhs.dimension(i);\
}\
FASTOR_INLINE expression_t<TLhs> lhs() const {return _lhs;}\
FASTOR_INLINE expression_t<TRhs> rhs() const {return _rhs;}\
template<typename U>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i) const {\
return helper<TLhs,TRhs,U>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {\
return SIMD_OP(_lhs.template eval<EVAL_TYPE>(i), _rhs.template eval<EVAL_TYPE>(i));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {\
return SIMD_OP((EVAL_TYPE)_lhs, _rhs.template eval<EVAL_TYPE>(i));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i) const {\
return SIMD_OP(_lhs.template eval<EVAL_TYPE>(i), (EVAL_TYPE)_rhs);\
}\
template<typename U>\
FASTOR_INLINE EVAL_TYPE eval_s(FASTOR_INDEX i) const {\
return helper_s<TLhs,TRhs,U>(i);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i) const {\
return OP(_lhs.template eval_s<EVAL_TYPE>(i), _rhs.template eval_s<EVAL_TYPE>(i));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i) const {\
return OP((EVAL_TYPE)_lhs, _rhs.template eval_s<EVAL_TYPE>(i));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i) const {\
return OP(_lhs.template eval_s<EVAL_TYPE>(i), (EVAL_TYPE)_rhs);\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return helper<TLhs,TRhs,U>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return SIMD_OP(_lhs.template eval<EVAL_TYPE>(i,j), _rhs.template eval<EVAL_TYPE>(i,j));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return SIMD_OP((EVAL_TYPE)_lhs, _rhs.template eval<EVAL_TYPE>(i,j));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return SIMD_OP(_lhs.template eval<EVAL_TYPE>(i,j), (EVAL_TYPE)_rhs);\
}\
template<typename U>\
FASTOR_INLINE EVAL_TYPE eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return helper_s<TLhs,TRhs,U>(i,j);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return OP(_lhs.template eval_s<EVAL_TYPE>(i,j), _rhs.template eval_s<EVAL_TYPE>(i,j));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return OP((EVAL_TYPE)_lhs, _rhs.template eval_s<EVAL_TYPE>(i,j));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return OP(_lhs.template eval_s<EVAL_TYPE>(i,j), (EVAL_TYPE)_rhs);\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> teval(const std::array<int,DIM0> &as) const {\
return thelper<TLhs,TRhs,U>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return SIMD_OP(_lhs.template teval<EVAL_TYPE>(as), _rhs.template teval<EVAL_TYPE>(as));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return SIMD_OP((EVAL_TYPE)_lhs, _rhs.template teval<EVAL_TYPE>(as));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {\
return SIMD_OP(_lhs.template teval<EVAL_TYPE>(as), (EVAL_TYPE)_rhs);\
}\
template<typename U>\
FASTOR_INLINE EVAL_TYPE teval_s(const std::array<int,DIM0> &as) const {\
return thelper_s<TLhs,TRhs,U>(as);\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {\
return OP(_lhs.template teval_s<EVAL_TYPE>(as), _rhs.template teval_s<EVAL_TYPE>(as));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<is_primitive_v_<LExpr> &&\
!is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {\
return OP((EVAL_TYPE)_lhs, _rhs.template teval_s<U>(as));\
}\
template<typename LExpr, typename RExpr, typename U,\
typename std::enable_if<!is_primitive_v_<LExpr> &&\
is_primitive_v_<RExpr>,bool>::type = 0>\
FASTOR_INLINE EVAL_TYPE thelper_s(const std::array<int,DIM0> &as) const {\
return OP(_lhs.template teval_s<EVAL_TYPE>(as), (EVAL_TYPE)_rhs);\
}\
};\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<!is_primitive_v_<TLhs> &&\
!is_primitive_v_<TRhs>,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, DIM0> OP_NAME(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM0> &_rhs) {\
return Binary ##NAME ## Op<TLhs, TRhs, DIM0>(_lhs.self(), _rhs.self());\
}\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<!is_primitive_v_<TLhs> &&\
is_primitive_v_<TRhs>,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, DIM0> OP_NAME(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {\
return Binary ##NAME ## Op<TLhs, TRhs, DIM0>(_lhs.self(), bb);\
}\
template<typename TLhs, typename TRhs, size_t DIM0,\
typename std::enable_if<is_primitive_v_<TLhs> &&\
!is_primitive_v_<TRhs>,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, DIM0> OP_NAME(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {\
return Binary ##NAME ## Op<TLhs, TRhs, DIM0>(bb,_rhs.self());\
}\
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,\
typename std::enable_if<!is_primitive_v_<TLhs> &&\
!is_primitive_v_<TRhs> &&\
DIM0!=DIM1,bool>::type = 0 >\
FASTOR_INLINE Binary ##NAME ## Op<TLhs, TRhs, meta_min<DIM0,DIM1>::value>\
OP_NAME(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM1> &_rhs) {\
return Binary ##NAME ## Op<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(_lhs.self(), _rhs.self());\
}\
// Dispatch based on type of expressions not the tensor
FASTOR_MAKE_BINARY_MATH_OPS(min, min, std::min, Min, scalar_type)
FASTOR_MAKE_BINARY_MATH_OPS(max, max, std::max, Max, scalar_type)
FASTOR_MAKE_BINARY_MATH_OPS(pow, pow, std::pow, Pow, scalar_type)
FASTOR_MAKE_BINARY_MATH_OPS(atan2, atan2, std::atan2, Atan2, scalar_type)
FASTOR_MAKE_BINARY_MATH_OPS(hypot, hypot, std::hypot, Hypot, scalar_type)
// Dispatch based on the type of tensor and not the expression
// FASTOR_MAKE_BINARY_MATH_OPS(min, min, std::min, Min, U)
// FASTOR_MAKE_BINARY_MATH_OPS(max, max, std::max, Max, U)
// FASTOR_MAKE_BINARY_MATH_OPS(pow, pow, std::pow, Pow, U)
// FASTOR_MAKE_BINARY_MATH_OPS(atan2, atan2, std::atan2, Atan2, U)
// FASTOR_MAKE_BINARY_MATH_OPS(hypot, hypot, std::hypot, Hypot, U)
// Create assignment for all binary math_ops
#define FASTOR_MAKE_BINARY_MATH_ASSIGNMENT(NAME, ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<!(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>),bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,\
enable_if_t_<(requires_evaluation_v<TLhs> || requires_evaluation_v<TRhs>),bool> = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Binary ##NAME ## Op<TLhs, TRhs, OtherDIM> &src) {\
using result_type = typename Binary ##NAME ## Op<TLhs, TRhs, OtherDIM>::result_type;\
const result_type a(src.self());\
trivial_assign ##ASSIGN_TYPE (dst.self(), a);\
}\
#define FASTOR_MAKE_BINARY_MATH_ASSIGNMENTS(NAME)\
FASTOR_MAKE_BINARY_MATH_ASSIGNMENT(NAME, )\
FASTOR_MAKE_BINARY_MATH_ASSIGNMENT(NAME, _add)\
FASTOR_MAKE_BINARY_MATH_ASSIGNMENT(NAME, _sub)\
FASTOR_MAKE_BINARY_MATH_ASSIGNMENT(NAME, _mul)\
FASTOR_MAKE_BINARY_MATH_ASSIGNMENT(NAME, _div)\
FASTOR_MAKE_BINARY_MATH_ASSIGNMENTS(Min)
FASTOR_MAKE_BINARY_MATH_ASSIGNMENTS(Max)
FASTOR_MAKE_BINARY_MATH_ASSIGNMENTS(Pow)
FASTOR_MAKE_BINARY_MATH_ASSIGNMENTS(Atan2)
FASTOR_MAKE_BINARY_MATH_ASSIGNMENTS(Hypot)
}
#endif // BINARY_MATH_OP_H

View File

@@ -0,0 +1,245 @@
#ifndef BINARY_MUL_OP_H
#define BINARY_MUL_OP_H
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryMulOp: public AbstractTensor<BinaryMulOp<TLhs, TRhs, DIM0>,DIM0> {
private:
expression_t<TLhs> _lhs;
expression_t<TRhs> _rhs;
public:
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<BinaryMulOp<TLhs, TRhs, DIM0>>::type;
using simd_vector_type = binary_op_simd_vector_t<BinaryMulOp<TLhs, TRhs, DIM0> >;
using simd_abi_type = typename simd_vector_type::abi_type;
FASTOR_INLINE BinaryMulOp(expression_t<TLhs> inlhs, expression_t<TRhs> inrhs) : _lhs((inlhs)), _rhs((inrhs)) {}
FASTOR_INLINE FASTOR_INDEX size() const {return helper_size<TLhs,TRhs>();}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _rhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _lhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.size()==_lhs.size(),"EXPRESSION SIZE MISMATCH");
#endif
return _rhs.size();
}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return helper_dimension<TLhs,TRhs>(i);}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _rhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _lhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.dimension(i)==_lhs.dimension(i),"EXPRESSION SHAPE MISMATCH");
#endif
return _rhs.dimension(i);
}
constexpr FASTOR_INLINE expression_t<TLhs> lhs() const {return _lhs;}
constexpr FASTOR_INLINE expression_t<TRhs> rhs() const {return _rhs;}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
return helper<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return _lhs.template eval<U>(i) * _rhs.template eval<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return (U)_lhs * _rhs.template eval<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return _lhs.template eval<U>(i) * (U)_rhs;
}
// scalar based
template<typename U>
FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return helper_s<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<U>(i) * _rhs.template eval_s<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return (U)_lhs * _rhs.template eval_s<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<U>(i) * (U)_rhs;
}
// for 2D tensors
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval<U>(i,j) * _rhs.template eval<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return (U)_lhs * _rhs.template eval<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval<U>(i,j) * (U)_rhs;
}
// scalar based (for 2D tensors)
template<typename U>
FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper_s<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<U>(i,j) * _rhs.template eval_s<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return (U)_lhs * _rhs.template eval_s<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<U>(i,j) * (U)_rhs;
}
// for nD tensors
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,DIM0> &as) const {
return thelper<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<U>(as) * _rhs.template teval<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return (U)_lhs * _rhs.template teval<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<U>(as) * (U)_rhs;
}
// scalar based (for nD tensors)
template<typename U>
FASTOR_INLINE U teval_s(const std::array<int,DIM0> &as) const {
return thelper_s<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<U>(as) * _rhs.template teval_s<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return (U)_lhs * _rhs.template teval_s<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<U>(as) * (U)_rhs;
}
};
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryMulOp<TLhs, TRhs, DIM0> operator*(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryMulOp<TLhs, TRhs, DIM0>(_lhs.self(), _rhs.self());
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryMulOp<TLhs, TRhs, DIM0> operator*(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {
return BinaryMulOp<TLhs, TRhs, DIM0>(_lhs.self(), bb);
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinaryMulOp<TLhs, TRhs, DIM0> operator*(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinaryMulOp<TLhs, TRhs, DIM0>(bb,_rhs.self());
}
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value &&
DIM0!=DIM1,bool>::type = 0 >
FASTOR_INLINE BinaryMulOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>
operator*(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM1> &_rhs) {
return BinaryMulOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(_lhs.self(), _rhs.self());
}
}
#endif // BINARY_MUL_OP_H

View File

@@ -0,0 +1,246 @@
#ifndef BINARY_SUB_OP_H
#define BINARY_SUB_OP_H
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinarySubOp: public AbstractTensor<BinarySubOp<TLhs, TRhs, DIM0>,DIM0> {
private:
expression_t<TLhs> _lhs;
expression_t<TRhs> _rhs;
public:
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<BinarySubOp<TLhs, TRhs, DIM0>>::type;
using simd_vector_type = binary_op_simd_vector_t<BinarySubOp<TLhs, TRhs, DIM0> >;
using simd_abi_type = typename simd_vector_type::abi_type;
FASTOR_INLINE BinarySubOp(expression_t<TLhs> inlhs, expression_t<TRhs> inrhs) : _lhs((inlhs)), _rhs((inrhs)) {}
FASTOR_INLINE FASTOR_INDEX size() const {return helper_size<TLhs,TRhs>();}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _rhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {return _lhs.size();}
template<class LExpr, class RExpr,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_size() const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.size()==_lhs.size(),"EXPRESSION SIZE MISMATCH");
#endif
return _rhs.size();
}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return helper_dimension<TLhs,TRhs>(i);}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<LExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _rhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {return _lhs.dimension(i);}
template<class LExpr, class RExpr,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type =0 >
FASTOR_INLINE FASTOR_INDEX helper_dimension(FASTOR_INDEX i) const {
#ifndef NDEBUG
FASTOR_ASSERT(_rhs.dimension(i)==_lhs.dimension(i),"EXPRESSION SHAPE MISMATCH");
#endif
return _rhs.dimension(i);
}
constexpr FASTOR_INLINE expression_t<TLhs> lhs() const {return _lhs;}
constexpr FASTOR_INLINE expression_t<TRhs> rhs() const {return _rhs;}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
return helper<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return _lhs.template eval<U>(i) - _rhs.template eval<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return (U)_lhs - _rhs.template eval<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i) const {
return _lhs.template eval<U>(i) - (U)_rhs;
}
// scalar based
template<typename U>
FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return helper_s<TLhs,TRhs,U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<U>(i) - _rhs.template eval_s<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return (U)_lhs - _rhs.template eval_s<U>(i);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i) const {
return _lhs.template eval_s<U>(i) - (U)_rhs;
}
// for 2D tensors
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval<U>(i,j) - _rhs.template eval<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return (U)_lhs - _rhs.template eval<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> helper(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval<U>(i,j) - (U)_rhs;
}
// scalar based (for 2D tensors)
template<typename U>
FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return helper_s<TLhs,TRhs,U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<U>(i,j) - _rhs.template eval_s<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return (U)_lhs - _rhs.template eval_s<U>(i,j);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U helper_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _lhs.template eval_s<U>(i,j) - (U)_rhs;
}
// for nD tensors
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,DIM0> &as) const {
return thelper<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<U>(as) - _rhs.template teval<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return (U)_lhs - _rhs.template teval<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE SIMDVector<U,simd_abi_type> thelper(const std::array<int,DIM0> &as) const {
return _lhs.template teval<U>(as) - (U)_rhs;
}
// scalar based (for nD tensors)
template<typename U>
FASTOR_INLINE U teval_s(const std::array<int,DIM0> &as) const {
return thelper_s<TLhs,TRhs,U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<U>(as) - _rhs.template teval_s<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<std::is_arithmetic<LExpr>::value &&
!std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return (U)_lhs - _rhs.template teval_s<U>(as);
}
template<typename LExpr, typename RExpr, typename U,
typename std::enable_if<!std::is_arithmetic<LExpr>::value &&
std::is_arithmetic<RExpr>::value,bool>::type = 0>
FASTOR_INLINE U thelper_s(const std::array<int,DIM0> &as) const {
return _lhs.template teval_s<U>(as) - (U)_rhs;
}
};
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinarySubOp<TLhs, TRhs, DIM0> operator-(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinarySubOp<TLhs, TRhs, DIM0>(_lhs.self(), _rhs.self());
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinarySubOp<TLhs, TRhs, DIM0> operator-(const AbstractTensor<TLhs,DIM0> &_lhs, TRhs bb) {
return BinarySubOp<TLhs, TRhs, DIM0>(_lhs.self(), bb);
}
template<typename TLhs, typename TRhs, size_t DIM0,
typename std::enable_if<std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value,bool>::type = 0 >
FASTOR_INLINE BinarySubOp<TLhs, TRhs, DIM0> operator-(TLhs bb, const AbstractTensor<TRhs,DIM0> &_rhs) {
return BinarySubOp<TLhs, TRhs, DIM0>(bb,_rhs.self());
}
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
!std::is_arithmetic<TRhs>::value &&
DIM0!=DIM1,bool>::type = 0 >
FASTOR_INLINE BinarySubOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>
operator-(const AbstractTensor<TLhs,DIM0> &_lhs, const AbstractTensor<TRhs,DIM1> &_rhs) {
return BinarySubOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(_lhs.self(), _rhs.self());
}
}
#endif // BINARY_SUB_OP_H

View File

@@ -0,0 +1,327 @@
#ifndef EXPRESSION_TRAITS_H
#define EXPRESSION_TRAITS_H
#include "Fastor/config/config.h"
#include "Fastor/meta/meta.h"
#include <type_traits>
namespace Fastor {
//------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_expression {
static constexpr bool value = false;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct is_expression<UnaryExpr<Expr,DIM>> {
static constexpr bool value = true;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct is_expression<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = true;
};
template<typename Derived>
static constexpr bool is_expression_v = is_expression<Derived>::value;
//------------------------------------------------------------------------------------------------//
// Expression binder - by value or ref
//------------------------------------------------------------------------------------------------//
template<class T>
struct expression_binder_type {
#ifndef FASTOR_COPY_EXPR
using type = conditional_t_<is_expression_v<T> || is_arithmetic_v_<T>, const T, const T&>;
#else
using type = const T;
#endif
};
template<class T>
using expression_t = typename expression_binder_type<T>::type;
//------------------------------------------------------------------------------------------------//
template<typename T, size_t ... Rest>
class Tensor;
template<typename T, size_t ... Rest>
class TensorMap;
template<typename T, size_t ... Rest>
class SingleValueTensor;
// traits
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_unary_bool_op {
static constexpr bool value = false;
};
template<typename Expr, size_t DIM>
struct is_unary_bool_op<UnaryNotOp<Expr,DIM>> {
static constexpr bool value = true;
};
template<typename Expr, size_t DIM>
struct is_unary_bool_op<UnaryIsinfOp<Expr,DIM>> {
static constexpr bool value = true;
};
template<typename Expr, size_t DIM>
struct is_unary_bool_op<UnaryIsnanOp<Expr,DIM>> {
static constexpr bool value = true;
};
template<typename Expr, size_t DIM>
struct is_unary_bool_op<UnaryIsfiniteOp<Expr,DIM>> {
static constexpr bool value = true;
};
template<size_t ... Rest>
struct is_unary_bool_op<Tensor<bool,Rest...>> {
static constexpr bool value = true;
};
template<size_t ... Rest>
struct is_unary_bool_op<TensorMap<bool,Rest...>> {
static constexpr bool value = true;
};
template<size_t ... Rest>
struct is_unary_bool_op<SingleValueTensor<bool,Rest...>> {
static constexpr bool value = true;
};
template<typename Derived>
static constexpr bool is_unary_bool_op_v = is_unary_bool_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_binary_cmp_op {
static constexpr bool value = false;
};
#define FASTOR_MAKE_IS_BINARY_CMP_OP(NAME) \
template<typename TLhs, typename TRhs, size_t DIMS>\
struct is_binary_cmp_op<BinaryCmpOp##NAME <TLhs,TRhs,DIMS>> {\
static constexpr bool value = true;\
};\
FASTOR_MAKE_IS_BINARY_CMP_OP(EQ)
FASTOR_MAKE_IS_BINARY_CMP_OP(NEQ)
FASTOR_MAKE_IS_BINARY_CMP_OP(LT)
FASTOR_MAKE_IS_BINARY_CMP_OP(GT)
FASTOR_MAKE_IS_BINARY_CMP_OP(LE)
FASTOR_MAKE_IS_BINARY_CMP_OP(GE)
FASTOR_MAKE_IS_BINARY_CMP_OP(AND)
FASTOR_MAKE_IS_BINARY_CMP_OP(OR)
template<size_t ... Rest>
struct is_binary_cmp_op<Tensor<bool,Rest...>> {
static constexpr bool value = true;
};
template<size_t ... Rest>
struct is_binary_cmp_op<TensorMap<bool,Rest...>> {
static constexpr bool value = true;
};
template<size_t ... Rest>
struct is_binary_cmp_op<SingleValueTensor<bool,Rest...>> {
static constexpr bool value = true;
};
template<typename Derived>
static constexpr bool is_binary_cmp_op_v = is_binary_cmp_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
/* Is boolean expresssion */
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_boolean_expression {
static constexpr bool value = is_unary_bool_op<Derived>::value || is_binary_cmp_op<Derived>::value;
};
template<typename Derived>
static constexpr bool is_boolean_expression_v = is_boolean_expression<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_tensor_view {
static constexpr bool value = false;
};
template<typename T, size_t DIMS, size_t M, size_t N, size_t ...Rest>
struct is_tensor_view<TensorViewExpr<Tensor<T,M,N,Rest...>,DIMS>> {
static constexpr bool value = true;
};
template<typename T, size_t DIMS, size_t M, size_t N, size_t ...Rest>
struct is_tensor_view<TensorConstViewExpr<Tensor<T,M,N,Rest...>,DIMS>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_tensor_view {
static constexpr bool value = is_tensor_view<Derived>::value ? true : false;
};
template<typename T, size_t DIMS, size_t M, size_t N, size_t ...Rest>
struct has_tensor_view<TensorViewExpr<Tensor<T,M,N,Rest...>,DIMS>> {
static constexpr bool value = true;
};
template<typename T, size_t DIMS, size_t M, size_t N, size_t ...Rest>
struct has_tensor_view<TensorConstViewExpr<Tensor<T,M,N,Rest...>,DIMS>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_tensor_view<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_tensor_view<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_tensor_view<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_tensor_view<TRhs>::value || has_tensor_view<TLhs>::value;
};
template<typename Derived>
static constexpr bool has_tensor_view_v = has_tensor_view<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_tensor_fixed_view_2d {
static constexpr bool value = false;
};
template<typename T, size_t M, size_t N, typename Seq0, typename Seq1>
struct is_tensor_fixed_view_2d<TensorFixedViewExpr2D<Tensor<T,M,N>,Seq0,Seq1,2>> {
static constexpr bool value = true;
};
template<typename T, size_t M, size_t N, typename Seq0, typename Seq1>
struct is_tensor_fixed_view_2d<TensorConstFixedViewExpr2D<Tensor<T,M,N>,Seq0,Seq1,2>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_tensor_fixed_view_2d {
static constexpr bool value = is_tensor_fixed_view_2d<Derived>::value ? true : false;
};
template<typename T, size_t M, size_t N, typename Seq0, typename Seq1>
struct has_tensor_fixed_view_2d<TensorFixedViewExpr2D<Tensor<T,M,N>,Seq0,Seq1,2>> {
static constexpr bool value = true;
};
template<typename T, size_t M, size_t N, typename Seq0, typename Seq1>
struct has_tensor_fixed_view_2d<TensorConstFixedViewExpr2D<Tensor<T,M,N>,Seq0,Seq1,2>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_tensor_fixed_view_2d<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_tensor_fixed_view_2d<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_tensor_fixed_view_2d<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_tensor_fixed_view_2d<TRhs>::value || has_tensor_fixed_view_2d<TLhs>::value;
};
template<typename Derived>
static constexpr bool has_tensor_fixed_view_2d_v = has_tensor_fixed_view_2d<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_tensor_fixed_view_nd {
static constexpr bool value = false;
};
template<typename T, size_t ...Rest, typename ...Fseq>
struct is_tensor_fixed_view_nd<TensorFixedViewExprnD<Tensor<T,Rest...>,Fseq...>> {
static constexpr bool value = true;
};
template<typename T, size_t ...Rest, typename ...Fseq>
struct is_tensor_fixed_view_nd<TensorConstFixedViewExprnD<Tensor<T,Rest...>,Fseq...>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_tensor_fixed_view_nd {
static constexpr bool value = is_tensor_fixed_view_nd<Derived>::value ? true : false;
};
template<typename T, size_t ...Rest, typename ...Fseq>
struct has_tensor_fixed_view_nd<TensorFixedViewExprnD<Tensor<T,Rest...>,Fseq...>> {
static constexpr bool value = true;
};
template<typename T, size_t ...Rest, typename ...Fseq>
struct has_tensor_fixed_view_nd<TensorConstFixedViewExprnD<Tensor<T,Rest...>,Fseq...>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_tensor_fixed_view_nd<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_tensor_fixed_view_nd<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_tensor_fixed_view_nd<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_tensor_fixed_view_nd<TRhs>::value || has_tensor_fixed_view_nd<TLhs>::value;
};
template<typename Derived>
static constexpr bool has_tensor_fixed_view_nd_v = has_tensor_fixed_view_nd<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
//------------------------------------------------------------------------------------------------//
template<typename T, typename T2 = void>
struct get_binary_arithmetic_result_type;
template<typename T>
struct get_binary_arithmetic_result_type<T, enable_if_t_<is_primitive_v_<T> > > {
using type = T;
};
template<typename T>
struct get_binary_arithmetic_result_type<T, enable_if_t_<!is_primitive_v_<T> > > {
using type = typename T::result_type;
};
template<class Derived>
struct binary_arithmetic_result_type;
template<template<typename,typename,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIM0>
struct binary_arithmetic_result_type< BinaryExpr<TLhs,TRhs,DIM0> > {
using type = conditional_t_<!is_primitive_v_<TLhs>,
typename get_binary_arithmetic_result_type<TLhs>::type,
typename get_binary_arithmetic_result_type<TRhs>::type >;
};
template<class Derived>
using binary_arithmetic_result_t = typename binary_arithmetic_result_type<Derived>::type;
//------------------------------------------------------------------------------------------------//
//------------------------------------------------------------------------------------------------//
template<typename T, typename T2 = void>
struct get_binary_op_simd_vector_type;
template<typename T>
struct get_binary_op_simd_vector_type<T, enable_if_t_<is_primitive_v_<T> > > {
using type = T;
};
template<typename T>
struct get_binary_op_simd_vector_type<T, enable_if_t_<!is_primitive_v_<T> > > {
using type = typename T::simd_vector_type;
};
template<class Derived>
struct binary_op_simd_vector_type;
template<template<typename,typename,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIM0>
struct binary_op_simd_vector_type< BinaryExpr<TLhs,TRhs,DIM0> > {
using type = conditional_t_<!is_primitive_v_<TLhs>,
typename get_binary_op_simd_vector_type<TLhs>::type,
typename get_binary_op_simd_vector_type<TRhs>::type >;
};
template<class Derived>
using binary_op_simd_vector_t = typename binary_op_simd_vector_type<Derived>::type;
//------------------------------------------------------------------------------------------------//
template<class T>
struct scalar_type_finder;
} // end of namespace Fastor
#endif // EXPRESSION_TRAITS_H

View File

@@ -0,0 +1,27 @@
#ifndef EXPRESSIONS_H
#define EXPRESSIONS_H
#include "Fastor/expressions/binary_ops/binary_arithmetic_ops.h"
// #include "Fastor/expressions/binary_ops/binary_add_op.h"
// #include "Fastor/expressions/binary_ops/binary_sub_op.h"
// #include "Fastor/expressions/binary_ops/binary_mul_op.h"
#include "Fastor/expressions/binary_ops/binary_div_op.h"
#include "Fastor/expressions/binary_ops/binary_arithmetic_assignment.h"
#include "Fastor/expressions/binary_ops/binary_math_ops.h"
#include "Fastor/expressions/binary_ops/binary_cmp_ops.h"
#include "Fastor/expressions/unary_ops/unary_math_ops.h"
#include "Fastor/expressions/unary_ops/unary_bool_ops.h"
#include "Fastor/expressions/linalg_ops/linalg_ops.h"
#include "Fastor/expressions/views/tensor_fixed_views_1d.h"
#include "Fastor/expressions/views/tensor_fixed_views_2d.h"
#include "Fastor/expressions/views/tensor_fixed_views_nd.h"
#include "Fastor/expressions/views/tensor_random_views.h"
#include "Fastor/expressions/views/tensor_filter_views.h"
#include "Fastor/expressions/views/tensor_diag_views.h"
#include "Fastor/expressions/views/tensor_views.h"
#include "Fastor/expressions/views/tensor_views_assignment.h"
#endif // EXPRESSIONS_H

View File

@@ -0,0 +1,191 @@
#ifndef BINARY_CROSS_OP_H
#define BINARY_CROSS_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/backend/tensor_cross.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
// classic vector cross product
template<typename T, size_t I, enable_if_t_<I==3,bool> = false>
FASTOR_INLINE Tensor<T,I> cross(const Tensor<T,I> &a, const Tensor<T,I> &b) {
Tensor<T,I> out;
_vector_crossproduct<T,I>(a.data(),b.data(),out.data());
return out;
}
template<typename T, size_t I, enable_if_t_<I==2,bool> = false>
FASTOR_INLINE Tensor<T,I+1> cross(const Tensor<T,I> &a, const Tensor<T,I> &b) {
Tensor<T,I+1> out;
_vector_crossproduct<T,I>(a.data(),b.data(),out.data());
return out;
}
// Tensor cross product of two 2nd order tensors
template<typename T, size_t I, size_t J, typename std::enable_if<I==3 && J==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J> cross(const Tensor<T,I,J> &b, const Tensor<T,I,J> &a) {
Tensor<T,I,J> out;
_crossproduct<T,I,I,J>(a.data(),b.data(),out.data());
return out;
}
template<typename T, size_t I, size_t J, typename std::enable_if<I==2 && J==2,bool>::type=0>
FASTOR_INLINE Tensor<T,I+1,J+1> cross(const Tensor<T,I,J> &b, const Tensor<T,I,J> &a) {
Tensor<T,I+1,J+1> out;
_crossproduct<T,I,I,J>(a.data(),b.data(),out.data());
return out;
}
template<int Plane, typename T, size_t I, size_t J, typename std::enable_if<I==2 && J==2 && Plane==FASTOR_PlaneStrain,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J> cross(const Tensor<T,I,J> &b, const Tensor<T,I,J> &a) {
// Plane strain case
Tensor<T,I,J> out;
Tensor<T,I+1,J+1> a3, b3;
a3(0,0) = a(0,0);
a3(0,1) = a(0,1);
a3(1,0) = a(1,0);
a3(1,1) = a(1,1);
a3(2,2) = 1;
b3(0,0) = b(0,0);
b3(0,1) = b(0,1);
b3(1,0) = b(1,0);
b3(1,1) = b(1,1);
b3(2,2) = 1;
_crossproduct<T,FASTOR_PlaneStrain>(a.data(),b.data(),out.data());
return out;
}
// Tensor cross product of a vector with 2nd order tensor
template<typename T, size_t I, size_t J, typename std::enable_if<I==3 && J==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J> cross(const Tensor<T,I> &b, const Tensor<T,I,J> &a) {
Tensor<T,I,J> out;
_crossproduct<T,I,1,J>(a.data(),b.data(),out.data());
return out;
}
template<typename T, size_t I, size_t J, typename std::enable_if<I==2 && J==2,bool>::type=0>
FASTOR_INLINE Tensor<T,I+1,J+1> cross(const Tensor<T,I> &b, const Tensor<T,I,J> &a) {
Tensor<T,I+1,J+1> out;
_crossproduct<T,I,1,J>(a.data(),b.data(),out.data());
return out;
}
// Tensor cross product of a 2nd order tensor with a vector
template<typename T, size_t I, size_t J, typename std::enable_if<I==3 && J==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J> cross(const Tensor<T,I,J> &b, const Tensor<T,J> &a) {
Tensor<T,I,J> out;
_crossproduct<T,I,J,1>(a.data(),b.data(),out.data());
return out;
}
template<typename T, size_t I, size_t J, typename std::enable_if<I==2 && J==2,bool>::type=0>
FASTOR_INLINE Tensor<T,I+1,J+1> cross(const Tensor<T,I,J> &b, const Tensor<T,J> &a) {
Tensor<T,I+1,J+1> out;
_crossproduct<T,I,J,1>(a.data(),b.data(),out.data());
return out;
}
// Tensor cross product of a 3rd order tensors
template<typename T, size_t I, size_t J, size_t K, size_t L, size_t M, size_t N,
typename std::enable_if<I==3 && J==3 && K==3 && L==3 && M==3 && N==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,3,3,N> cross(const Tensor<T,I,J,K> &A, const Tensor<T,L,M,N> &B) {
Tensor<T,I,3,3,N> C;
_crossproduct<T,I,J,K,L,M,N>(A.data(),B.data(),C.data());
return C;
}
// Tensor cross product of a 4th order tensors
template<typename T, size_t I, size_t J, size_t K, size_t L, size_t M, size_t N, size_t O, size_t P,
typename std::enable_if<I==3 && J==3 && K==3 && L==3 && M==3 && N==3 && O==3 && P==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J,3,3,O,P> cross(const Tensor<T,I,J,K,L> &A, const Tensor<T,M,N,O,P> &B) {
Tensor<T,I,J,3,3,O,P> C;
_crossproduct<T,I,J,K,L,M,N,O,P>(A.data(),B.data(),C.data());
return C;
}
// Tensor cross product of a 4th order tensor with 2nd order tensor
template<typename T, size_t I, size_t J, size_t K, size_t L, size_t M, size_t N,
typename std::enable_if<I==3 && J==3 && K==3 && L==3 && M==3 && N==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J,K,L> cross(const Tensor<T,I,J,K,L> &A, const Tensor<T,M,N> &B) {
Tensor<T,I,J,K,L> C;
_crossproduct42<T,I,J,K,L,M,N>(A.data(),B.data(),C.data());
return C;
}
// Tensor cross product of a 2nd order tensor with 4th order tensor
template<typename T, size_t I, size_t J, size_t K, size_t L, size_t M, size_t N,
typename std::enable_if<I==3 && J==3 && K==3 && L==3 && M==3 && N==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J,K,L> cross(const Tensor<T,M,N> &A, const Tensor<T,I,J,K,L> &B) {
Tensor<T,I,J,K,L> C;
_crossproduct24<T,I,J,K,L,M,N>(B.data(),A.data(),C.data());
return C;
}
// Tensor cross product of a 3rd order tensor with 2nd order tensor
template<typename T, size_t I, size_t J, size_t K, size_t L, size_t M,
typename std::enable_if<I==3 && J==3 && K==3 && L==3 && M==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J,K> cross(const Tensor<T,I,J,K> &A, const Tensor<T,L,M> &B) {
Tensor<T,I,J,K> C;
_crossproduct32<T,I,J,K,L,M>(A.data(),B.data(),C.data());
return C;
}
// Tensor cross product of a 2nd order tensor with 3rd order tensor
template<typename T, size_t I, size_t J, size_t K, size_t L, size_t M,
typename std::enable_if<I==3 && J==3 && K==3 && L==3 && M==3,bool>::type=0>
FASTOR_INLINE Tensor<T,I,J,K> cross(const Tensor<T,L,M> &A, const Tensor<T,I,J,K> &B) {
Tensor<T,I,J,K> C;
_crossproduct23<T,I,J,K,L,M>(B.data(),A.data(),C.data());
return C;
}
#if FASTOR_CXX_VERSION >= 2014
// Tensor cross product for generic expressions
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
auto
cross(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using rhs_type = typename Derived1::result_type;
const rhs_type tmp_b(b);
return cross(a.self(),tmp_b);
}
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<!is_tensor_v<Derived0> && is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
auto
cross(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using lhs_type = typename Derived0::result_type;
const lhs_type tmp_a(a);
return cross(tmp_a,b.self());
}
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<!is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
auto
cross(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using lhs_type = typename Derived0::result_type;
using rhs_type = typename Derived1::result_type;
const lhs_type tmp_a(a);
const rhs_type tmp_b(b);
return cross(tmp_a,tmp_b);
}
#endif
} // end of namespace Fastor
#endif // BINARY_CROSS_OP_H

View File

@@ -0,0 +1,627 @@
#ifndef BINARY_MATMUL_OP_H
#define BINARY_MATMUL_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/backend/inner.h"
#include "Fastor/backend/matmul/matmul.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename TLhs, typename TRhs, size_t DIM0>
struct BinaryMatMulOp: public AbstractTensor<BinaryMatMulOp<TLhs, TRhs, DIM0>,DIM0> {
using lhs_expr_type = expression_t<TLhs>;
using rhs_expr_type = expression_t<TRhs>;
using lhs_type = typename TLhs::result_type;
using rhs_type = typename TRhs::result_type;
static constexpr FASTOR_INDEX lhs_rank = lhs_type::dimension_t::value;
static constexpr FASTOR_INDEX rhs_rank = rhs_type::dimension_t::value;
static constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,lhs_type>;
static constexpr FASTOR_INDEX K = get_tensor_dimension_v<1,lhs_type>;
static constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,rhs_type>;
static constexpr FASTOR_INDEX K_other = get_tensor_dimension_v<0,rhs_type>;
static constexpr FASTOR_INDEX flop_count = M*N*K;
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<BinaryMatMulOp<TLhs, TRhs, DIM0>>::type;
// does not matter which one as matmul bypasses this
using simd_vector_type = typename TLhs::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = conditional_t_<lhs_rank == 1, // vector-matrix
Tensor<scalar_type,N> ,
conditional_t_<rhs_rank == 1, // matrix-vector
Tensor<scalar_type,M>,
Tensor<scalar_type,M,N> // matrix-matrix
>
>;
FASTOR_INLINE BinaryMatMulOp(lhs_expr_type inlhs, rhs_expr_type inrhs) : _lhs(inlhs), _rhs(inrhs) {
static_assert(lhs_rank <=2 && rhs_rank <=2, "EXPRESSIONS FOR MATRIX MULTIPLICATION HAVE TO BE 2-DIMENSIONAL");
static_assert(K == K_other, "INVALID MATMUL OPERANDS. COLUMNS(A)!=ROWS(B)");
}
constexpr FASTOR_INLINE FASTOR_INDEX size() const {return M*N;}
constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return i==0 ? M : N;}
constexpr FASTOR_INLINE lhs_expr_type lhs() const {return _lhs;}
constexpr FASTOR_INLINE rhs_expr_type rhs() const {return _rhs;}
private:
lhs_expr_type _lhs;
rhs_expr_type _rhs;
};
template<typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
enable_if_t_<!is_arithmetic_v_<TLhs> &&!is_arithmetic_v_<TRhs>,bool> = 0 >
constexpr FASTOR_INLINE BinaryMatMulOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>
operator %(const AbstractTensor<TLhs,DIM0> &lhs, const AbstractTensor<TRhs,DIM1> &rhs) {
return BinaryMatMulOp<TLhs, TRhs, meta_min<DIM0,DIM1>::value>(lhs.self(), rhs.self());
}
// helper dispatcher functions
namespace internal {
// till streaming gemm is implemented
template<typename T, size_t M, size_t K, size_t N>
FASTOR_INLINE
void _gemm(const T alpha, const T * FASTOR_RESTRICT a, const T * FASTOR_RESTRICT b, const T beta, T * FASTOR_RESTRICT c) {
FASTOR_ARCH_ALIGN T tmp[M*N];
if (beta == 0) {
// non-streaming
_matmul<T,M,K,N>(a,b,tmp);
for (size_t i = 0; i<M*N; ++i)
c[i] = alpha * tmp[i];
}
else {
// streaming
_matmul<T,M,K,N>(a,b,tmp);
for (size_t i = 0; i<M*N; ++i)
c[i] = alpha * tmp[i] + beta*c[i];
}
}
template<typename T, size_t M, size_t K, size_t N>
FASTOR_INLINE
void _gemm_mul(const T * FASTOR_RESTRICT a, const T * FASTOR_RESTRICT b, T * FASTOR_RESTRICT c) {
FASTOR_ARCH_ALIGN T tmp[M*N];
_matmul<T,M,K,N>(a,b,tmp);
for (size_t i = 0; i<M*N; ++i)
c[i] *= tmp[i];
}
template<typename T, size_t M, size_t K, size_t N>
FASTOR_INLINE
void _gemm_div(const T * FASTOR_RESTRICT a, const T * FASTOR_RESTRICT b, T * FASTOR_RESTRICT c) {
FASTOR_ARCH_ALIGN T tmp[M*N];
_matmul<T,M,K,N>(a,b,tmp);
for (size_t i = 0; i<M*N; ++i)
c[i] /= tmp[i];
}
// matmul - matvec overloads
template<typename T, size_t I, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher(const Tensor<T,I,J> &a, const Tensor<T,J,K> &b, Tensor<T,I,K> &out) {
FASTOR_IF_CONSTEXPR(J==1) {
_dyadic<T,I,K>(a.data(),b.data(),out.data());
}
else FASTOR_IF_CONSTEXPR(I==1 && J!=1 && K==1) {
out.data()[0] = _inner<T,J>(a.data(),b.data());
}
else {
_matmul<T,I,J,K>(a.data(),b.data(),out.data());
}
}
template<typename T, size_t I, size_t J>
FASTOR_INLINE void matmul_dispatcher(const Tensor<T,I,J> &a, const Tensor<T,J> &b, Tensor<T,I> &out) {
_matmul<T,I,J,1>(a.data(),b.data(),out.data());
}
template<typename T, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher(const Tensor<T,J> &a, const Tensor<T,J,K> &b, Tensor<T,K> &out) {
_matmul<T,1,J,K>(a.data(),b.data(),out.data());
}
template<typename T, size_t I, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher(const T alpha, const Tensor<T,I,J> &a, const Tensor<T,J,K> &b, const T beta, Tensor<T,I,K> &out) {
_gemm<T,I,J,K>(alpha,a.data(),b.data(),beta,out.data());
}
template<typename T, size_t I, size_t J>
FASTOR_INLINE void matmul_dispatcher(const T alpha, const Tensor<T,I,J> &a, const Tensor<T,J> &b, const T beta, Tensor<T,I> &out) {
_gemm<T,I,J,1>(alpha,a.data(),b.data(),beta,out.data());
}
template<typename T, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher(const T alpha, const Tensor<T,J> &a, const Tensor<T,J,K> &b, const T beta, Tensor<T,K> &out) {
_gemm<T,1,J,K>(alpha,a.data(),b.data(),beta,out.data());
}
template<typename T, size_t I, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher_mul(const Tensor<T,I,J> &a, const Tensor<T,J,K> &b, Tensor<T,I,K> &out) {
_gemm_mul<T,I,J,K>(a.data(),b.data(),out.data());
}
template<typename T, size_t I, size_t J>
FASTOR_INLINE void matmul_dispatcher_mul(const Tensor<T,I,J> &a, const Tensor<T,J> &b, Tensor<T,I> &out) {
_gemm_mul<T,I,J,1>(a.data(),b.data(),out.data());
}
template<typename T, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher_mul(const Tensor<T,J> &a, const Tensor<T,J,K> &b, Tensor<T,K> &out) {
_gemm_mul<T,1,J,K>(a.data(),b.data(),out.data());
}
template<typename T, size_t I, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher_div(const Tensor<T,I,J> &a, const Tensor<T,J,K> &b, Tensor<T,I,K> &out) {
_gemm_div<T,I,J,K>(a.data(),b.data(),out.data());
}
template<typename T, size_t I, size_t J>
FASTOR_INLINE void matmul_dispatcher_div(const Tensor<T,I,J> &a, const Tensor<T,J> &b, Tensor<T,I> &out) {
_gemm_div<T,I,J,1>(a.data(),b.data(),out.data());
}
template<typename T, size_t J, size_t K>
FASTOR_INLINE void matmul_dispatcher_div(const Tensor<T,J> &a, const Tensor<T,J,K> &b, Tensor<T,K> &out) {
_gemm_div<T,1,J,K>(a.data(),b.data(),out.data());
}
} // internal
// For tensors
template<typename T, size_t I, size_t J, size_t K>
FASTOR_INLINE Tensor<T,I,K> matmul(const Tensor<T,I,J> &a, const Tensor<T,J,K> &b) {
Tensor<T,I,K> out;
FASTOR_IF_CONSTEXPR(J==1) {
_dyadic<T,I,K>(a.data(),b.data(),out.data());
}
else FASTOR_IF_CONSTEXPR(I==1 && J!=1 && K==1) {
out.data()[0] = _inner<T,J>(a.data(),b.data());
}
else {
_matmul<T,I,J,K>(a.data(),b.data(),out.data());
}
return out;
}
template<typename T, size_t I, size_t J>
FASTOR_INLINE Tensor<T,I> matmul(const Tensor<T,I,J> &a, const Tensor<T,J> &b) {
Tensor<T,I> out;
_matmul<T,I,J,1>(a.data(),b.data(),out.data());
return out;
}
template<typename T, size_t J, size_t K>
FASTOR_INLINE Tensor<T,K> matmul(const Tensor<T,J> &a, const Tensor<T,J,K> &b) {
Tensor<T,K> out;
_matmul<T,1,J,K>(a.data(),b.data(),out.data());
return out;
}
// Generic matmul function for AbstractTensor types are provided here
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<is_less_equal_v_<DIM0,2> && is_less_equal_v_<DIM1,2>
&& !is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
conditional_t_<Derived0::result_type::dimension_t::value == 1,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<1,typename Derived1::result_type> >,
conditional_t_<Derived1::result_type::dimension_t::value == 1,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<0,typename Derived0::result_type> >,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<0,typename Derived0::result_type> ,
get_tensor_dimension_v<1,typename Derived1::result_type> >
>
>
matmul(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using lhs_type = typename Derived0::result_type;
using rhs_type = typename Derived1::result_type;
const lhs_type tmp_a(a);
const rhs_type tmp_b(b);
return matmul(tmp_a,tmp_b);
}
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<is_less_equal_v_<DIM0,2> && is_less_equal_v_<DIM1,2>
&& !is_tensor_v<Derived0> && is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
conditional_t_<Derived0::result_type::dimension_t::value == 1,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<1,typename Derived1::result_type> >,
conditional_t_<Derived1::result_type::dimension_t::value == 1,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<0,typename Derived0::result_type> >,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<0,typename Derived0::result_type> ,
get_tensor_dimension_v<1,typename Derived1::result_type> >
>
>
matmul(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using lhs_type = typename Derived0::result_type;
const lhs_type tmp_a(a);
return matmul(tmp_a,b.self());
}
template<typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<is_less_equal_v_<DIM0,2> && is_less_equal_v_<DIM1,2>
&& is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
conditional_t_<Derived0::result_type::dimension_t::value == 1,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<1,typename Derived1::result_type> >,
conditional_t_<Derived1::result_type::dimension_t::value == 1,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<0,typename Derived0::result_type> >,
Tensor<typename Derived0::scalar_type,
get_tensor_dimension_v<0,typename Derived0::result_type> ,
get_tensor_dimension_v<1,typename Derived1::result_type> >
>
>
matmul(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using rhs_type = typename Derived1::result_type;
const rhs_type tmp_b(b);
return matmul(a.self(),tmp_b);
}
// triangular matmul functions
template<typename LhsType = UpLoType::General, typename RhsType = UpLoType::General, typename T, size_t M, size_t K, size_t N>
Tensor<T,M,N> tmatmul(const Tensor<T,M,K> &a, const Tensor<T,K,N> &b) {
Tensor<T,M,N> out;
_tmatmul<T,M,K,N,LhsType,RhsType>(a.data(),b.data(),out.data());
return out;
}
template<typename LhsType = UpLoType::General, typename RhsType = UpLoType::General, typename T, size_t I, size_t J>
FASTOR_INLINE Tensor<T,I> tmatmul(const Tensor<T,I,J> &a, const Tensor<T,J> &b) {
Tensor<T,I> out;
_tmatmul<T,I,J,1,LhsType,RhsType>(a.data(),b.data(),out.data());
return out;
}
template<typename LhsType = UpLoType::General, typename RhsType = UpLoType::General, typename T, size_t J, size_t K>
FASTOR_INLINE Tensor<T,K> tmatmul(const Tensor<T,J> &a, const Tensor<T,J,K> &b) {
Tensor<T,K> out;
_tmatmul<T,1,J,K,LhsType,RhsType>(a.data(),b.data(),out.data());
return out;
}
#if FASTOR_CXX_VERSION >= 2014
// tmatmul for generic expressions
template<typename LhsType = UpLoType::General, typename RhsType = UpLoType::General,
typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<is_less_equal_v_<DIM0,2> && is_less_equal_v_<DIM1,2>
&& !is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
decltype(auto)
tmatmul(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using lhs_type = typename Derived0::result_type;
using rhs_type = typename Derived1::result_type;
const lhs_type tmp_a(a);
const rhs_type tmp_b(b);
return tmatmul<LhsType,RhsType>(tmp_a,tmp_b);
}
template<typename LhsType = UpLoType::General, typename RhsType = UpLoType::General,
typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<is_less_equal_v_<DIM0,2> && is_less_equal_v_<DIM1,2>
&& !is_tensor_v<Derived0> && is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
decltype(auto)
tmatmul(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using lhs_type = typename Derived0::result_type;
const lhs_type tmp_a(a);
return tmatmul<LhsType,RhsType>(tmp_a,b.self());
}
template<typename LhsType = UpLoType::General, typename RhsType = UpLoType::General,
typename Derived0, size_t DIM0, typename Derived1, size_t DIM1,
enable_if_t_<is_less_equal_v_<DIM0,2> && is_less_equal_v_<DIM1,2>
&& is_tensor_v<Derived0> && !is_tensor_v<Derived1>,bool> = 0 >
FASTOR_INLINE
decltype(auto)
tmatmul(const AbstractTensor<Derived0,DIM0> &a, const AbstractTensor<Derived1,DIM1> &b) {
using rhs_type = typename Derived1::result_type;
const rhs_type tmp_b(b);
return tmatmul<LhsType,RhsType>(a.self(),tmp_b);
}
#endif
// assignments
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
// dst = matmul(src.lhs().self(),src.rhs().self()); // this makes a copy for dst, compiler emits a memcpy
internal::matmul_dispatcher(src.lhs().self(),src.rhs().self(),dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
lhs_t a(src.lhs().self());
// dst = matmul(a,src.rhs().self()); // this makes a copy for dst, compiler emits a memcpy
internal::matmul_dispatcher(a,src.rhs().self(),dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
rhs_t b(src.rhs().self());
// dst = matmul(src.lhs().self(),b); // this makes a copy for dst, compiler emits a memcpy
internal::matmul_dispatcher(src.lhs().self(),b,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
lhs_t a(src.lhs().self());
rhs_t b(src.rhs().self());
// dst = matmul(a,b); // this makes a copy for dst, compiler emits a memcpy
internal::matmul_dispatcher(a,b,dst.self());
}
// assignments add
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
internal::matmul_dispatcher((T)1,src.lhs().self(),src.rhs().self(),(T)1,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
lhs_t a(src.lhs().self());
internal::matmul_dispatcher((T)1,a,src.rhs().self(),(T)1,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
rhs_t b(src.rhs().self());
internal::matmul_dispatcher((T)1,src.lhs().self(),b,(T)1,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
lhs_t a(src.lhs().self());
rhs_t b(src.rhs().self());
internal::matmul_dispatcher((T)1,a,b,(T)1,dst.self());
}
// assignments sub
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
internal::matmul_dispatcher((T)-1,src.lhs().self(),src.rhs().self(),(T)1,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
lhs_t a(src.lhs().self());
internal::matmul_dispatcher((T)-1,a,src.rhs().self(),(T)1,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
rhs_t b(src.rhs().self());
internal::matmul_dispatcher((T)-1,src.lhs().self(),b,(T)1,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using T = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::scalar_type;
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
lhs_t a(src.lhs().self());
rhs_t b(src.rhs().self());
internal::matmul_dispatcher((T)-1,a,b,(T)1,dst.self());
}
// assignments mul
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
internal::matmul_dispatcher_mul(src.lhs().self(),src.rhs().self(),dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
lhs_t a(src.lhs().self());
internal::matmul_dispatcher_mul(a,src.rhs().self(),dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
rhs_t b(src.rhs().self());
internal::matmul_dispatcher_mul(src.lhs().self(),b,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
lhs_t a(src.lhs().self());
rhs_t b(src.rhs().self());
internal::matmul_dispatcher_mul(a,b,dst.self());
}
// assignments div
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
internal::matmul_dispatcher_div(src.lhs().self(),src.rhs().self(),dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
lhs_t a(src.lhs().self());
internal::matmul_dispatcher_div(a,src.rhs().self(),dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
rhs_t b(src.rhs().self());
internal::matmul_dispatcher_div(src.lhs().self(),b,dst.self());
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs, size_t OtherDIM,
typename std::enable_if<!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_expr_type>> &&
!is_tensor_v<remove_all_t<typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_expr_type>>, bool >::type = false>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<TLhs, TRhs, OtherDIM> &src) {
using lhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::lhs_type;
using rhs_t = typename BinaryMatMulOp<TLhs, TRhs, OtherDIM>::rhs_type;
lhs_t a(src.lhs().self());
rhs_t b(src.rhs().self());
internal::matmul_dispatcher_div(a,b,dst.self());
}
// recursive greedy-like
template<typename Derived, size_t DIM, typename TLhs, typename TRhs0, typename TRhs1, size_t OtherDIM>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<BinaryMatMulOp<TLhs, TRhs0, OtherDIM>, TRhs1, OtherDIM> &src) {
FASTOR_IF_CONSTEXPR(BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::flop_count > BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::flop_count)
{
using result_t = typename BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>(src.lhs().rhs().self(),src.rhs().self()));
assign(dst, BinaryMatMulOp<TLhs, result_t, OtherDIM>(src.lhs().lhs().self(),tmp));
}
else
{
using result_t = typename BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TLhs, TRhs0, OtherDIM>(src.lhs().lhs().self(),src.lhs().rhs().self()));
assign(dst, BinaryMatMulOp<result_t, TRhs1, OtherDIM>(tmp,src.rhs().self()));
}
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs0, typename TRhs1, size_t OtherDIM>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<BinaryMatMulOp<TLhs, TRhs0, OtherDIM>, TRhs1, OtherDIM> &src) {
FASTOR_IF_CONSTEXPR(BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::flop_count > BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::flop_count)
{
using result_t = typename BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>(src.lhs().rhs().self(),src.rhs().self()));
assign_add(dst, BinaryMatMulOp<TLhs, result_t, OtherDIM>(src.lhs().lhs().self(),tmp));
}
else
{
using result_t = typename BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TLhs, TRhs0, OtherDIM>(src.lhs().lhs().self(),src.lhs().rhs().self()));
assign_add(dst, BinaryMatMulOp<result_t, TRhs1, OtherDIM>(tmp,src.rhs().self()));
}
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs0, typename TRhs1, size_t OtherDIM>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<BinaryMatMulOp<TLhs, TRhs0, OtherDIM>, TRhs1, OtherDIM> &src) {
FASTOR_IF_CONSTEXPR(BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::flop_count > BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::flop_count)
{
using result_t = typename BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>(src.lhs().rhs().self(),src.rhs().self()));
assign_sub(dst, BinaryMatMulOp<TLhs, result_t, OtherDIM>(src.lhs().lhs().self(),tmp));
}
else
{
using result_t = typename BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TLhs, TRhs0, OtherDIM>(src.lhs().lhs().self(),src.lhs().rhs().self()));
assign_sub(dst, BinaryMatMulOp<result_t, TRhs1, OtherDIM>(tmp,src.rhs().self()));
}
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs0, typename TRhs1, size_t OtherDIM>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<BinaryMatMulOp<TLhs, TRhs0, OtherDIM>, TRhs1, OtherDIM> &src) {
FASTOR_IF_CONSTEXPR(BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::flop_count > BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::flop_count)
{
using result_t = typename BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>(src.lhs().rhs().self(),src.rhs().self()));
assign_mul(dst, BinaryMatMulOp<TLhs, result_t, OtherDIM>(src.lhs().lhs().self(),tmp));
}
else
{
using result_t = typename BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TLhs, TRhs0, OtherDIM>(src.lhs().lhs().self(),src.lhs().rhs().self()));
assign_mul(dst, BinaryMatMulOp<result_t, TRhs1, OtherDIM>(tmp,src.rhs().self()));
}
}
template<typename Derived, size_t DIM, typename TLhs, typename TRhs0, typename TRhs1, size_t OtherDIM>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const BinaryMatMulOp<BinaryMatMulOp<TLhs, TRhs0, OtherDIM>, TRhs1, OtherDIM> &src) {
FASTOR_IF_CONSTEXPR(BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::flop_count > BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::flop_count)
{
using result_t = typename BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TRhs0, TRhs1, OtherDIM>(src.lhs().rhs().self(),src.rhs().self()));
assign_div(dst, BinaryMatMulOp<TLhs, result_t, OtherDIM>(src.lhs().lhs().self(),tmp));
}
else
{
using result_t = typename BinaryMatMulOp<TLhs, TRhs0, OtherDIM>::result_type;
result_t tmp;
assign(tmp, BinaryMatMulOp<TLhs, TRhs0, OtherDIM>(src.lhs().lhs().self(),src.lhs().rhs().self()));
assign_div(dst, BinaryMatMulOp<result_t, TRhs1, OtherDIM>(tmp,src.rhs().self()));
}
}
} // end of namespace Fastor
#endif // BINARY_MATMUL_OP_H

View File

@@ -0,0 +1,197 @@
#ifndef BINARY_SOLVE_OP_H
#define BINARY_SOLVE_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/binary_matmul_op.h"
#include "Fastor/expressions/linalg_ops/unary_inv_op.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/unary_piv_op.h"
namespace Fastor {
// Solving using LU decomposition is in the LU module [unary_lu_op]
// For tensors
// Solve - no pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t I,
enable_if_t_< SType == SolveCompType::SimpleInv, bool> = false>
FASTOR_INLINE Tensor<T,I> solve(const Tensor<T,I,I> &A, const Tensor<T,I> &b) {
return matmul(inverse<InvCompType::SimpleInv>(A),b);
}
// Solve - pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t I,
enable_if_t_< SType == SolveCompType::SimpleInvPiv, bool> = false>
FASTOR_INLINE Tensor<T,I> solve(const Tensor<T,I,I> &A, const Tensor<T,I> &b) {
// We need to post multiply - swap columns using row permutation vector
Tensor<size_t,I> p;
pivot_inplace(A,p);
auto tmp(apply_pivot(A,p));
Tensor<T,I,I> invA = inverse<InvCompType::SimpleInv>(tmp);
return matmul(reconstruct_colwise(invA,p),b);
// // matrix version
// Tensor<T,I,I> p;
// pivot_inplace(A,p);
// auto tmp(apply_pivot(A,p));
// Tensor<T,I,I> invA = inverse<InvCompType::SimpleInv>(tmp);
// return matmul(matmul(invA,p),b);
}
// Multiple right hand sides
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t I, size_t J,
enable_if_t_< SType == SolveCompType::SimpleInv, bool> = false>
FASTOR_INLINE Tensor<T,I,J> solve(const Tensor<T,I,I> &A, const Tensor<T,I,J> &B) {
return matmul(inverse(A),B);
}
// Solve - pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t I, size_t J,
enable_if_t_< SType == SolveCompType::SimpleInvPiv, bool> = false>
FASTOR_INLINE Tensor<T,I,J> solve(const Tensor<T,I,I> &A, const Tensor<T,I,J> &B) {
Tensor<size_t,I> p;
pivot_inplace(A,p);
auto tmp(apply_pivot(A,p));
Tensor<T,I,I> invA = inverse<InvCompType::SimpleInv>(tmp);
return matmul(reconstruct(invA,p),B);
}
// For expressions
template<SolveCompType SType = SolveCompType::SimpleInv,
typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
enable_if_t_< is_tensor_v<TLhs> && is_tensor_v<TRhs> && DIM0==2,bool> = false>
FASTOR_INLINE
conditional_t_<TRhs::result_type::dimension_t::value == 1,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>
>,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>,
get_tensor_dimension_v<1,typename TRhs::result_type>
>
>
solve(const AbstractTensor<TLhs,DIM0> &lhs, const AbstractTensor<TRhs,DIM1> &rhs) {
using lhs_type = typename TLhs::result_type;
using rhs_type = typename TRhs::result_type;
constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,lhs_type>;
constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,lhs_type>;
constexpr FASTOR_INDEX M_other = get_tensor_dimension_v<0,rhs_type>;
static_assert(M==N, "LHS EXPRESSION FOR SOLVE HAS TO BE A SQUARE MATRIX");
static_assert(M == M_other, "INVALID SOLVE OPERANDS. IN Ax=b ROWS(A)!=ROWS(b)");
return solve<SType>(lhs.self(),rhs.self());
}
template<SolveCompType SType = SolveCompType::SimpleInv,
typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
enable_if_t_< !is_tensor_v<TLhs> && is_tensor_v<TRhs> && DIM0==2,bool> = false>
FASTOR_INLINE
conditional_t_<TRhs::result_type::dimension_t::value == 1,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>
>,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>,
get_tensor_dimension_v<1,typename TRhs::result_type>
>
>
solve(const AbstractTensor<TLhs,DIM0> &lhs, const AbstractTensor<TRhs,DIM1> &rhs) {
using lhs_type = typename TLhs::result_type;
using rhs_type = typename TRhs::result_type;
constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,lhs_type>;
constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,lhs_type>;
constexpr FASTOR_INDEX M_other = get_tensor_dimension_v<0,rhs_type>;
static_assert(M==N, "LHS EXPRESSION FOR SOLVE HAS TO BE A SQUARE MATRIX");
static_assert(M == M_other, "INVALID SOLVE OPERANDS. IN Ax=b ROWS(A)!=ROWS(b)");
const lhs_type A(lhs.self());
return solve<SType>(A,rhs.self());
}
template<SolveCompType SType = SolveCompType::SimpleInv,
typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
enable_if_t_< is_tensor_v<TLhs> && !is_tensor_v<TRhs> && DIM0==2,bool> = false>
FASTOR_INLINE
conditional_t_<TRhs::result_type::dimension_t::value == 1,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>
>,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>,
get_tensor_dimension_v<1,typename TRhs::result_type>
>
>
solve(const AbstractTensor<TLhs,DIM0> &lhs, const AbstractTensor<TRhs,DIM1> &rhs) {
using lhs_type = typename TLhs::result_type;
using rhs_type = typename TRhs::result_type;
constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,lhs_type>;
constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,lhs_type>;
constexpr FASTOR_INDEX M_other = get_tensor_dimension_v<0,rhs_type>;
static_assert(M==N, "LHS EXPRESSION FOR SOLVE HAS TO BE A SQUARE MATRIX");
static_assert(M == M_other, "INVALID SOLVE OPERANDS. IN Ax=b ROWS(A)!=ROWS(b)");
const rhs_type b(rhs.self());
return solve<SType>(lhs.self(),b);
}
template<SolveCompType SType = SolveCompType::SimpleInv,
typename TLhs, typename TRhs, size_t DIM0, size_t DIM1,
enable_if_t_< !is_tensor_v<TLhs> && !is_tensor_v<TRhs> && DIM0==2,bool> = false>
FASTOR_INLINE
conditional_t_<TRhs::result_type::dimension_t::value == 1,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>
>,
Tensor<
typename TLhs::scalar_type,
get_tensor_dimension_v<0,typename TLhs::result_type>,
get_tensor_dimension_v<1,typename TRhs::result_type>
>
>
solve(const AbstractTensor<TLhs,DIM0> &lhs, const AbstractTensor<TRhs,DIM1> &rhs) {
using lhs_type = typename TLhs::result_type;
using rhs_type = typename TRhs::result_type;
constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,lhs_type>;
constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,lhs_type>;
constexpr FASTOR_INDEX M_other = get_tensor_dimension_v<0,rhs_type>;
static_assert(M==N, "LHS EXPRESSION FOR SOLVE HAS TO BE A SQUARE MATRIX");
static_assert(M == M_other, "INVALID SOLVE OPERANDS. IN Ax=b ROWS(A)!=ROWS(b)");
const lhs_type A(lhs.self());
const rhs_type b(rhs.self());
return solve<SType>(A,b);
}
} // end of namespace Fastor
#endif // BINARY_SOLVE_OP_H

View File

@@ -0,0 +1,66 @@
#ifndef LINALG_COMPUTATION_TYPES_H
#define LINALG_COMPUTATION_TYPES_H
namespace Fastor {
// Pivot types
enum class PivType : int
{
V = 0, /* The permutation vector */
M, /* The permutatoin matrix */
};
// QR factorisation computation types
enum class QRCompType : int
{
MGSR = 0, /* Modified Gram-Schmidt Row-wise */
MGSRPiv, /* Modified Gram-Schmidt Row-wise with pivot */
HHR /* House Holder Reflections */
};
// LU factorisation computation types
enum class LUCompType : int
{
BlockLU = 0, /* Block LU decomposition wiht no pivot */
BlockLUPiv, /* Block LU decomposition wiht pivot */
SimpleLU, /* Simple LU decomposition wiht no pivot */
SimpleLUPiv, /* Simple LU decomposition wiht pivot */
};
// Determinant computation type
enum class DetCompType : int
{
Simple = 0, /* Using simple hand-optimised calculations */
LU, /* Using LU factorisation */
QR, /* Using QR factorisation */
};
// Inverse computation type
enum class InvCompType : int
{
SimpleInv = 0,/* Using simple hand-optimised calculations */
SimpleInvPiv, /* Simple with pivot */
BlockLU, /* Using block LU factorisation */
BlockLUPiv, /* Using block LU factorisation with pivot */
SimpleLU, /* Using simple LU factorisation */
SimpleLUPiv, /* Using simple LU factorisation with pivot */
};
// Solve computation type
enum class SolveCompType : int
{
SimpleInv = 0, /* Using optimised inversion */
SimpleInvPiv, /* Using optimised inversion with pivot */
BlockLU, /* Using block LU factorisation */
BlockLUPiv, /* Using block LU factorisation with pivot */
SimpleLU, /* Using simple LU factorisation */
SimpleLUPiv, /* Using simple LU factorisation with pivot */
QR, /* Using QR factorisation */
Chol, /* Using Cholesky factorisation */
};
} // end of namespace Fastor
#endif // LINALG_COMPUTATION_TYPES_H

View File

@@ -0,0 +1,24 @@
#ifndef LINALG_OPS_H
#define LINALG_OPS_H
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/binary_matmul_op.h"
#include "Fastor/expressions/linalg_ops/unary_piv_op.h"
#include "Fastor/expressions/linalg_ops/unary_lu_op.h"
#include "Fastor/expressions/linalg_ops/binary_solve_op.h"
#include "Fastor/expressions/linalg_ops/unary_trans_op.h"
#include "Fastor/expressions/linalg_ops/unary_ctrans_op.h"
#include "Fastor/expressions/linalg_ops/unary_adj_op.h"
#include "Fastor/expressions/linalg_ops/unary_cof_op.h"
#include "Fastor/expressions/linalg_ops/unary_inv_op.h"
#include "Fastor/expressions/linalg_ops/unary_trace_op.h"
#include "Fastor/expressions/linalg_ops/unary_norm_op.h"
#include "Fastor/expressions/linalg_ops/unary_qr_op.h"
#include "Fastor/expressions/linalg_ops/unary_det_op.h"
#include "Fastor/expressions/linalg_ops/unary_svd_op.h"
#include "Fastor/expressions/linalg_ops/binary_cross_op.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
#endif // LINALG_OPS_H

View File

@@ -0,0 +1,273 @@
#ifndef LINALG_TRAITS_H
#define LINALG_TRAITS_H
#include "Fastor/expressions/linalg_ops/binary_matmul_op.h"
#include "Fastor/expressions/linalg_ops/unary_trans_op.h"
#include "Fastor/expressions/linalg_ops/unary_ctrans_op.h"
#include "Fastor/expressions/linalg_ops/unary_adj_op.h"
#include "Fastor/expressions/linalg_ops/unary_cof_op.h"
#include "Fastor/expressions/linalg_ops/unary_inv_op.h"
#include "Fastor/expressions/linalg_ops/binary_solve_op.h"
#include <type_traits>
namespace Fastor {
// Is a binary matmul expression
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_binary_matmul_op {
static constexpr bool value = false;
};
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t DIM>
struct is_binary_matmul_op<BinaryMatMulOp<Tensor<T,Rest0...>,Tensor<T,Rest1...>,DIM>> {
static constexpr bool value = true;
};
template<typename Derived0, typename Derived1, size_t DIM>
struct is_binary_matmul_op<BinaryMatMulOp<Derived0,Derived1,DIM>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_binary_matmul_op {
static constexpr bool value = is_binary_matmul_op<Derived>::value ? true : false;
};
template<typename T, size_t ... Rest0, size_t ... Rest1, size_t DIM>
struct has_binary_matmul_op<BinaryMatMulOp<Tensor<T,Rest0...>,Tensor<T,Rest1...>,DIM>> {
static constexpr bool value = true;
};
template<typename Derived0, typename Derived1, size_t DIM>
struct has_binary_matmul_op<BinaryMatMulOp<Derived0,Derived1,DIM>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_binary_matmul_op<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_binary_matmul_op<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_binary_matmul_op<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_binary_matmul_op<TRhs>::value || has_binary_matmul_op<TLhs>::value;
};
// helper
template<typename Derived>
static constexpr bool is_binary_matmul_op_v = is_binary_matmul_op<Derived>::value;
template<typename Derived>
static constexpr bool has_binary_matmul_op_v = has_binary_matmul_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
// Is unary trans expression
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_unary_trans_op {
static constexpr bool value = false;
};
template<typename Derived, size_t DIM>
struct is_unary_trans_op<UnaryTransOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_unary_trans_op {
static constexpr bool value = is_unary_trans_op<Derived>::value ? true : false;
};
template<typename Derived, size_t DIM>
struct has_unary_trans_op<UnaryTransOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_unary_trans_op<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_unary_trans_op<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_unary_trans_op<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_unary_trans_op<TRhs>::value || has_unary_trans_op<TLhs>::value;
};
// helper
template<typename Derived>
static constexpr bool is_unary_trans_op_v = is_unary_trans_op<Derived>::value;
template<typename Derived>
static constexpr bool has_unary_trans_op_v = has_unary_trans_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
// Is unary ctrans expression
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_unary_ctrans_op {
static constexpr bool value = false;
};
template<typename Derived, size_t DIM>
struct is_unary_ctrans_op<UnaryCTransOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_unary_ctrans_op {
static constexpr bool value = is_unary_ctrans_op<Derived>::value ? true : false;
};
template<typename Derived, size_t DIM>
struct has_unary_ctrans_op<UnaryCTransOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_unary_ctrans_op<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_unary_ctrans_op<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_unary_ctrans_op<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_unary_ctrans_op<TRhs>::value || has_unary_ctrans_op<TLhs>::value;
};
// helper
template<typename Derived>
static constexpr bool is_unary_ctrans_op_v = is_unary_ctrans_op<Derived>::value;
template<typename Derived>
static constexpr bool has_unary_ctrans_op_v = has_unary_ctrans_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
// Is unary adj expression
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_unary_adj_op {
static constexpr bool value = false;
};
template<typename Derived, size_t DIM>
struct is_unary_adj_op<UnaryAdjOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_unary_adj_op {
static constexpr bool value = is_unary_adj_op<Derived>::value ? true : false;
};
template<typename Derived, size_t DIM>
struct has_unary_adj_op<UnaryAdjOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_unary_adj_op<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_unary_adj_op<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_unary_adj_op<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_unary_adj_op<TRhs>::value || has_unary_adj_op<TLhs>::value;
};
// helper
template<typename Derived>
static constexpr bool is_unary_adj_op_v = is_unary_adj_op<Derived>::value;
template<typename Derived>
static constexpr bool has_unary_adj_op_v = has_unary_adj_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
// Is unary adj expression
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_unary_cof_op {
static constexpr bool value = false;
};
template<typename Derived, size_t DIM>
struct is_unary_cof_op<UnaryCofOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_unary_cof_op {
static constexpr bool value = is_unary_cof_op<Derived>::value ? true : false;
};
template<typename Derived, size_t DIM>
struct has_unary_cof_op<UnaryCofOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_unary_cof_op<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_unary_cof_op<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_unary_cof_op<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_unary_cof_op<TRhs>::value || has_unary_cof_op<TLhs>::value;
};
// helper
template<typename Derived>
static constexpr bool is_unary_cof_op_v = is_unary_cof_op<Derived>::value;
template<typename Derived>
static constexpr bool has_unary_cof_op_v = has_unary_cof_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
// Is unary inv expression
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct is_unary_inv_op {
static constexpr bool value = false;
};
template<typename Derived, size_t DIM>
struct is_unary_inv_op<UnaryInvOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<typename Derived>
struct has_unary_inv_op {
static constexpr bool value = is_unary_inv_op<Derived>::value ? true : false;
};
template<typename Derived, size_t DIM>
struct has_unary_inv_op<UnaryInvOp<Derived,DIM>> {
static constexpr bool value = true;
};
template<template<typename,size_t> class UnaryExpr, typename Expr, size_t DIM>
struct has_unary_inv_op<UnaryExpr<Expr,DIM>> {
static constexpr bool value = has_unary_inv_op<Expr>::value;
};
template<template<class,class,size_t> class BinaryExpr, typename TLhs, typename TRhs, size_t DIMS>
struct has_unary_inv_op<BinaryExpr<TLhs,TRhs,DIMS>> {
static constexpr bool value = has_unary_inv_op<TRhs>::value || has_unary_inv_op<TLhs>::value;
};
// helper
template<typename Derived>
static constexpr bool is_unary_inv_op_v = is_unary_inv_op<Derived>::value;
template<typename Derived>
static constexpr bool has_unary_inv_op_v = has_unary_inv_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
// Is a linear algebra expression
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct has_linalg_op {
static constexpr bool value = has_binary_matmul_op<Derived>::value || has_unary_trans_op<Derived>::value ||
has_unary_ctrans_op<Derived>::value || has_unary_adj_op<Derived>::value ||
has_unary_cof_op<Derived>::value || has_unary_inv_op<Derived>::value;
};
// helper
template<typename Derived>
static constexpr bool has_linalg_op_v = has_linalg_op<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
// Requires immediate evaluation
//----------------------------------------------------------------------------------------------------------//
template<typename Derived>
struct requires_evaluation {
static constexpr bool value = has_linalg_op<Derived>::value;
};
// helper
template<typename Derived>
static constexpr bool requires_evaluation_v = requires_evaluation<Derived>::value;
//----------------------------------------------------------------------------------------------------------//
} // end of namespace Fastor
#endif // LINALG_TRAITS_H

View File

@@ -0,0 +1,160 @@
#ifndef UNARY_ADJ_OP_H
#define UNARY_ADJ_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/backend/adjoint.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename Expr, size_t DIM0>
struct UnaryAdjOp: public AbstractTensor<UnaryAdjOp<Expr, DIM0>,DIM0> {
using expr_type = expression_t<Expr>;
using result_type = typename Expr::result_type;
static constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,result_type>;
static constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,result_type>;
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<UnaryAdjOp<Expr, DIM0>>::type;
using simd_vector_type = typename Expr::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
FASTOR_INLINE UnaryAdjOp(expr_type inexpr) : _expr(inexpr) {
static_assert(M==N, "MATRIX MUST BE SQUARE");
}
FASTOR_INLINE FASTOR_INDEX size() const {return M*N;}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX ) const {return M;}
constexpr FASTOR_INLINE expr_type expr() const {return _expr;}
private:
expr_type _expr;
};
template<typename Expr, size_t DIM0>
FASTOR_INLINE UnaryAdjOp<Expr, DIM0>
adj(const AbstractTensor<Expr,DIM0> &src) {
return UnaryAdjOp<Expr, DIM0>(src.self());
}
namespace internal {
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,4>,bool> = false>
FASTOR_INLINE void adjoint_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
_adjoint<T,M>(in.data(),out.data());
}
} // internal
// For tensors
template<typename T, size_t I>
FASTOR_INLINE Tensor<T,I,I> adjoint(const Tensor<T,I,I> &a) {
Tensor<T,I,I> out;
_adjoint<T,I>(a.data(),out.data());
return out;
}
// For high order tensors
template<typename T, size_t ... Rest, typename std::enable_if<sizeof...(Rest)>=3,bool>::type=0>
FASTOR_INLINE Tensor<T,Rest...>
adjoint(const Tensor<T,Rest...> &a) {
constexpr size_t remaining_product = last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::remaining_product;
constexpr size_t I = get_value<sizeof...(Rest)-1,Rest...>::value;
constexpr size_t J = get_value<sizeof...(Rest),Rest...>::value;
static_assert(I==J,"THE LAST TWO DIMENSIONS OF TENSOR MUST BE THE SAME");
Tensor<T,Rest...> out;
T *a_data = a.data();
T *out_data = out.data();
for (size_t i=0; i<remaining_product; ++i) {
_adjoint<T,J,J>(a_data+i*J*J,out_data+i*J*J);
}
return out;
}
// Adjoint for generic expressions is provided here
template<typename Derived, size_t DIM>
FASTOR_INLINE
typename Derived::result_type
adjoint(const AbstractTensor<Derived,DIM> &src) {
// If we are here Derived is already an expression
using result_type = typename Derived::result_type;
const result_type tmp(src.self());
return adjoint(tmp);
}
// assignments
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const UnaryAdjOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
const result_type& tmp = evaluate(src.expr().self());
internal::adjoint_dispatcher(tmp,dst.self());
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const UnaryAdjOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::adjoint_dispatcher(tmp,tmp_inv);
trivial_assign_add(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const UnaryAdjOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::adjoint_dispatcher(tmp,tmp_inv);
trivial_assign_sub(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const UnaryAdjOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::adjoint_dispatcher(tmp,tmp_inv);
trivial_assign_mul(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const UnaryAdjOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::adjoint_dispatcher(tmp,tmp_inv);
trivial_assign_div(dst.self(),tmp_inv);
}
} // end of namespace Fastor
#endif // UNARY_ADJ_OP_H

View File

@@ -0,0 +1,160 @@
#ifndef UNARY_COF_OP_H
#define UNARY_COF_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/backend/cofactor.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename Expr, size_t DIM0>
struct UnaryCofOp: public AbstractTensor<UnaryCofOp<Expr, DIM0>,DIM0> {
using expr_type = expression_t<Expr>;
using result_type = typename Expr::result_type;
static constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,result_type>;
static constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,result_type>;
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<UnaryCofOp<Expr, DIM0>>::type;
using simd_vector_type = typename Expr::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
FASTOR_INLINE UnaryCofOp(expr_type inexpr) : _expr(inexpr) {
static_assert(M==N, "MATRIX MUST BE SQUARE");
}
FASTOR_INLINE FASTOR_INDEX size() const {return M*N;}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX ) const {return M;}
constexpr FASTOR_INLINE expr_type expr() const {return _expr;}
private:
expr_type _expr;
};
template<typename Expr, size_t DIM0>
FASTOR_INLINE UnaryCofOp<Expr, DIM0>
cof(const AbstractTensor<Expr,DIM0> &src) {
return UnaryCofOp<Expr, DIM0>(src.self());
}
namespace internal {
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,4>,bool> = false>
FASTOR_INLINE void cofactor_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
_cofactor<T,M>(in.data(),out.data());
}
} // internal
// For tensors
template<typename T, size_t I>
FASTOR_INLINE Tensor<T,I,I> cofactor(const Tensor<T,I,I> &a) {
Tensor<T,I,I> out;
_cofactor<T,I>(a.data(),out.data());
return out;
}
// For high order tensors
template<typename T, size_t ... Rest, typename std::enable_if<sizeof...(Rest)>=3,bool>::type=0>
FASTOR_INLINE Tensor<T,Rest...>
cofactor(const Tensor<T,Rest...> &a) {
constexpr size_t remaining_product = last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::remaining_product;
constexpr size_t I = get_value<sizeof...(Rest)-1,Rest...>::value;
constexpr size_t J = get_value<sizeof...(Rest),Rest...>::value;
static_assert(I==J,"THE LAST TWO DIMENSIONS OF TENSOR MUST BE THE SAME");
Tensor<T,Rest...> out;
T *a_data = a.data();
T *out_data = out.data();
for (size_t i=0; i<remaining_product; ++i) {
_cofactor<T,J,J>(a_data+i*J*J,out_data+i*J*J);
}
return out;
}
// Cofactor for generic expressions is provided here
template<typename Derived, size_t DIM>
FASTOR_INLINE
typename Derived::result_type
cofactor(const AbstractTensor<Derived,DIM> &src) {
// If we are here Derived is already an expression
using result_type = typename Derived::result_type;
const result_type tmp(src.self());
return cofactor(tmp);
}
// assignments
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const UnaryCofOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
const result_type& tmp = evaluate(src.expr().self());
internal::cofactor_dispatcher(tmp,dst.self());
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const UnaryCofOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::cofactor_dispatcher(tmp,tmp_inv);
trivial_assign_add(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const UnaryCofOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::cofactor_dispatcher(tmp,tmp_inv);
trivial_assign_sub(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const UnaryCofOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::cofactor_dispatcher(tmp,tmp_inv);
trivial_assign_mul(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const UnaryCofOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::cofactor_dispatcher(tmp,tmp_inv);
trivial_assign_div(dst.self(),tmp_inv);
}
} // end of namespace Fastor
#endif // UNARY_COF_OP_H

View File

@@ -0,0 +1,178 @@
#ifndef UNARY_CTRANS_OP_H
#define UNARY_CTRANS_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename Expr, size_t DIM0>
struct UnaryCTransOp: public AbstractTensor<UnaryCTransOp<Expr, DIM0>,DIM0> {
using expr_type = expression_t<Expr>;
static constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,typename Expr::result_type>;
static constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,typename Expr::result_type>;
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<UnaryCTransOp<Expr, DIM0>>::type;
using simd_vector_type = typename Expr::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<scalar_type,N,M>;
FASTOR_INLINE UnaryCTransOp(expr_type inexpr) : _expr(inexpr) {
}
FASTOR_INLINE FASTOR_INDEX size() const {return M*N;}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return i == 0 ? N : M;}
constexpr FASTOR_INLINE expr_type expr() const {return _expr;}
private:
expr_type _expr;
};
/* Tensor conjugate transpose returning a tensor expression */
template<typename Expr, size_t DIM0>
FASTOR_INLINE UnaryCTransOp<Expr, DIM0>
ctrans(const AbstractTensor<Expr,DIM0> &src) {
return UnaryCTransOp<Expr, DIM0>(src.self());
}
/* Backend implementation */
template<typename T, size_t M, size_t N>
FASTOR_INLINE void _ctranspose(const T * FASTOR_RESTRICT a, T * FASTOR_RESTRICT out) {
for (size_t j=0; j<N; ++j)
for (size_t i=0; i< M; ++i)
out[j*M+i] = conj(a[i*N+j]);
}
/* Tensor conjugate transpose immediately returning a tensor */
template<typename T, size_t I, size_t J>
FASTOR_INLINE Tensor<T,J,I> ctranspose(const Tensor<T,I,J> &a) {
Tensor<T,J,I> out;
_ctranspose<T,I,J>(a.data(),out.data());
return out;
}
/* Tensor conjugate transpose for higher order tensors immediately returning a tensor */
template<typename T, size_t ... Rest, typename std::enable_if<sizeof...(Rest)>=3,bool>::type=0>
FASTOR_INLINE Tensor<T,Rest...>
ctranspose(const Tensor<T,Rest...> &a) {
constexpr size_t remaining_product = last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::remaining_product;
constexpr size_t I = get_value<sizeof...(Rest)-1,Rest...>::value;
constexpr size_t J = get_value<sizeof...(Rest),Rest...>::value;
static_assert(I==J,"THE LAST TWO DIMENSIONS OF TENSOR MUST BE THE SAME");
Tensor<T,Rest...> out;
T *a_data = a.data();
T *out_data = out.data();
for (size_t i=0; i<remaining_product; ++i) {
_ctranspose<T,J,J>(a_data+i*J*J,out_data+i*J*J);
}
return out;
}
// Conjagate transpose for generic expressions
template<typename Expr, size_t DIM0>
FASTOR_INLINE
Tensor<
typename scalar_type_finder<Expr>::type,
get_tensor_dimension_v<1,typename Expr::result_type>,
get_tensor_dimension_v<0,typename Expr::result_type>>
ctranspose(const AbstractTensor<Expr,DIM0> &src) {
// If we are here Expr is already an expression
using result_type = typename Expr::result_type;
const result_type tmp(src.self());
return ctranspose(tmp);
}
// assignments
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const UnaryCTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
const result_type& tmp = evaluate(src.expr().self());
using T = typename UnaryCTransOp<Expr, OtherDIM>::scalar_type;
static constexpr size_t M = UnaryCTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryCTransOp<Expr, OtherDIM>::N;
_ctranspose<T,M,N>(tmp.data(),dst.self().data());
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const UnaryCTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryCTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryCTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryCTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryCTransOp<Expr, OtherDIM>::N;
_ctranspose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_add(dst.self(),tmp_trans);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const UnaryCTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryCTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryCTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryCTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryCTransOp<Expr, OtherDIM>::N;
_ctranspose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_sub(dst.self(),tmp_trans);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const UnaryCTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryCTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryCTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryCTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryCTransOp<Expr, OtherDIM>::N;
_ctranspose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_mul(dst.self(),tmp_trans);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const UnaryCTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryCTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryCTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryCTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryCTransOp<Expr, OtherDIM>::N;
_ctranspose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_div(dst.self(),tmp_trans);
}
} // end of namespace Fastor
#endif // UNARY_CTRANS_OP_H

View File

@@ -0,0 +1,86 @@
#ifndef UNARY_DET_OP_H
#define UNARY_DET_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/backend/determinant.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
#include <cmath>
namespace Fastor {
// Computing determinant using QR/LU decompositions are in those respective modules
// For tensors
template<DetCompType DetType = DetCompType::Simple, typename T, size_t M,
enable_if_t_<is_less_equal_v_<M,4UL> && DetType==DetCompType::Simple,bool> = false>
FASTOR_INLINE T determinant(const Tensor<T,M,M> &a) {
return _det<T,M,M>(static_cast<const T *>(a.data()));
}
template<DetCompType DetType = DetCompType::Simple, typename T, size_t M,
enable_if_t_<is_greater_v_<M,4UL> && DetType == DetCompType::Simple,bool> = false>
FASTOR_INLINE T determinant(const Tensor<T,M,M> &a) {
// Dispatch to LU
return determinant<DetCompType::LU>(a);
}
// For high order tensors
template<DetCompType DetType = DetCompType::Simple,
typename T, size_t ... Rest, enable_if_t_<sizeof...(Rest)>=3 && DetType == DetCompType::Simple,bool> = false>
FASTOR_INLINE
typename last_matrix_extracter<Tensor<T,Rest...>, typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::type
determinant(const Tensor<T,Rest...> &a) {
using OutTensor = typename last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::type;
constexpr size_t remaining_product = last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::remaining_product;
constexpr size_t I = get_value<sizeof...(Rest)-1,Rest...>::value;
constexpr size_t J = get_value<sizeof...(Rest),Rest...>::value;
static_assert(I==J,"THE LAST TWO DIMENSIONS OF TENSOR MUST BE THE SAME");
OutTensor out;
T *a_data = a.data();
T *out_data = out.data();
for (size_t i=0; i<remaining_product; ++i) {
out_data[i] = _det<T,J,J>(static_cast<const T *>(a_data+i*J*J));
}
return out;
}
// Find determinant of a tensor expression - dispatches to determinant for tensors
template<DetCompType DetType = DetCompType::Simple, typename Derived, size_t DIMS>
FASTOR_INLINE typename Derived::scalar_type determinant(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out = evaluate(src);
return determinant<DetType>(out);
}
template<DetCompType DetType = DetCompType::Simple, typename Derived, size_t DIMS>
FASTOR_INLINE typename Derived::scalar_type det(const AbstractTensor<Derived,DIMS> &_src) {
return determinant<DetType>(_src.self());
}
template<DetCompType DetType = DetCompType::Simple, typename Derived, size_t DIMS>
FASTOR_INLINE typename Derived::scalar_type absdet(const AbstractTensor<Derived,DIMS> &_src) {
return std::abs(determinant<DetType>(_src.self()));
}
template<DetCompType DetType = DetCompType::Simple, typename Derived, size_t DIMS>
FASTOR_INLINE typename Derived::scalar_type logdet(const AbstractTensor<Derived,DIMS> &_src) {
return std::log(std::abs(determinant<DetType>(_src.self())));
}
} // end of namespace Fastor
#endif // UNARY_DET_OP_H

View File

@@ -0,0 +1,731 @@
#ifndef UNARY_INV_OP_H
#define UNARY_INV_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/backend/inverse.h"
#include "Fastor/backend/lut_inverse.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/unary_piv_op.h"
namespace Fastor {
template<typename Expr, size_t DIM0>
struct UnaryInvOp: public AbstractTensor<UnaryInvOp<Expr, DIM0>,DIM0> {
using expr_type = expression_t<Expr>;
using result_type = typename Expr::result_type;
static constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,result_type>;
static constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,result_type>;
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<UnaryInvOp<Expr, DIM0>>::type;
using simd_vector_type = typename Expr::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
FASTOR_INLINE UnaryInvOp(expr_type inexpr) : _expr(inexpr) {
static_assert(M==N, "MATRIX MUST BE SQUARE");
}
constexpr FASTOR_INLINE FASTOR_INDEX size() const {return M*N;}
constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX ) const {return M;}
constexpr FASTOR_INLINE expr_type expr() const {return _expr;}
private:
expr_type _expr;
};
template<typename Expr, size_t DIM0>
FASTOR_INLINE UnaryInvOp<Expr, DIM0>
inv(const AbstractTensor<Expr,DIM0> &src) {
return UnaryInvOp<Expr, DIM0>(src.self());
}
// Upper triangular block matrix inversion
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
namespace internal {
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,4>,bool> = false>
FASTOR_INLINE void ut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
_inverse<T,M>(in.data(),out.data());
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,4> && is_less_equal_v_<M,8>,bool> = false>
FASTOR_INLINE void ut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
constexpr size_t N = 4UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
// Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
ut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,M-N> inv_d;
ut_inverse_dispatcher(d, inv_d);
Tensor<T,N,M-N> b_invd = matmul(b, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = -matmul(inv_a, b_invd);
out(fseq<N,M>(),fseq<0,N>()) = 0;
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,8> && is_less_equal_v_<M,16>,bool> = false>
FASTOR_INLINE void ut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
constexpr size_t N = 8UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
// Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
ut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,M-N> inv_d;
ut_inverse_dispatcher(d, inv_d);
Tensor<T,N,M-N> b_invd = matmul(b, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = -matmul(inv_a, b_invd);
out(fseq<N,M>(),fseq<0,N>()) = 0;
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,16> && is_less_equal_v_<M,32>,bool> = false>
FASTOR_INLINE void ut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 16UL; // start size
constexpr size_t N = (M / 8UL * 8UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
// Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
ut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,M-N> inv_d;
ut_inverse_dispatcher(d, inv_d);
Tensor<T,N,M-N> b_invd = matmul(b, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = -matmul(inv_a, b_invd);
out(fseq<N,M>(),fseq<0,N>()) = 0;
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,32> && is_less_equal_v_<M,64>,bool> = false>
FASTOR_INLINE void ut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 32UL; // start size
constexpr size_t N = (M / 16UL * 16UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
// Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
ut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,M-N> inv_d;
ut_inverse_dispatcher(d, inv_d);
Tensor<T,N,M-N> b_invd = tmatmul<UpLoType::General,UpLoType::Upper>(b, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = -tmatmul<UpLoType::Upper,UpLoType::General>(inv_a, b_invd);
out(fseq<N,M>(),fseq<0,N>()) = 0;
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,64> && is_less_equal_v_<M,128>,bool> = false>
FASTOR_INLINE void ut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 64UL; // start size
constexpr size_t N = (M / 32UL * 32UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
// Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
ut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,M-N> inv_d;
ut_inverse_dispatcher(d, inv_d);
Tensor<T,N,M-N> b_invd = tmatmul<UpLoType::General,UpLoType::Upper>(b, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = -tmatmul<UpLoType::Upper,UpLoType::General>(inv_a, b_invd);
out(fseq<N,M>(),fseq<0,N>()) = 0;
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,128> && is_less_equal_v_<M,256>,bool> = false>
FASTOR_INLINE void ut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 128UL; // start size
constexpr size_t N = (M / 64UL * 64UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
// Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
ut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,M-N> inv_d;
ut_inverse_dispatcher(d, inv_d);
Tensor<T,N,M-N> b_invd = tmatmul<UpLoType::General,UpLoType::Upper>(b, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = -tmatmul<UpLoType::Upper,UpLoType::General>(inv_a, b_invd);
out(fseq<N,M>(),fseq<0,N>()) = 0;
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // internal
// Lower uni-triangular block matrix inversion
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
namespace internal {
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,4>,bool> = false>
FASTOR_INLINE void lut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// This restricts the recursive block to lower uni-triangualar matrices
_lowunitri_inverse<T,M>(in.data(),out.data());
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,4> && is_less_equal_v_<M,8>,bool> = false>
FASTOR_INLINE void lut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
constexpr size_t N = 4UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
// Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
lut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> inv_d;
lut_inverse_dispatcher(d, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = 0;
out(fseq<N,M>(),fseq<0,N>()) = -matmul(inv_d, c_inva);
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,8> && is_less_equal_v_<M,16>,bool> = false>
FASTOR_INLINE void lut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
constexpr size_t N = 8UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
// Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
lut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> inv_d;
lut_inverse_dispatcher(d, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = 0;
out(fseq<N,M>(),fseq<0,N>()) = -matmul(inv_d, c_inva);
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,16> && is_less_equal_v_<M,32>,bool> = false>
FASTOR_INLINE void lut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 16UL; // start size
constexpr size_t N = (M / 8UL * 8UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
// Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
lut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> inv_d;
lut_inverse_dispatcher(d, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = 0;
out(fseq<N,M>(),fseq<0,N>()) = -matmul(inv_d, c_inva);
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,32> && is_less_equal_v_<M,64>,bool> = false>
FASTOR_INLINE void lut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 32UL; // start size
constexpr size_t N = (M / 16UL * 16UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
// Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
lut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = tmatmul<UpLoType::General,UpLoType::Lower>(c, inv_a);
Tensor<T,M-N,M-N> inv_d;
lut_inverse_dispatcher(d, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = 0;
out(fseq<N,M>(),fseq<0,N>()) = -tmatmul<UpLoType::Lower,UpLoType::General>(inv_d, c_inva);
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,64> && is_less_equal_v_<M,128>,bool> = false>
FASTOR_INLINE void lut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 64UL; // start size
constexpr size_t N = (M / 32UL * 32UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
// Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
lut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = tmatmul<UpLoType::General,UpLoType::Lower>(c, inv_a);
Tensor<T,M-N,M-N> inv_d;
lut_inverse_dispatcher(d, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = 0;
out(fseq<N,M>(),fseq<0,N>()) = -tmatmul<UpLoType::Lower,UpLoType::General>(inv_d, c_inva);
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,128> && is_less_equal_v_<M,256>,bool> = false>
FASTOR_INLINE void lut_inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 128UL; // start size
constexpr size_t N = (M / 64UL * 64UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
// Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
lut_inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = tmatmul<UpLoType::General,UpLoType::Lower>(c, inv_a);
Tensor<T,M-N,M-N> inv_d;
lut_inverse_dispatcher(d, inv_d);
out(fseq<0,N>(),fseq<0,N>()) = inv_a;
out(fseq<0,N>(),fseq<N,M>()) = 0;
out(fseq<N,M>(),fseq<0,N>()) = -tmatmul<UpLoType::Lower,UpLoType::General>(inv_d, c_inva);
out(fseq<N,M>(),fseq<N,M>()) = inv_d;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // internal
// General recursive block matrix inversion
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
namespace internal {
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,4>,bool> = false>
FASTOR_INLINE void inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
_inverse<T,M>(in.data(),out.data());
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,4> && is_less_equal_v_<M,8>,bool> = false>
FASTOR_INLINE void inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
constexpr size_t N = 4UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a = inverse(a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> block_bb = inverse(static_cast<Tensor<T,M-N,M-N>>(d - matmul(c_inva, b)));
Tensor<T,N,M-N> inva_b = matmul(inv_a, b);
Tensor<T,M-N,N> bb_c_inva = matmul(block_bb, c_inva);
Tensor<T,N ,N > block_aa = inv_a + matmul(inva_b, bb_c_inva);
Tensor<T,N ,M-N> block_ab = -matmul(inva_b, block_bb);
Tensor<T,M-N,N > block_ba = -bb_c_inva;
out(fseq<0,N>(),fseq<0,N>()) = block_aa;
out(fseq<0,N>(),fseq<N,M>()) = block_ab;
out(fseq<N,M>(),fseq<0,N>()) = block_ba;
out(fseq<N,M>(),fseq<N,M>()) = block_bb;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,8> && is_less_equal_v_<M,16>,bool> = false>
FASTOR_INLINE void inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
constexpr size_t N = 8UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> block_bb;
inverse_dispatcher(static_cast<Tensor<T,M-N,M-N>>(d - matmul(c_inva, b)),block_bb);
Tensor<T,N,M-N> inva_b = matmul(inv_a, b);
Tensor<T,M-N,N> bb_c_inva = matmul(block_bb, c_inva);
Tensor<T,N ,N > block_aa = inv_a + matmul(inva_b, bb_c_inva);
Tensor<T,N ,M-N> block_ab = -matmul(inva_b, block_bb);
Tensor<T,M-N,N > block_ba = -bb_c_inva;
out(fseq<0,N>(),fseq<0,N>()) = block_aa;
out(fseq<0,N>(),fseq<N,M>()) = block_ab;
out(fseq<N,M>(),fseq<0,N>()) = block_ba;
out(fseq<N,M>(),fseq<N,M>()) = block_bb;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,16> && is_less_equal_v_<M,32>,bool> = false>
FASTOR_INLINE void inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 16UL; // start size
constexpr size_t N = (M / 8UL * 8UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> block_bb;
inverse_dispatcher(static_cast<Tensor<T,M-N,M-N>>(d - matmul(c_inva, b)),block_bb);
Tensor<T,N,M-N> inva_b = matmul(inv_a, b);
Tensor<T,M-N,N> bb_c_inva = matmul(block_bb, c_inva);
Tensor<T,N ,N > block_aa = inv_a + matmul(inva_b, bb_c_inva);
Tensor<T,N ,M-N> block_ab = -matmul(inva_b, block_bb);
Tensor<T,M-N,N > block_ba = -bb_c_inva;
out(fseq<0,N>(),fseq<0,N>()) = block_aa;
out(fseq<0,N>(),fseq<N,M>()) = block_ab;
out(fseq<N,M>(),fseq<0,N>()) = block_ba;
out(fseq<N,M>(),fseq<N,M>()) = block_bb;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,32> && is_less_equal_v_<M,64>,bool> = false>
FASTOR_INLINE void inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 32UL; // start size
constexpr size_t N = (M / 16UL * 16UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> block_bb;
inverse_dispatcher(static_cast<Tensor<T,M-N,M-N>>(d - matmul(c_inva, b)),block_bb);
Tensor<T,N,M-N> inva_b = matmul(inv_a, b);
Tensor<T,M-N,N> bb_c_inva = matmul(block_bb, c_inva);
Tensor<T,N ,N > block_aa = inv_a + matmul(inva_b, bb_c_inva);
Tensor<T,N ,M-N> block_ab = -matmul(inva_b, block_bb);
Tensor<T,M-N,N > block_ba = -bb_c_inva;
out(fseq<0,N>(),fseq<0,N>()) = block_aa;
out(fseq<0,N>(),fseq<N,M>()) = block_ab;
out(fseq<N,M>(),fseq<0,N>()) = block_ba;
out(fseq<N,M>(),fseq<N,M>()) = block_bb;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,64> && is_less_equal_v_<M,128>,bool> = false>
FASTOR_INLINE void inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 64UL; // start size
constexpr size_t N = (M / 32UL * 32UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> block_bb;
inverse_dispatcher(static_cast<Tensor<T,M-N,M-N>>(d - matmul(c_inva, b)),block_bb);
Tensor<T,N,M-N> inva_b = matmul(inv_a, b);
Tensor<T,M-N,N> bb_c_inva = matmul(block_bb, c_inva);
Tensor<T,N ,N > block_aa = inv_a + matmul(inva_b, bb_c_inva);
Tensor<T,N ,M-N> block_ab = -matmul(inva_b, block_bb);
Tensor<T,M-N,N > block_ba = -bb_c_inva;
out(fseq<0,N>(),fseq<0,N>()) = block_aa;
out(fseq<0,N>(),fseq<N,M>()) = block_ab;
out(fseq<N,M>(),fseq<0,N>()) = block_ba;
out(fseq<N,M>(),fseq<N,M>()) = block_bb;
}
template<typename T, size_t M, enable_if_t_<is_greater_v_<M,128> && is_less_equal_v_<M,256>,bool> = false>
FASTOR_INLINE void inverse_dispatcher(const Tensor<T,M,M> &in, Tensor<T,M,M>& out) {
// constexpr size_t N = 128UL; // start size
constexpr size_t N = (M / 64UL * 64UL) / 2UL; // start size
Tensor<T,N ,N > a = in(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> b = in(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> c = in(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> d = in(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> inv_a;
inverse_dispatcher(a, inv_a);
Tensor<T,M-N,N> c_inva = matmul(c, inv_a);
Tensor<T,M-N,M-N> block_bb;
inverse_dispatcher(static_cast<Tensor<T,M-N,M-N>>(d - matmul(c_inva, b)),block_bb);
Tensor<T,N,M-N> inva_b = matmul(inv_a, b);
Tensor<T,M-N,N> bb_c_inva = matmul(block_bb, c_inva);
Tensor<T,N ,N > block_aa = inv_a + matmul(inva_b, bb_c_inva);
Tensor<T,N ,M-N> block_ab = -matmul(inva_b, block_bb);
Tensor<T,M-N,N > block_ba = -bb_c_inva;
out(fseq<0,N>(),fseq<0,N>()) = block_aa;
out(fseq<0,N>(),fseq<N,M>()) = block_ab;
out(fseq<N,M>(),fseq<0,N>()) = block_ba;
out(fseq<N,M>(),fseq<N,M>()) = block_bb;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // internal
// Inversion using LU decomposition is in the LU module [unary_lu_op]
// For tensors
// SimpleInv - no pivot
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t M, enable_if_t_<is_less_equal_v_<M,4UL> && InvType == InvCompType::SimpleInv,bool> = false>
FASTOR_INLINE Tensor<T,M,M> inverse(const Tensor<T,M,M> &a) {
Tensor<T,M,M> out;
_inverse<T,M>(a.data(),out.data());
return out;
}
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t M, enable_if_t_<is_greater_v_<M,4UL> && InvType == InvCompType::SimpleInv,bool> = false>
FASTOR_INLINE Tensor<T,M,M> inverse(const Tensor<T,M,M> &in) {
Tensor<T,M,M> out;
internal::inverse_dispatcher(in,out);
return out;
}
// SimpleInv pivot
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t M, enable_if_t_<InvType == InvCompType::SimpleInvPiv,bool> = false>
FASTOR_INLINE Tensor<T,M,M> inverse(const Tensor<T,M,M> &in) {
Tensor<T,M,M> out;
// We need to post multiply - swap columns using row permutation vector
Tensor<size_t,M> P;
pivot_inplace(in,P);
auto A(apply_pivot(in,P));
internal::inverse_dispatcher(A,out);
return reconstruct_colwise(out,P);
// // matrix version
// Tensor<T,M,M> P;
// pivot_inplace(in,P);
// auto A(apply_pivot(in,P));
// internal::inverse_dispatcher(A,out);
// return matmul(out,P);
}
// For high order tensors
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t ... Rest, enable_if_t_<sizeof...(Rest)>=3 && InvType == InvCompType::SimpleInv,bool> = false >
FASTOR_INLINE Tensor<T,Rest...>
inverse(const Tensor<T,Rest...> &a) {
constexpr size_t remaining_product = last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::remaining_product;
constexpr size_t I = get_value<sizeof...(Rest)-1,Rest...>::value;
constexpr size_t J = get_value<sizeof...(Rest),Rest...>::value;
static_assert(I==J,"THE LAST TWO DIMENSIONS OF TENSOR MUST BE THE SAME");
Tensor<T,Rest...> out;
T *a_data = a.data();
T *out_data = out.data();
for (size_t i=0; i<remaining_product; ++i) {
T det = _det<T,J,J>(static_cast<const T *>(a_data+i*J*J));
_inverse<T,J>(a_data+i*J*J,out_data+i*J*J);
}
return out;
}
// Inverse for generic expressions is provided here
template<InvCompType InvType = InvCompType::SimpleInv,
typename Derived, size_t DIM>
FASTOR_INLINE
typename Derived::result_type
inverse(const AbstractTensor<Derived,DIM> &src) {
// If we are here Derived is already an expression
using result_type = typename Derived::result_type;
const result_type tmp(src.self());
return inverse<InvType>(tmp);
}
// Inverse of lower uni-triangular matrices
template<InvCompType InvType = InvCompType::SimpleInv, typename ULType = UpLoType::General,
typename T, size_t M, enable_if_t_<InvType == InvCompType::SimpleInv && is_same_v_<ULType,UpLoType::UniLower>,bool> = false>
FASTOR_INLINE Tensor<T,M,M> tinverse(const Tensor<T,M,M> &in) {
Tensor<T,M,M> out;
internal::lut_inverse_dispatcher(in,out);
return out;
}
// Inverse of lower uni-triangular matrices
template<InvCompType InvType = InvCompType::SimpleInv, typename ULType = UpLoType::General,
typename T, size_t M, enable_if_t_<InvType == InvCompType::SimpleInv && is_same_v_<ULType,UpLoType::Upper>,bool> = false>
FASTOR_INLINE Tensor<T,M,M> tinverse(const Tensor<T,M,M> &in) {
Tensor<T,M,M> out;
internal::ut_inverse_dispatcher(in,out);
return out;
}
// Inverse for generic expressions of lower uni-triangular matrices is provided here
template<InvCompType InvType = InvCompType::SimpleInv, typename ULType = UpLoType::General,
typename Derived, size_t DIM>
FASTOR_INLINE
typename Derived::result_type
tinverse(const AbstractTensor<Derived,DIM> &src) {
// If we are here Derived is already an expression
using result_type = typename Derived::result_type;
const result_type tmp(src.self());
return tinverse<InvType,ULType>(tmp);
}
// assignments
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const UnaryInvOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
const result_type& tmp = evaluate(src.expr().self());
internal::inverse_dispatcher(tmp,dst.self());
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const UnaryInvOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::inverse_dispatcher(tmp,tmp_inv);
trivial_assign_add(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const UnaryInvOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::inverse_dispatcher(tmp,tmp_inv);
trivial_assign_sub(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const UnaryInvOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::inverse_dispatcher(tmp,tmp_inv);
trivial_assign_mul(dst.self(),tmp_inv);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const UnaryInvOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
result_type tmp_inv;
internal::inverse_dispatcher(tmp,tmp_inv);
trivial_assign_div(dst.self(),tmp_inv);
}
} // end of namespace Fastor
#endif // UNARY_INV_OP_H

View File

@@ -0,0 +1,970 @@
#ifndef UNARY_LU_OP_H
#define UNARY_LU_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/backend/inner.h"
#include "Fastor/backend/lufact.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/unary_piv_op.h"
namespace Fastor {
namespace internal {
/* Compile time recursive loop with inner for forward substitution of b/B given the lower unitriangular matrix L.
The following meta functions implements L * y = b for single or multiple right sides
*/
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
template <size_t from, size_t to>
struct forward_subs_impl {
template<typename T, size_t M>
static FASTOR_INLINE void do_single_rhs(const Tensor<T,M,M> &L, const Tensor<T,M> &b, Tensor<T,M> &y) {
y(from) = b(from) - _inner<T,from>(&L.data()[from*M],y.data());
forward_subs_impl<from+1,to>::do_single_rhs(L, b, y);
}
template<typename T, size_t M>
static FASTOR_INLINE void do_single_rhs_pivot(const Tensor<T,M,M> &L, const Tensor<T,M> &b, const Tensor<size_t,M> &p, Tensor<T,M> &y) {
y(from) = b(p(from)) - _inner<T,from>(&L.data()[from*M],y.data());
forward_subs_impl<from+1,to>::do_single_rhs_pivot(L, b, p, y);
}
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void do_multi_rhs(const size_t j, const Tensor<T,M,M> &L, const Tensor<T,M,N> &B, Tensor<T,M> &y, Tensor<T,M,N> &X) {
y(from) = B(from,j) - _inner<T,from>(&L.data()[from*M],y.data());
X(from,j) = y(from);
forward_subs_impl<from+1,to>::do_multi_rhs(j, L, B, y, X);
}
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void do_multi_rhs_pivot(const size_t j, const Tensor<T,M,M> &L, const Tensor<T,M,N> &B,
const Tensor<size_t,M> &p, Tensor<T,M> &y, Tensor<T,M,N> &X) {
y(from) = B(p(from),j) - _inner<T,from>(&L.data()[from*M],y.data());
X(from,j) = y(from);
forward_subs_impl<from+1,to>::do_multi_rhs_pivot(j, L, B, p, y, X);
}
};
template <size_t from>
struct forward_subs_impl<from,from> {
template<typename T, size_t M>
static FASTOR_INLINE void do_single_rhs(const Tensor<T,M,M> &L, const Tensor<T,M> &b, Tensor<T,M> &y) {
y(from) = b(from) - _inner<T,from>(&L.data()[from*M],y.data());
}
template<typename T, size_t M>
static FASTOR_INLINE void do_single_rhs_pivot(const Tensor<T,M,M> &L, const Tensor<T,M> &b, const Tensor<size_t,M> &p, Tensor<T,M> &y) {
y(from) = b(p(from)) - _inner<T,from>(&L.data()[from*M],y.data());
}
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void do_multi_rhs(const size_t j, const Tensor<T,M,M> &L, const Tensor<T,M,N> &B, Tensor<T,M> &y, Tensor<T,M,N> &X) {
y(from) = B(from,j) - _inner<T,from>(&L.data()[from*M],y.data());
X(from,j) = y(from);
}
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void do_multi_rhs_pivot(const size_t j, const Tensor<T,M,M> &L, const Tensor<T,M,N> &B,
const Tensor<size_t,M> &p, Tensor<T,M> &y, Tensor<T,M,N> &X) {
y(from) = B(p(from),j) - _inner<T,from>(&L.data()[from*M],y.data());
X(from,j) = y(from);
}
};
template<typename T, size_t M>
FASTOR_INLINE Tensor<T,M> forward_subs(const Tensor<T,M,M> &L, const Tensor<T,M> &b) {
Tensor<T,M> y(0);
forward_subs_impl<0,M-1>::do_single_rhs(L, b, y);
#if 0
// The run-time loop version
// Solve for L * y = b
for (size_t i=0; i< M; ++i) {
T value = 0;
for (size_t k=0; k<i; ++k) {
value += L(i,k)*y(k);
}
y(i) = b(i) - value;
}
#endif
return y;
}
template<typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> forward_subs(const Tensor<T,M,M> &L, const Tensor<T,M,N> &B) {
// We keep a separate output tensor X from y [y is columns of X]
// to avoid strided access in X for the inner product
Tensor<T,M,N> X;
for (size_t j=0; j < N; ++j) {
Tensor<T,M> y(0);
forward_subs_impl<0,M-1>::do_multi_rhs(j, L, B, y, X);
}
#if 0
// The run-time loop version - X needs to be zeroed out for this version
for (size_t j=0; j < N; ++j) {
Tensor<T,M> y(0);
// Solve for L * y = b
for (size_t i=0; i< M; ++i) {
T value = 0;
for (size_t k=0; k<i; ++k) {
value += L(i,k)*y(k);
}
y(i) = B(i,j) - value;
X(i,j) = y(i);
}
}
#endif
return X;
}
template<typename T, size_t M>
FASTOR_INLINE Tensor<T,M> forward_subs(const Tensor<T,M,M> &L, const Tensor<size_t,M> &p, const Tensor<T,M> &b) {
Tensor<T,M> y(0);
forward_subs_impl<0,M-1>::do_single_rhs_pivot(L, b, p, y);
#if 0
// The run-time loop version
// Solve for L * y = b
for (size_t i=0; i< M; ++i) {
T value = 0;
for (size_t k=0; k<i; ++k) {
value += L(i,k)*y(k);
}
y(i) = b(p(i)) - value;
}
#endif
return y;
}
template<typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> forward_subs(const Tensor<T,M,M> &L, const Tensor<size_t,M> &p, const Tensor<T,M,N> &B) {
// We keep a separate output tensor X from y [y is columns of X]
// to avoid strided access in X for the inner product
Tensor<T,M,N> X;
for (size_t j=0; j < N; ++j) {
Tensor<T,M> y(0);
forward_subs_impl<0,M-1>::do_multi_rhs_pivot(j, L, B, p, y, X);
}
#if 0
// The run-time loop version - X needs to be zeroed out for this version
for (size_t j=0; j < N; ++j) {
Tensor<T,M> y(0);
// Solve for L * y = b
for (size_t i=0; i< M; ++i) {
T value = 0;
for (size_t k=0; k<i; ++k) {
value += L(i,k)*y(k);
}
y(i) = B(p(i),j) - value;
X(i,j) = y(i);
}
}
#endif
return X;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
/* Compile time recursive loop with inner for backward substitution of y/Y given the upper triangular matrix U.
The following meta functions implements U * x = y for single or multiple right sides
*/
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
template <int from, int to>
struct backward_subs_impl {
template<typename T, size_t M>
static FASTOR_INLINE void do_single_rhs(const Tensor<T,M,M> &U, const Tensor<T,M> &y, Tensor<T,M> &x) {
constexpr int idx = (int)M - from;
const T value = _inner<T,idx>(&U.data()[from*M+from],&x.data()[from]);
x(from) = ( y(from) - value) / U(from, from);
backward_subs_impl<from-1,to>::do_single_rhs(U, y, x);
}
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void do_multi_rhs(const size_t j, const Tensor<T,M,M> &U, const Tensor<T,M,N> &Y, Tensor<T,M> &x, Tensor<T,M,N> &X) {
constexpr int idx = (int)M - from;
const T value = _inner<T,idx>(&U.data()[from*M+from],&x.data()[from]);
x(from) = ( Y(from,j) - value ) / U(from, from);
X(from,j) = x(from);
backward_subs_impl<from-1,to>::do_multi_rhs(j, U, Y, x, X);
}
};
template <>
struct backward_subs_impl<0,0> {
template<typename T, size_t M>
static FASTOR_INLINE void do_single_rhs(const Tensor<T,M,M> &U, const Tensor<T,M> &y, Tensor<T,M> &x) {
constexpr int idx = (int)M;
const T value = _inner<T,idx>(&U.data()[0*M+0],&x.data()[0]);
x(0) = ( y(0) - value) / U(0, 0);
}
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void do_multi_rhs(const size_t j, const Tensor<T,M,M> &U, const Tensor<T,M,N> &Y, Tensor<T,M> &x, Tensor<T,M,N> &X) {
constexpr int idx = (int)M;
const T value = _inner<T,idx>(&U.data()[0*M+0],&x.data()[0]);
x(0) = ( Y(0,j) - value ) / U(0, 0);
X(0,j) = x(0);
}
};
template<typename T, size_t M>
FASTOR_INLINE Tensor<T,M> backward_subs(const Tensor<T,M,M> &U, const Tensor<T,M> &y) {
// We keep a separate output tensor X from x [x is columns of X]
// to avoid strided access in X for the inner product
Tensor<T,M> x(0);
backward_subs_impl<int(M)-1,0>::do_single_rhs(U, y, x);
#if 0
// The run-time loop version
// Solve for of U * x = y
for (int i= int(M) - 1; i>=0; --i) {
T value = 0;
for (int k=i; k<int(M); ++k) {
value += U(i,k)*x(k);
}
x(i) = (y(i) - value) / U(i, i);
}
#endif
return x;
}
template<typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> backward_subs(const Tensor<T,M,M> &U, const Tensor<T,M,N> &Y) {
// We keep a separate output tensor X from x [x is columns of X]
// to avoid strided access in X for the inner product
Tensor<T,M,N> X;
for (size_t j=0; j < N; ++j) {
Tensor<T,M> x(0);
backward_subs_impl<int(M)-1,0>::do_multi_rhs(j, U, Y, x, X);
}
#if 0
// The run-time loop version - X needs to be zeroed out for this version
Tensor<T,M,N> X(0);
for (size_t j=0; j < 1; ++j) {
// Solve for of U * x = y
for (int i= int(M) - 1; i>=0; --i) {
T value = 0;
for (int k=i; k<int(M); ++k) {
value += U(i,k)*X(k,j);
}
X(i,j) = (Y(i,j) - value) / U(i, i);
}
}
#endif
return X;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
/* Simple LU factorisation without pivoting */
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,8>,bool> = false>
FASTOR_INLINE void lu_simple_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
_lufact<T,M>(A.data(),L.data(),U.data());
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,8>,bool> = false>
FASTOR_INLINE void lu_simple_dispatcher(const Tensor<T,M,M>& A1, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
L.fill(0);
U.fill(0);
for (size_t j = 0; j < M; ++j) {
L(j, j) = 1;
for (size_t i = 0; i <= j; ++i) {
T value = A1(i, j);
for (size_t k = 0; k < i; ++k) {
value -= L(i, k) * U(k, j);
}
U(i, j) = value;
}
for (size_t i = j; i < M; ++i) {
T value = A1(i, j);
for (size_t k = 0; k < j; ++k) {
value -= L(i, k) * U(k, j);
}
value /= U(j, j);
L(i, j) = value;
}
}
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// Recursive non-modifying LU using matmul/outer product
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
/* This in essence implements the following loop but with static views
as dynamic views cannot be dispatched to matmul or a tensor cannot be
constructed to be sent to matmul
for(size_t j=0; j<M-1; ++j) {
L(seq(j+1,M),j) /= L(j,j);
L(seq(j+1,M),seq(j+1,M)) -= L(seq(j+1,M),j) % L(j,seq(j+1,M));
}
This is a non-modifying version that fills L and U directly and avoids
the need for extracting L and U later
The pre-requisite is that L should be Identity and U be a copy of A before
the recursive routine starts
*/
template<size_t from, size_t to>
struct recursive_lu_impl {
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void Do(Tensor<T,M,N> &L, Tensor<T,M,N> &U) {
L(fseq<from+1,M>(),fix<from>) = U(fseq<from+1,M>(),fix<from>) / U.data()[from*N+from];
U(fseq<from+1,M>(),fix<from>) = 0;
U(fseq<from+1,M>(),fseq<from+1,M>()) -= matmul(L(fseq<from+1,M>(),fix<from>), U(fix<from>,fseq<from+1,M>()));
recursive_lu_impl<from+1,to>::Do(L, U);
}
};
template<size_t from>
struct recursive_lu_impl<from,from> {
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void Do(Tensor<T,M,N> &L, Tensor<T,M,N> &U) {
L(fseq<from+1,M>(),fix<from>) = U(fseq<from+1,M>(),fix<from>) / U.data()[from*N+from];
U(fseq<from+1,M>(),fix<from>) = 0;
U(fseq<from+1,M>(),fseq<from+1,M>()) -= matmul(L(fseq<from+1,M>(),fix<from>), U(fix<from>,fseq<from+1,M>()));
}
};
template <typename T, size_t M, enable_if_t_<is_equal_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_lu_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
L(0,0) = 1; U(0,0) = A(0,0);
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_lu_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
// Requires M >=2
U = A;
L.eye2();
recursive_lu_impl<0,M-2>::Do(L, U);
}
#if 0
// Recursive in-place LU using matmul/outer product
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
/* This in essence implements the following loop but with static views
as dynamic views cannot be dispatched to matmul or a tensor cannot be
constructed to be sent to matmul
for(size_t j=0; j<M-1; ++j) {
L(seq(j+1,M),j) /= L(j,j);
L(seq(j+1,M),seq(j+1,M)) -= L(seq(j+1,M),j) % L(j,seq(j+1,M));
}
This is a self-modifying [in-place] version - if instead of a copy of
(LU in this case) we pass the matrix itself it will decompose it in to
an LU. Extracting L and U after this recursive decomposition is done
almost beats the purpose performance wise
*/
template<size_t from, size_t to>
struct recursive_lu_impl_inplace {
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void Do(Tensor<T,M,N> &LU) {
LU(fseq<from+1,M>(),fix<from>) /= LU.data()[from*N+from];
LU(fseq<from+1,M>(),fseq<from+1,M>()) -= matmul(LU(fseq<from+1,M>(),fix<from>), LU(fix<from>,fseq<from+1,M>()));
recursive_lu_impl_inplace<from+1,to>::Do(LU);
}
};
template<size_t from>
struct recursive_lu_impl_inplace<from,from> {
template<typename T, size_t M, size_t N>
static FASTOR_INLINE void Do(Tensor<T,M,N> &LU) {
LU(fseq<from+1,M>(),fix<from>) /= LU.data()[from*N+from];
LU(fseq<from+1,M>(),fseq<from+1,M>()) -= matmul(LU(fseq<from+1,M>(),fix<from>), LU(fix<from>,fseq<from+1,M>()));
}
};
template <typename T, size_t M, enable_if_t_<is_equal_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_inplace_lu_dispatcher(Tensor<T,M,M>& A) {
return;
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_inplace_lu_dispatcher(Tensor<T,M,M>& A) {
// Requires M >=2
recursive_lu_impl_inplace<0,M-2>::Do(A);
}
template <typename T, size_t M, enable_if_t_<is_equal_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_inplace_lu_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& LU) {
LU(0,0) = A(0,0);
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_inplace_lu_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& LU) {
// Requires M >=2
LU =A;
recursive_lu_impl_inplace<0,M-2>::Do(LU);
}
template <typename T, size_t M, enable_if_t_<is_equal_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_inplace_lu_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
L(0,0) = 1; U(0,0) = A(0,0);
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,1>,bool> = false>
FASTOR_INLINE void recursive_inplace_lu_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
// Requires M >=2
Tensor<T,M,M> LU(A);
recursive_lu_impl_inplace<0,M-2>::Do(LU);
// Extracting L and U after this recursive decomposition is done
// almost beats the purpose performance wise
for (size_t i=0; i<M; ++i) {
L(i,i) = 1;
}
for (size_t i=0; i<M; ++i) {
for (size_t j=0; j<i; ++j) {
L(i,j) = LU(i,j);
}
}
for (size_t i=0; i<M; ++i) {
for (size_t j=i; j<M; ++j) {
U(i,j) = LU(i,j);
}
}
}
#endif
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
/* Block LU factorisation without pivoting */
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,8>,bool> = false>
FASTOR_INLINE void lu_block_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
_lufact<T,M>(A.data(),L.data(),U.data());
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,8> && is_less_equal_v_<M,32>,bool> = false>
FASTOR_INLINE void lu_block_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
recursive_lu_dispatcher(A, L, U);
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,32> && is_less_equal_v_<M,64>,bool> = false>
FASTOR_INLINE void lu_block_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
// We will compute LU decomposition block-wise assuming that A11 and A22 are invertible
//
// [A11 A12] [L11 0] [U11 U12]
// [A21 A22] [L21 L22] [0 U22]
//
// This results in
//
// A11 = L11 * U11
// A12 = L11 * U12
// A21 = L21 * U11
// A22 = L21 * U12 - L22 * U22
//
// Hence we need to do LU factorisation once for A11 and once for A22
// This is to avoid odd sizes for instance for size 35 we would
// want to do 35 = 16 + 19 rather than 35 = 32 + 3 if the start size was 32
constexpr size_t N = (M / 8UL * 8UL) / 2UL; // start size
Tensor<T,N ,N > A11 = A(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> A12 = A(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> A21 = A(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> A22 = A(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> L11(0), U11(0);
lu_block_dispatcher(A11, L11, U11);
// Solve for U12 = {L11}^(-1)*A12
Tensor<T,N ,M-N> U12 = tmatmul<UpLoType::Lower,UpLoType::General>(tinverse<InvCompType::SimpleInv, UpLoType::UniLower>(L11),A12);
// Solve for L21 = A21*{U11}^(-1)
Tensor<T,M-N, N> L21 = tmatmul<UpLoType::General,UpLoType::Upper>(A21,tinverse<InvCompType::SimpleInv, UpLoType::Upper>(U11));
Tensor<T,M-N,M-N> S = A22 - matmul(L21,U12);
Tensor<T,M-N,M-N> L22(0), U22(0);
lu_block_dispatcher(S, L22, U22);
L(fseq<0,N>(),fseq<0,N>()) = L11;
// L(fseq<0,N>(),fseq<N,M>()) = 0;
L(fseq<N,M>(),fseq<0,N>()) = L21;
L(fseq<N,M>(),fseq<N,M>()) = L22;
U(fseq<0,N>(),fseq<0,N>()) = U11;
U(fseq<0,N>(),fseq<N,M>()) = U12;
// U(fseq<N,M>(),fseq<0,N>()) = 0;
U(fseq<N,M>(),fseq<N,M>()) = U22;
}
// Conditional dispatch
namespace useless {
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,0> && is_less_equal_v_<M,64>,bool> = false>
FASTOR_INLINE void lu_block_simple_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
lu_block_dispatcher(A, L, U);
return;
}
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,64>,bool> = false>
FASTOR_INLINE void lu_block_simple_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
// lu_simple_dispatcher(A, L, U);
recursive_lu_dispatcher(A, L, U);
return;
}
} // useless
/* For sizes greater than 64 we tile differently to avoid too many recursions
*/
template <typename T, size_t M, enable_if_t_<is_greater_v_<M,64>,bool> = false>
FASTOR_INLINE void lu_block_dispatcher(const Tensor<T,M,M>& A, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
// We will compute LU decomposition block-wise assuming that A11 and A22 are invertible
//
// [A11 A12] [L11 0] [U11 U12]
// [A21 A22] [L21 L22] [0 U22]
//
// This results in
//
// A11 = L11 * U11
// A12 = L11 * U12
// A21 = L21 * U11
// A22 = L21 * U12 - L22 * U22
//
// Hence we need to do LU factorisation once for A11 and once for A22
// This is to avoid odd sizes for instance for size 65 we would
// want to do 65 = 32 + 33 rather than 65 = 64 + 1 if the start size was 64
constexpr size_t N = (M / 16UL * 16UL) / 2UL; // start size
Tensor<T,N ,N > A11 = A(fseq<0,N>(),fseq<0,N>());
Tensor<T,N ,M-N> A12 = A(fseq<0,N>(),fseq<N,M>());
Tensor<T,M-N, N> A21 = A(fseq<N,M>(),fseq<0,N>());
Tensor<T,M-N,M-N> A22 = A(fseq<N,M>(),fseq<N,M>());
Tensor<T,N,N> L11(0), U11(0);
useless::lu_block_simple_dispatcher(A11, L11, U11);
// Solve for U12 = {L11}^(-1)*A12
Tensor<T,N ,M-N> U12 = tmatmul<UpLoType::Lower,UpLoType::General>(tinverse<InvCompType::SimpleInv, UpLoType::UniLower>(L11),A12);
// Ideally use forward_subs but its iterative nature makes it less efficient than tmatmul
// Tensor<T,N ,M-N> U12 = forward_subs(L11,A12);
// Solve for L21 = A21*{U11}^(-1)
Tensor<T,M-N, N> L21 = tmatmul<UpLoType::General,UpLoType::Upper>(A21,tinverse<InvCompType::SimpleInv, UpLoType::Upper>(U11));
// Not quite performant as we can't avoid the matmul here
// Tensor<T,N ,N > I; I.eye2();
// Tensor<T,M-N, N> L21 = matmul(A21, backward_subs(U11, I));
Tensor<T,M-N,M-N> S = A22 - matmul(L21,U12);
Tensor<T,M-N,M-N> L22(0), U22(0);
useless::lu_block_simple_dispatcher(S, L22, U22);
L(fseq<0,N>(),fseq<0,N>()) = L11;
// L(fseq<0,N>(),fseq<N,M>()) = 0;
L(fseq<N,M>(),fseq<0,N>()) = L21;
L(fseq<N,M>(),fseq<N,M>()) = L22;
U(fseq<0,N>(),fseq<0,N>()) = U11;
U(fseq<0,N>(),fseq<N,M>()) = U12;
// U(fseq<N,M>(),fseq<0,N>()) = 0;
U(fseq<N,M>(),fseq<N,M>()) = U22;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // internal
/* Block LU factorisation overloads */
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// BlockLU - no pivot
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<is_tensor_v<Expr> && LUType == LUCompType::BlockLU,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
L.fill(0);
U.fill(0);
internal::lu_block_dispatcher(src.self(),L,U);
}
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<!is_tensor_v<Expr> && LUType == LUCompType::BlockLU,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
L.fill(0);
U.fill(0);
typename Expr::result_type tmp(src.self());
internal::lu_block_dispatcher(tmp,L,U);
}
// BlockLU - vector pivot
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<is_tensor_v<Expr> && LUType == LUCompType::BlockLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<size_t,M>& P) {
L.fill(0);
U.fill(0);
pivot_inplace(src.self(),P);
auto A(apply_pivot(src.self(),P));
internal::lu_block_dispatcher(A,L,U);
}
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<!is_tensor_v<Expr> && LUType == LUCompType::BlockLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<size_t,M>& P) {
L.fill(0);
U.fill(0);
typename Expr::result_type A(src.self());
pivot_inplace(A,P);
// Modify A as A is a temporary anyway
apply_pivot_inplace(A,P);
internal::lu_block_dispatcher(A,L,U);
}
// BlockLU - matrix pivot
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<is_tensor_v<Expr> && LUType == LUCompType::BlockLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<T,M,M>& P) {
L.fill(0);
U.fill(0);
pivot_inplace(src.self(),P);
auto A(apply_pivot(src.self(),P));
internal::lu_block_dispatcher(A,L,U);
}
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<!is_tensor_v<Expr> && LUType == LUCompType::BlockLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<T,M,M>& P) {
L.fill(0);
U.fill(0);
typename Expr::result_type A(src.self());
pivot_inplace(A,P);
// Modify A as A is a temporary anyway
apply_pivot_inplace(A,P);
internal::lu_block_dispatcher(A,L,U);
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
/* Simple LU factorisation overloads */
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// SimpleLU - no pivot
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<is_tensor_v<Expr> && LUType == LUCompType::SimpleLU,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
internal::lu_simple_dispatcher(src.self(),L,U);
}
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<!is_tensor_v<Expr> && LUType == LUCompType::SimpleLU,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U) {
typename Expr::result_type tmp(src.self());
internal::lu_simple_dispatcher(tmp,L,U);
}
// SimpleLU - vector pivot
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<is_tensor_v<Expr> && LUType == LUCompType::SimpleLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<size_t,M>& P) {
pivot_inplace(src.self(),P);
auto A(apply_pivot(src.self(),P));
internal::lu_simple_dispatcher(A,L,U);
}
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<!is_tensor_v<Expr> && LUType == LUCompType::SimpleLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<size_t,M>& P) {
typename Expr::result_type A(src.self());
pivot_inplace(A,P);
// Modify A as A is a temporary anyway
apply_pivot_inplace(A,P);
internal::lu_simple_dispatcher(A,L,U);
}
// SimpleLU - matrix pivot
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<is_tensor_v<Expr> && LUType == LUCompType::SimpleLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<T,M,M>& P) {
pivot_inplace(src.self(),P);
auto A(apply_pivot(src.self(),P));
internal::lu_simple_dispatcher(A,L,U);
}
template<LUCompType LUType = LUCompType::BlockLU, typename Expr, size_t DIM0, typename T, size_t M,
enable_if_t_<!is_tensor_v<Expr> && LUType == LUCompType::SimpleLUPiv,bool> = false>
FASTOR_INLINE
void
lu(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,M>& L, Tensor<T,M,M>& U, Tensor<T,M,M>& P) {
typename Expr::result_type A(src.self());
pivot_inplace(A,P);
// Modify A as A is a temporary anyway
apply_pivot_inplace(A,P);
internal::lu_simple_dispatcher(A,L,U);
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// Inversion using LU
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
namespace internal {
template<typename T, size_t M>
FASTOR_INLINE Tensor<T,M,M> get_lu_inverse(const Tensor<T,M,M> &L, const Tensor<T,M,M> &U) {
// We will solve for multiple RHS [B = I]
// Loop over columns of B = I
Tensor<T,M,M> I; I.eye2();
Tensor<T,M,M> Y = forward_subs(L, I);
Tensor<T,M,M> X = backward_subs(U, Y);
return X;
}
template<typename T, size_t M>
FASTOR_INLINE Tensor<T,M,M> get_lu_inverse(Tensor<T,M,M> &L, const Tensor<T,M,M> &U, const Tensor<size_t,M> &p) {
// We will solve for multiple RHS [B = I]
// Loop over columns of B = I
Tensor<T,M,M> I; I.eye2();
Tensor<T,M,M> Y = forward_subs(L, p, I);
Tensor<T,M,M> X = backward_subs(U, Y);
return X;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // internal
// SimpleLU
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t M, enable_if_t_<InvType == InvCompType::SimpleLU,bool> = false>
FASTOR_INLINE Tensor<T,M,M> inverse(const Tensor<T,M,M> &A) {
Tensor<T,M,M> L, U;
lu<LUCompType::SimpleLU>(A, L, U);
return internal::get_lu_inverse(L, U);
}
// BlockLU
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t M, enable_if_t_<InvType == InvCompType::BlockLU,bool> = false>
FASTOR_INLINE Tensor<T,M,M> inverse(const Tensor<T,M,M> &A) {
Tensor<T,M,M> L, U;
lu<LUCompType::BlockLU>(A, L, U);
return internal::get_lu_inverse(L, U);
}
// SimpleLUPiv
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t M, enable_if_t_<InvType == InvCompType::SimpleLUPiv,bool> = false>
FASTOR_INLINE Tensor<T,M,M> inverse(const Tensor<T,M,M> &A) {
Tensor<T,M,M> L, U;
Tensor<size_t,M> p;
lu<LUCompType::SimpleLUPiv>(A, L, U, p);
return internal::get_lu_inverse(L, U, p);
}
// BlockLUPiv
template<InvCompType InvType = InvCompType::SimpleInv,
typename T, size_t M, enable_if_t_<InvType == InvCompType::BlockLUPiv,bool> = false>
FASTOR_INLINE Tensor<T,M,M> inverse(const Tensor<T,M,M> &A) {
Tensor<T,M,M> L, U;
Tensor<size_t,M> p;
lu<LUCompType::BlockLUPiv>(A, L, U, p);
return internal::get_lu_inverse(L, U, p);
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// Solving linear system of equations using LU
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
namespace internal {
template<typename T, size_t M>
FASTOR_INLINE Tensor<T,M> get_lu_solve(const Tensor<T,M,M> &L, const Tensor<T,M,M> &U, const Tensor<T,M> &b) {
Tensor<T,M> y = forward_subs(L, b);
Tensor<T,M> x = backward_subs(U, y);
return x;
}
template<typename T, size_t M>
FASTOR_INLINE Tensor<T,M> get_lu_solve(Tensor<T,M,M> &L, const Tensor<T,M,M> &U, const Tensor<size_t,M> &p, const Tensor<T,M> &b) {
Tensor<T,M> y = forward_subs(L, p, b);
Tensor<T,M> x = backward_subs(U, y);
return x;
}
// Multiple RHS
template<typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> get_lu_solve(const Tensor<T,M,M> &L, const Tensor<T,M,M> &U, const Tensor<T,M,N> &B) {
Tensor<T,M,N> Y = forward_subs(L, B);
Tensor<T,M,N> X = backward_subs(U, Y);
return X;
}
template<typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> get_lu_solve(const Tensor<T,M,M> &L, const Tensor<T,M,M> &U, const Tensor<size_t,M> &p, const Tensor<T,M,N> &B) {
Tensor<T,M,N> Y = forward_subs(L, p, B);
Tensor<T,M,N> X = backward_subs(U, Y);
return X;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // internal
// Single RHS
// SimpleLU - no pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M,
enable_if_t_< SType == SolveCompType::SimpleLU, bool> = false>
FASTOR_INLINE Tensor<T,M> solve(const Tensor<T,M,M> &A, const Tensor<T,M> &b) {
Tensor<T,M,M> L, U;
lu<LUCompType::SimpleLU>(A, L, U);
return internal::get_lu_solve(L, U, b);
}
// SimpleLU - pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M,
enable_if_t_< SType == SolveCompType::SimpleLUPiv, bool> = false>
FASTOR_INLINE Tensor<T,M> solve(const Tensor<T,M,M> &A, const Tensor<T,M> &b) {
Tensor<T,M,M> L, U;
Tensor<size_t,M> p;
lu<LUCompType::SimpleLUPiv>(A, L, U, p);
return internal::get_lu_solve(L, U, p, b);
}
// BlockLU - no pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M,
enable_if_t_< SType == SolveCompType::BlockLU, bool> = false>
FASTOR_INLINE Tensor<T,M> solve(const Tensor<T,M,M> &A, const Tensor<T,M> &b) {
Tensor<T,M,M> L, U;
lu<LUCompType::BlockLU>(A, L, U);
return internal::get_lu_solve(L, U, b);
}
// BlockLU - pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M,
enable_if_t_< SType == SolveCompType::BlockLUPiv, bool> = false>
FASTOR_INLINE Tensor<T,M> solve(const Tensor<T,M,M> &A, const Tensor<T,M> &b) {
Tensor<T,M,M> L, U;
Tensor<size_t,M> p;
lu<LUCompType::BlockLUPiv>(A, L, U, p);
return internal::get_lu_solve(L, U, p, b);
}
// Multiple RHS
// SimpleLU - no pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M, size_t N,
enable_if_t_< SType == SolveCompType::SimpleLU, bool> = false>
FASTOR_INLINE Tensor<T,M,N> solve(const Tensor<T,M,M> &A, const Tensor<T,M,N> &B) {
Tensor<T,M,M> L, U;
lu<LUCompType::SimpleLU>(A, L, U);
return internal::get_lu_solve(L, U, B);
}
// SimpleLU - pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M, size_t N,
enable_if_t_< SType == SolveCompType::SimpleLUPiv, bool> = false>
FASTOR_INLINE Tensor<T,M,N> solve(const Tensor<T,M,M> &A, const Tensor<T,M,N> &B) {
Tensor<T,M,M> L, U;
Tensor<size_t,M> p;
lu<LUCompType::SimpleLUPiv>(A, L, U, p);
return internal::get_lu_solve(L, U, p, B);
}
// SimpleLU - no pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M, size_t N,
enable_if_t_< SType == SolveCompType::BlockLU, bool> = false>
FASTOR_INLINE Tensor<T,M,N> solve(const Tensor<T,M,M> &A, const Tensor<T,M,N> &B) {
Tensor<T,M,M> L, U;
lu<LUCompType::BlockLU>(A, L, U);
return internal::get_lu_solve(L, U, B);
}
// SimpleLU - pivot
template<SolveCompType SType = SolveCompType::SimpleInv, typename T, size_t M, size_t N,
enable_if_t_< SType == SolveCompType::BlockLUPiv, bool> = false>
FASTOR_INLINE Tensor<T,M,N> solve(const Tensor<T,M,M> &A, const Tensor<T,M,N> &B) {
Tensor<T,M,M> L, U;
Tensor<size_t,M> p;
lu<LUCompType::BlockLUPiv>(A, L, U, p);
return internal::get_lu_solve(L, U, p, B);
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// Computing determinant using LU
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
template<DetCompType DetType = DetCompType::Simple, typename T, size_t M,
enable_if_t_<DetType == DetCompType::LU,bool> = false>
FASTOR_INLINE T determinant(const Tensor<T,M,M> &A) {
int nswaps = internal::count_swaps(A) % 2UL == 0 ? 1 : -1;
Tensor<T,M,M> L, U;
Tensor<size_t,M> p;
lu<LUCompType::BlockLUPiv>(A, L, U, p);
return product(diag(U)) * nswaps;
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // end of namespace Fastor
#endif // UNARY_LU_OP_H

View File

@@ -0,0 +1,106 @@
#ifndef UNARY_NORM_OP_H
#define UNARY_NORM_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/backend/norm.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
namespace Fastor {
// For tensors
template<typename T, enable_if_t_<is_arithmetic_v_<T>,bool> = false>
FASTOR_INLINE T norm(const T &a) {
return std::abs(a);
}
template<typename T, size_t ... Rest>
FASTOR_INLINE T norm(const Tensor<T,Rest...> &a) {
if (sizeof...(Rest) == 0)
return *a.data();
return _norm<T,pack_prod<Rest...>::value>(a.data());
}
// For generic expressions
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type norm(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using T = typename Derived::scalar_type;
using V = choose_best_simd_vector_t<T>;
T _scal=0;
#ifdef FASTOR_AVX512_IMPL
V omm0, omm1, omm2, omm3, omm4, omm5, omm6, omm7;
#else
V omm0, omm1, omm2, omm3;
#endif
FASTOR_INDEX i = 0;
// With AVX utilises all the 16 registers but hurts the performance
// due to spill if eval has created temporary registers so only
// activated for AVX512
#ifdef FASTOR_AVX512_IMPL
for (; i < ROUND_DOWN(src.size(),8*V::Size); i+=8*V::Size) {
const auto smm0 = src.template eval<T>(i);
const auto smm1 = src.template eval<T>(i+V::Size);
const auto smm2 = src.template eval<T>(i+2*V::Size);
const auto smm3 = src.template eval<T>(i+3*V::Size);
const auto smm4 = src.template eval<T>(i+4*V::Size);
const auto smm5 = src.template eval<T>(i+5*V::Size);
const auto smm6 = src.template eval<T>(i+6*V::Size);
const auto smm7 = src.template eval<T>(i+7*V::Size);
omm0 = fmadd(smm0,smm0,omm0);
omm1 = fmadd(smm1,smm1,omm1);
omm2 = fmadd(smm2,smm2,omm2);
omm3 = fmadd(smm3,smm3,omm3);
omm4 = fmadd(smm4,smm4,omm4);
omm5 = fmadd(smm5,smm5,omm5);
omm6 = fmadd(smm6,smm6,omm6);
omm7 = fmadd(smm7,smm7,omm7);
}
#endif
for (; i < ROUND_DOWN(src.size(),4*V::Size); i+=4*V::Size) {
const auto smm0 = src.template eval<T>(i);
const auto smm1 = src.template eval<T>(i+V::Size);
const auto smm2 = src.template eval<T>(i+2*V::Size);
const auto smm3 = src.template eval<T>(i+3*V::Size);
omm0 = fmadd(smm0,smm0,omm0);
omm1 = fmadd(smm1,smm1,omm1);
omm2 = fmadd(smm2,smm2,omm2);
omm3 = fmadd(smm3,smm3,omm3);
}
for (; i < ROUND_DOWN(src.size(),2*V::Size); i+=2*V::Size) {
const auto smm0 = src.template eval<T>(i);
const auto smm1 = src.template eval<T>(i+V::Size);
omm0 = fmadd(smm0,smm0,omm0);
omm1 = fmadd(smm1,smm1,omm1);
}
for (; i < ROUND_DOWN(src.size(),V::Size); i+=V::Size) {
const auto smm0 = src.template eval<T>(i);
omm0 = fmadd(smm0,smm0,omm0);
}
for (; i < src.size(); ++i) {
const auto smm0 = src.template eval_s<T>(i);
_scal += smm0*smm0;
}
#ifdef FASTOR_AVX512_IMPL
return sqrts( (omm0 + omm1 + omm2 + omm3 + omm4 + omm5 + omm6 + omm7).sum() + _scal);
#else
return sqrts( (omm0 + omm1 + omm2 + omm3).sum() + _scal);
#endif
}
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type norm(const AbstractTensor<Derived,DIMS> &_src) {
const Derived &src = _src.self();
using result_type = typename Derived::result_type;
const result_type out(src);
return norm(out);
}
} // end of namespace Fastor
#endif // UNARY_NORM_OP_H

View File

@@ -0,0 +1,409 @@
#ifndef UNARY_PIV_OP_H
#define UNARY_PIV_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include <algorithm>
namespace Fastor {
namespace internal {
template<typename T, size_t M, size_t N>
FASTOR_INLINE size_t count_swaps(const Tensor<T,M,N>& A) {
size_t count = 0;
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A(i, j)) > std::abs(A(max_index, j)))
max_index = i;
}
if (j != max_index)
count++;
}
return count;
}
}
template<PivType PType = PivType::V, typename T, size_t M, size_t N,
enable_if_t_<PType == PivType::M, bool> = false>
FASTOR_INLINE Tensor<T,M,N> pivot(const Tensor<T,M,N>& A) {
Tensor<size_t,M> perm;
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A(i, j)) > std::abs(A(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
Tensor<T,M,N> P(0);
for (size_t i = 0; i < M; ++i)
P(i, perm(i)) = 1;
return P;
}
template<PivType PType = PivType::V, typename T, size_t M, size_t N,
enable_if_t_<PType == PivType::V, bool> = false>
FASTOR_INLINE Tensor<size_t,M> pivot(const Tensor<T,M,N>& A) {
Tensor<size_t,M> perm;
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A(i, j)) > std::abs(A(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
return perm;
}
// For generic expressions
template<PivType PType = PivType::V, typename Derived, size_t DIM,
enable_if_t_<PType == PivType::M && requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
Tensor<typename Derived::scalar_type,
get_tensor_dimension_v<0,typename Derived::result_type>,
get_tensor_dimension_v<1,typename Derived::result_type>
>
pivot(const AbstractTensor<Derived,DIM>& src) {
typename Derived::result_type tmp(src.self());
return pivot<PType>(tmp);
}
template<PivType PType = PivType::M, typename Derived, size_t DIM,
enable_if_t_<PType == PivType::M && !requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
Tensor<typename Derived::scalar_type,
get_tensor_dimension_v<0,typename Derived::result_type>,
get_tensor_dimension_v<1,typename Derived::result_type>
>
pivot(const AbstractTensor<Derived,DIM>& src) {
static_assert(DIM==2, "TENSOR MUST BE SQUARE FOR PIVOT COMPUTATION");
using T = typename Derived::scalar_type;
using result_type = typename Derived::result_type;
constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,result_type>;
constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,result_type>;
const Derived &A = src.self();
Tensor<size_t,M> perm;
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A.template eval_s<T>(i, j)) > std::abs(A.template eval_s<T>(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
Tensor<T,M,N> P(0);
for (size_t i = 0; i < M; ++i)
P(i, perm(i)) = 1;
return P;
}
template<PivType PType = PivType::V, typename Derived, size_t DIM,
enable_if_t_<PType == PivType::V && requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
Tensor<size_t,
get_tensor_dimension_v<0,typename Derived::result_type>
>
pivot(const AbstractTensor<Derived,DIM>& src) {
typename Derived::result_type tmp(src.self());
return pivot<PType>(tmp);
}
template<PivType PType = PivType::M, typename Derived, size_t DIM,
enable_if_t_<PType == PivType::V && !requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
Tensor<size_t,
get_tensor_dimension_v<0,typename Derived::result_type>
>
pivot(const AbstractTensor<Derived,DIM>& src) {
static_assert(DIM==2, "TENSOR MUST BE SQUARE FOR PIVOT COMPUTATION");
using T = typename Derived::scalar_type;
using result_type = typename Derived::result_type;
constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,result_type>;
constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,result_type>;
const Derived &A = src.self();
Tensor<size_t,M> perm;
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A.template eval_s<T>(i, j)) > std::abs(A.template eval_s<T>(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
return perm;
}
/* In place versions - Given an evaluated pivot tensor populates it
*/
template<typename T, size_t M, size_t N>
FASTOR_INLINE void pivot_inplace(const Tensor<T,M,N>& A, Tensor<size_t,M>& perm) {
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A(i, j)) > std::abs(A(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
}
template<typename T, size_t M, size_t N>
FASTOR_INLINE void pivot_inplace(const Tensor<T,M,N>& A, Tensor<T,M,N> &P) {
Tensor<size_t,M> perm;
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A(i, j)) > std::abs(A(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
P.fill(0);
for (size_t i = 0; i < M; ++i)
P(i, perm(i)) = 1;
}
template<typename Derived, size_t DIM, size_t M,
enable_if_t_<requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
void
pivot_inplace(const AbstractTensor<Derived,DIM>& src, Tensor<size_t,M> &perm) {
typename Derived::result_type tmp(src.self());
pivot_inplace(tmp,perm);
}
template<typename Derived, size_t DIM, size_t M,
enable_if_t_<!requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
void
pivot_inplace(const AbstractTensor<Derived,DIM>& src, Tensor<size_t,M> &perm) {
static_assert(DIM==2, "TENSOR MUST BE 2D FOR PIVOT COMPUTATION");
using T = typename Derived::scalar_type;
const Derived &A = src.self();
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A.template eval_s<T>(i, j)) > std::abs(A.template eval_s<T>(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
}
template<typename Derived, size_t DIM, typename T, size_t M, size_t N,
enable_if_t_<requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
void
pivot_inplace(const AbstractTensor<Derived,DIM>& src, Tensor<T,M,N> &P) {
typename Derived::result_type tmp(src.self());
pivot_inplace(tmp,P);
}
template<typename Derived, size_t DIM, typename T, size_t M, size_t N,
enable_if_t_<!requires_evaluation_v<Derived>, bool> = false>
FASTOR_INLINE
void
pivot_inplace(const AbstractTensor<Derived,DIM>& src, Tensor<T,M,N> &P) {
static_assert(DIM==2, "TENSOR MUST BE 2D FOR PIVOT COMPUTATION");
const Derived &A = src.self();
Tensor<size_t,M> perm;
perm.iota();
for (size_t j = 0; j < M; ++j) {
size_t max_index = j;
for (size_t i = j; i < M; ++i) {
// std::abs is necessary only for complex valued numbers
if (std::abs(A.template eval_s<T>(i, j)) > std::abs(A.template eval_s<T>(max_index, j)))
max_index = i;
}
if (j != max_index)
std::swap(perm(j), perm(max_index));
}
for (size_t i = 0; i < M; ++i)
P(i, perm(i)) = 1;
}
/* Apply a pivot on a tensor/matrix
Applying pivot can only work on evaluated tensors and not expression
as non-evaluated expression do not have storage/data
*/
template <typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> apply_pivot(const Tensor<T,M,N>& A, const Tensor<size_t,M>& P) {
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
if (P(i) != i) {
std::copy_n(&A.data()[P(i)*N],N,&copyA.data()[i*N]);
}
}
return copyA;
}
template <typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> apply_pivot(const Tensor<T,M,N>& A, const Tensor<T,M,N>& P) {
// The output tensor is just matmul(P,A), but we are going to avoid
// the call to matmul
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
auto it = std::find(&P.data()[i*N],&P.data()[i*N+N],T(1));
size_t p = std::distance(&P.data()[i*N],it);
// Swap row p and i
if (p != i) {
std::copy_n(&A.data()[p*N],N,&copyA.data()[i*N]);
}
}
return copyA;
}
template <typename T, size_t M, size_t N>
FASTOR_INLINE void apply_pivot_inplace(Tensor<T,M,N>& A, const Tensor<size_t,M>& P) {
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
if (P(i) != i) {
std::copy_n(&copyA.data()[P(i)*N],N,&A.data()[i*N]);
}
}
}
template <typename T, size_t M, size_t N>
FASTOR_INLINE void apply_pivot_inplace(Tensor<T,M,N>& A, const Tensor<T,M,N>& P) {
// The output tensor is just matmul(P,A), but we are going to avoid
// the call to matmul
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
auto it = std::find(&P.data()[i*N],&P.data()[i*N+N],T(1));
size_t p = std::distance(&P.data()[i*N],it);
// Swap row p and i
if (p != i) {
std::copy_n(&copyA.data()[p*N],N,&A.data()[i*N]);
}
}
}
/* Reconstructing the matrix back from a pivoted factorisation
Reconstructs from LU/QR/QL etc
*/
template <typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> reconstruct(const Tensor<T,M,N>& L, Tensor<T,M,N>& U) {
return matmul(L,U);
}
/* Reconstructing the matrix back from a pivoted factorisation
Reconstructs from an PLU decomposition given P, L, U where P is
integral permutation vector
A = {P}^(-1)*L*U
*/
template <typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> reconstruct(const Tensor<T,M,N>& L, Tensor<T,M,N>& U, const Tensor<size_t,M>& P) {
Tensor<T,M,N> A = matmul(L,U);
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
if (P(i) != i) {
std::copy_n(&copyA.data()[i*N],N,&A.data()[P(i)*N]);
}
}
return A;
}
/* Reconstructing the matrix back from a pivoted factorisation
Reconstructs from an PLU decomposition given P, L, U
A = {P}^(-1)*L*U
*/
template <typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> reconstruct(const Tensor<T,M,N>& L, Tensor<T,M,N>& U, const Tensor<T,M,N>& P) {
// To avoid computing the inverse of P in {P}^(-1)*L*U
Tensor<T,M,N> A = matmul(L,U);
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
auto it = std::find(&P.data()[i*N],&P.data()[i*N+N],T(1));
size_t p = std::distance(&P.data()[i*N],it);
if (p != i) {
std::copy_n(&copyA.data()[i*N],N,&A.data()[p*N]);
}
}
return A;
}
/* Reconstructing the matrix back from a pivot only
*/
template <typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> reconstruct(const Tensor<T,M,N>& A, const Tensor<size_t,M>& P) {
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
if (P(i) != i) {
std::copy_n(&A.data()[i*N],N,&copyA.data()[P(i)*N]);
}
}
return copyA;
}
/* Reconstructing the matrix back from a pivot only - column-wise or rather post multiplication
used for computing inverse
*/
template <typename T, size_t M, size_t N>
FASTOR_INLINE Tensor<T,M,N> reconstruct_colwise(const Tensor<T,M,N>& A, const Tensor<size_t,M>& P) {
Tensor<T,M,N> copyA(A);
for (size_t i=0; i< M; ++i) {
if (P(i) != i) {
copyA(all,P(i)) = A(all,i);
}
}
return copyA;
}
} // end of namespace Fastor
#endif // UNARY_PIV_OP_H

View File

@@ -0,0 +1,198 @@
#ifndef UNARY_QR_OP_H
#define UNARY_QR_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/unary_piv_op.h"
namespace Fastor {
namespace internal {
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
/* Modified Gram-Schmidt Row-wise [MGSR] QR factorisation
that provides numerical stabilitiy.
This simple implementation provided for now is just for
convenience and not tuned for performance. Given that Tensor
types have fixed dimensions the compiler typically does a good
job
See:
Thomas Jakobs et. al. "Performance and energy consumption of the SIMD
GramSchmidt process for vector orthogonalization"
for implementation details including AVX/AVX512 implementation. A straight-
forward explicit vectorisation of this does not yield good performance for
row-major tensors, as step 1-2 need gather instructions and step 3-4 require
dynamic masking to gain performance
*/
template<typename T, size_t M, size_t N>
FASTOR_INLINE void qr_mgsr_dispatcher(const Tensor<T,M,N> &A0, Tensor<T,M,N>& Q, Tensor<T,M,N>& R) {
// Copy incoming tensor as we will modify A
Tensor<T,M,N> A(A0);
// Zero out
R.fill(0);
for (size_t i=0; i< N; ++i) {
// step 1
T R_ii = 0;
for (size_t k=0; k< M; ++k) {
R_ii += A(k,i)*A(k,i);
}
R_ii = sqrts(R_ii);
R(i,i) = R_ii;
// step 2
for (size_t k=0; k< M; ++k) {
Q(k,i) = A(k,i) / R_ii;
}
// step 3
for (size_t k=0; k< M; ++k) {
for (size_t j=i+1; j<N; ++j) {
R(i,j) += Q(k,i) * A(k,j);
}
}
// step 4
for (size_t k=0; k< M; ++k) {
for (size_t j=i+1; j<N; ++j) {
A(k,j) -= Q(k,i) * R(i,j);
}
}
}
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // internal
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// QR MGSR - no pivot
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<is_tensor_v<Expr> && QRType == QRCompType::MGSR,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R) {
internal::qr_mgsr_dispatcher(src.self(),Q,R);
}
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<!is_tensor_v<Expr> && QRType == QRCompType::MGSR,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R) {
Tensor<T,M,N> A(src.self());
internal::qr_mgsr_dispatcher(A,Q,R);
}
// QR MGSR - vector pivot
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<is_tensor_v<Expr> && QRType == QRCompType::MGSRPiv,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R, Tensor<size_t,M> &P) {
pivot_inplace(src.self(),P);
auto A(apply_pivot(src.self(),P));
internal::qr_mgsr_dispatcher(A,Q,R);
}
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<!is_tensor_v<Expr> && QRType == QRCompType::MGSRPiv,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R, Tensor<size_t,M> &P) {
typename Expr::result_type A(src.self());
pivot_inplace(A,P);
// Modify A as A is a temporary anyway
apply_pivot_inplace(A,P);
internal::qr_mgsr_dispatcher(A,Q,R);
}
// QR MGSR - matrix pivot
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<is_tensor_v<Expr> && QRType == QRCompType::MGSRPiv,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R, Tensor<T,M,N> &P) {
pivot_inplace(src.self(),P);
auto A(apply_pivot(src.self(),P));
internal::qr_mgsr_dispatcher(A,Q,R);
}
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<!is_tensor_v<Expr> && QRType == QRCompType::MGSRPiv,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R, Tensor<T,M,N> &P) {
typename Expr::result_type A(src.self());
pivot_inplace(A,P);
// Modify A as A is a temporary anyway
apply_pivot_inplace(A,P);
internal::qr_mgsr_dispatcher(A,Q,R);
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// QR householder reflections etc
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<QRType != QRCompType::MGSR,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R) {
static_assert(QRType==QRCompType::MGSR, "QR FACTORISATION USING HOUSEHOLDER REFLECTIONS IS NOT IMPLEMENETED YET");
}
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<QRType != QRCompType::MGSRPiv,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R, Tensor<size_t,M> &P) {
static_assert(QRType==QRCompType::MGSR, "QR FACTORISATION USING HOUSEHOLDER REFLECTIONS IS NOT IMPLEMENETED YET");
}
template<QRCompType QRType = QRCompType::MGSR, typename Expr, size_t DIM0, typename T, size_t M, size_t N,
enable_if_t_<QRType != QRCompType::MGSRPiv,bool> = false>
FASTOR_INLINE
void
qr(const AbstractTensor<Expr,DIM0> &src, Tensor<T,M,N> &Q, Tensor<T,N,M> &R, Tensor<T,M,N> &P) {
static_assert(QRType==QRCompType::MGSR, "QR FACTORISATION USING HOUSEHOLDER REFLECTIONS IS NOT IMPLEMENETED YET");
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
// Computing determinant using QR
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
template<DetCompType DetType = DetCompType::Simple, typename T, size_t M,
enable_if_t_<DetType == DetCompType::QR,bool> = false>
FASTOR_INLINE T determinant(const Tensor<T,M,M> &a) {
Tensor<T,M,M> Q, R;
qr(a, Q, R);
return product(diag(R));
}
//-----------------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------//
} // end of namespace Fastor
#endif // UNARY_QR_OP_H

View File

@@ -0,0 +1,163 @@
#ifndef UNARY_SVD_OP_H
#define UNARY_SVD_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/backend/inner.h"
#include "Fastor/backend/lufact.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_computation_types.h"
#include "Fastor/expressions/linalg_ops/unary_det_op.h"
#include "Fastor/expressions/linalg_ops/unary_trans_op.h"
namespace Fastor {
// SVD
template<typename T, size_t M, enable_if_t_<M==2, bool> = false >
FASTOR_INLINE void svd(const Tensor<T,M,M> &A, Tensor<T,M,M> &U, Tensor<T,M,M> &S, Tensor<T,M,M> &V) {
constexpr T Epsilon_v = std::numeric_limits<T>::epsilon();
const T f00 = A(0, 0);
const T f01 = A(0, 1);
const T f10 = A(1, 0);
const T f11 = A(1, 1);
// If matrix is diagonal, SVD is trivial
if (std::abs(f01 - f10) < Epsilon_v && std::abs(f01) < Epsilon_v)
{
// Compute U
U(0,0) = f00 < 0 ? -1. : 1.;
U(0,1) = 0.;
U(1,0) = 0.;
U(1,1) = f11 < 0. ? -1. : 1.;
// Compute S
S(0,0) = std::abs(f00);
S(0,1) = 0;
S(1,0) = 0;
S(1,1) = std::abs(f11);
// Compute V
V.eye2();
}
// Otherwise, we need to compute A^T*A
else
{
T j = f00 * f00 + f01 * f01;
T k = f10 * f10 + f11 * f11;
T v_c = f00 * f10 + f01 * f11;
// Check to see if A^T*A is diagonal
if (std::abs(v_c) < Epsilon_v)
{
// Compute S
T s1 = std::sqrt(j);
T s2 = std::abs(j - k) < Epsilon_v ? s1 : std::sqrt(k);
S(0,0) = s1;
S(0,1) = 0;
S(1,0) = 0;
S(1,1) = s2;
// Compute U
U.eye2();
// Compute V
V(0,0) = f00 / s1;
V(0,1) = f10 / s2;
V(1,0) = f01 / s1;
V(1,1) = f11 / s2;
}
// Otherwise, solve quadratic equation for eigenvalues
else
{
T jmk = j - k;
T jpk = j + k;
T root = std::sqrt(jmk * jmk + 4. * v_c * v_c);
T eig1 = (jpk + root) * 0.5;
T eig2 = (jpk - root) * 0.5;
// Compute S
T s1 = std::sqrt(eig1);
T s2 = std::abs(root) < Epsilon_v ? s1 : ( eig2 > 0 ? std::sqrt(eig2) : Epsilon_v);
S(0,0) = s1;
S(0,1) = 0;
S(1,0) = 0;
S(1,1) = s2;
// Compute U - use eigenvectors of A^T*A as U
T v_s = eig1 - j;
T len = std::max(std::sqrt(v_s * v_s + v_c * v_c), Epsilon_v);
v_c /= len;
v_s /= len;
U(0,0) = v_c;
U(0,1) = -v_s;
U(1,0) = v_s;
U(1,1) = v_c;
// Compute V - as A * U / s
const T cc = (f00 * v_c + f10 * v_s) / s1;
const T cs = (f01 * v_c + f11 * v_s) / s1;
if (std::abs(s2) > Epsilon_v)
{
V(0,0) = cc;
V(0,1) = (f10* v_c - f00 * v_s) / s2;
V(1,0) = cs;
V(1,1) = (f11 * v_c - f01 * v_s) / s2;
}
else
{
V(0,0) = cc;
V(0,1) = cs;
V(1,0) = cs;
V(1,1) = -cc;
}
}
}
}
// Signed SVD
template<typename T, size_t M>
FASTOR_INLINE void ssvd(const Tensor<T,M,M> &A, Tensor<T,M,M> &U, Tensor<T,M,M> &S, Tensor<T,M,M> &V) {
// Same as above but avoiding the L matrix
svd(A, U, S, V);
// See where to pull the reflection out of
const T detU = determinant(U);
const T detV = determinant(V);
if (detU >= 0 && detV >= 0)
{
// No reflection svd == svd_rv, return
return;
}
Tensor<T, M, M> L = matmul(U, transpose(V));
const T lastColumn = determinant(L);
if (detU < 0 && detV > 0)
{
U(all, M - 1) *= lastColumn;
}
else if (detU > 0 && detV < 0)
{
V(all, M - 1) *= lastColumn;
}
// Push the reflection to the diagonal
S(M - 1, M - 1) *= lastColumn;
}
//-----------------------------------------------------------------------------------------------------------//
} // end of namespace Fastor
#endif // UNARY_SVD_OP_H

View File

@@ -0,0 +1,75 @@
#ifndef UNARY_TRACE_OP_H
#define UNARY_TRACE_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
namespace Fastor {
// For tensors
template<typename T, size_t I>
FASTOR_INLINE T trace(const Tensor<T,I,I> &a) {
return _trace<T,I,I>(static_cast<const T *>(a.data()));
}
// For high order tensors
template<typename T, size_t ... Rest, typename std::enable_if<sizeof...(Rest)>=3,bool>::type=0>
FASTOR_INLINE
typename last_matrix_extracter<Tensor<T,Rest...>, typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::type
trace(const Tensor<T,Rest...> &a) {
using OutTensor = typename last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::type;
constexpr size_t remaining_product = last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::remaining_product;
constexpr size_t I = get_value<sizeof...(Rest)-1,Rest...>::value;
constexpr size_t J = get_value<sizeof...(Rest),Rest...>::value;
static_assert(I==J,"THE LAST TWO DIMENSIONS OF TENSOR MUST BE THE SAME");
OutTensor out;
T *a_data = a.data();
T *out_data = out.data();
for (size_t i=0; i<remaining_product; ++i) {
out_data[i] = _trace<T,J,J>(static_cast<const T *>(a_data+i*J*J));
}
return out;
}
// Trace for generic expressions
template<class Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type trace(const AbstractTensor<Derived,DIMS> &_src) {
const Derived& src = _src.self();
using T = typename Derived::scalar_type;
using tensor_type = typename Derived::result_type;
constexpr size_t M = get_tensor_dimensions<tensor_type>::dims[0];
constexpr size_t N = get_tensor_dimensions<tensor_type>::dims[1];
static_assert(DIMS==2,"TENSOR EXPRESSION SHOULD BE UNIFORM (SQUARE)");
static_assert(M==N,"TENSOR EXPRESSION SHOULD BE TWO DIMENSIONAL");
FASTOR_INDEX i;
T _scal=0;
for (i = 0; i < M; ++i) {
_scal += src.template eval_s<T>(i*(N+1));
}
return _scal;
}
template<class Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_INLINE typename Derived::scalar_type trace(const AbstractTensor<Derived,DIMS> &_src) {
using result_type = typename Derived::result_type;
const result_type out(_src.self());
return trace(out);
}
} // end of namespace Fastor
#endif // UNARY_TRACE_OP_H

View File

@@ -0,0 +1,173 @@
#ifndef UNARY_TRANS_OP_H
#define UNARY_TRANS_OP_H
#include "Fastor/meta/meta.h"
#include "Fastor/backend/transpose/transpose.h"
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/tensor/AbstractTensor.h"
#include "Fastor/tensor/Aliasing.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/tensor/TensorTraits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
template<typename Expr, size_t DIM0>
struct UnaryTransOp: public AbstractTensor<UnaryTransOp<Expr, DIM0>,DIM0> {
using expr_type = expression_t<Expr>;
static constexpr FASTOR_INDEX M = get_tensor_dimension_v<0,typename Expr::result_type>;
static constexpr FASTOR_INDEX N = get_tensor_dimension_v<1,typename Expr::result_type>;
static constexpr FASTOR_INDEX Dimension = DIM0;
static constexpr FASTOR_INDEX rank() {return DIM0;}
using scalar_type = typename scalar_type_finder<UnaryTransOp<Expr, DIM0>>::type;
using simd_vector_type = typename Expr::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<scalar_type,N,M>;
FASTOR_INLINE UnaryTransOp(expr_type inexpr) : _expr(inexpr) {
}
FASTOR_INLINE FASTOR_INDEX size() const {return M*N;}
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return i == 0 ? N : M;}
constexpr FASTOR_INLINE expr_type expr() const {return _expr;}
private:
expr_type _expr;
};
/* Tensor transpose returning a tensor expression */
template<typename Expr, size_t DIM0>
FASTOR_INLINE UnaryTransOp<Expr, DIM0>
trans(const AbstractTensor<Expr,DIM0> &src) {
return UnaryTransOp<Expr, DIM0>(src.self());
}
/* Tensor transpose immediately returning a tensor */
template<typename T, size_t I, size_t J>
FASTOR_INLINE Tensor<T,J,I> transpose(const Tensor<T,I,J> &a) {
Tensor<T,J,I> out;
_transpose<T,I,J>(a.data(),out.data());
return out;
}
/* Tensor transpose for higher order tensors immediately returning a tensor */
template<typename T, size_t ... Rest, typename std::enable_if<sizeof...(Rest)>=3,bool>::type=0>
FASTOR_INLINE Tensor<T,Rest...>
transpose(const Tensor<T,Rest...> &a) {
constexpr size_t remaining_product = last_matrix_extracter<Tensor<T,Rest...>,
typename std_ext::make_index_sequence<sizeof...(Rest)-2>::type>::remaining_product;
constexpr size_t I = get_value<sizeof...(Rest)-1,Rest...>::value;
constexpr size_t J = get_value<sizeof...(Rest),Rest...>::value;
static_assert(I==J,"THE LAST TWO DIMENSIONS OF TENSOR MUST BE THE SAME");
Tensor<T,Rest...> out;
T *a_data = a.data();
T *out_data = out.data();
for (size_t i=0; i<remaining_product; ++i) {
_transpose<T,J,J>(a_data+i*J*J,out_data+i*J*J);
}
return out;
}
// Transpose for generic expressions
template<typename Expr, size_t DIM0>
FASTOR_INLINE
Tensor<
typename scalar_type_finder<Expr>::type,
get_tensor_dimension_v<1,typename Expr::result_type>,
get_tensor_dimension_v<0,typename Expr::result_type>>
transpose(const AbstractTensor<Expr,DIM0> &src) {
// If we are here Expr is already an expression
using result_type = typename Expr::result_type;
const result_type tmp(src.self());
return transpose(tmp);
}
// assignments
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign(AbstractTensor<Derived,DIM> &dst, const UnaryTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
const result_type& tmp = evaluate(src.expr().self());
using T = typename UnaryTransOp<Expr, OtherDIM>::scalar_type;
static constexpr size_t M = UnaryTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryTransOp<Expr, OtherDIM>::N;
_transpose<T,M,N>(tmp.data(),dst.self().data());
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_add(AbstractTensor<Derived,DIM> &dst, const UnaryTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryTransOp<Expr, OtherDIM>::N;
_transpose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_add(dst.self(),tmp_trans);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_sub(AbstractTensor<Derived,DIM> &dst, const UnaryTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryTransOp<Expr, OtherDIM>::N;
_transpose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_sub(dst.self(),tmp_trans);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_mul(AbstractTensor<Derived,DIM> &dst, const UnaryTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryTransOp<Expr, OtherDIM>::N;
_transpose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_mul(dst.self(),tmp_trans);
}
template<typename Derived, size_t DIM, typename Expr, size_t OtherDIM>
FASTOR_INLINE void assign_div(AbstractTensor<Derived,DIM> &dst, const UnaryTransOp<Expr, OtherDIM> &src) {
using result_type = typename Expr::result_type;
// no copies if expr is a tensor
const result_type& tmp = evaluate(src.expr().self());
// one copy for the inverse
using T = typename UnaryTransOp<Expr, OtherDIM>::scalar_type;
using result_t = typename UnaryTransOp<Expr, OtherDIM>::result_type;
result_t tmp_trans;
static constexpr size_t M = UnaryTransOp<Expr, OtherDIM>::M;
static constexpr size_t N = UnaryTransOp<Expr, OtherDIM>::N;
_transpose<T,M,N>(tmp.data(),tmp_trans.data());
trivial_assign_div(dst.self(),tmp_trans);
}
} // end of namespace Fastor
#endif // UNARY_TRANS_OP_H

View File

@@ -0,0 +1,101 @@
#ifndef UNARY_BOOL_OP_H
#define UNARY_BOOL_OP_H
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/simd_math/simd_math.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
// All unary bool ops
#define FASTOR_MAKE_UNARY_BOOL_OPS(OP_NAME, SIMD_OP, SCALAR_OP, STRUCT_NAME, EVAL_TYPE)\
template<typename Expr, size_t DIM0>\
struct Unary ##STRUCT_NAME ## Op: public AbstractTensor<Unary ##STRUCT_NAME ## Op<Expr, DIM0>,DIM0> {\
private:\
expression_t<Expr> _expr;\
public:\
using scalar_type = typename Expr::scalar_type;\
using simd_vector_type = typename Expr::simd_vector_type;\
using simd_abi_type = typename simd_vector_type::abi_type;\
using result_type = to_bool_tensor_t<typename Expr::result_type>;\
using result_scalar_type = typename result_type::scalar_type;\
using result_simd_abi_type = typename result_type::simd_abi_type;\
using result_simd_vector_type = typename result_type::simd_vector_type;\
using UU = bool /*this needs to change to U once masks are implemented*/;\
using ABI = simd_abi::fixed_size<SIMDVector<EVAL_TYPE,simd_abi_type>::Size>;\
static constexpr FASTOR_INDEX Dimension = DIM0;\
static constexpr FASTOR_INDEX rank() {return DIM0;}\
FASTOR_INLINE FASTOR_INDEX size() const {return _expr.size();}\
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return _expr.dimension(i);}\
Unary ##STRUCT_NAME ## Op(expression_t<Expr> inexpr) : _expr(inexpr) {}\
FASTOR_INLINE expression_t<Expr> expr() const {return _expr;}\
template<typename U=scalar_type>\
FASTOR_INLINE SIMDVector<UU,ABI> eval(FASTOR_INDEX i) const {\
return SIMD_OP(_expr.template eval<EVAL_TYPE>(i));\
}\
template<typename U=scalar_type>\
FASTOR_INLINE UU eval_s(FASTOR_INDEX i) const {\
return SCALAR_OP(_expr.template eval_s<EVAL_TYPE>(i));\
}\
template<typename U=scalar_type>\
FASTOR_INLINE SIMDVector<UU,ABI> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return SIMD_OP(_expr.template eval<EVAL_TYPE>(i,j));\
}\
template<typename U=scalar_type>\
FASTOR_INLINE UU eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return SCALAR_OP(_expr.template eval_s<EVAL_TYPE>(i,j));\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<UU,ABI> teval(const std::array<int,DIM0> &as) const {\
return SIMD_OP(_expr.template teval<EVAL_TYPE>(as));\
}\
template<typename U>\
FASTOR_INLINE UU teval_s(const std::array<int,DIM0> &as) const {\
return SCALAR_OP(_expr.template teval_s<EVAL_TYPE>(as));\
}\
};\
template<typename Expr, size_t DIM0,\
typename std::enable_if<!std::is_arithmetic<Expr>::value,bool>::type = 0 >\
FASTOR_INLINE Unary ##STRUCT_NAME ## Op<Expr, DIM0> OP_NAME(const AbstractTensor<Expr,DIM0> &_expr) {\
return Unary ##STRUCT_NAME ## Op<Expr, DIM0>(_expr.self());\
}\
FASTOR_MAKE_UNARY_BOOL_OPS(operator!, ! , ! , Not , scalar_type)
FASTOR_MAKE_UNARY_BOOL_OPS(isinf , isinf , std::isinf , Isinf , scalar_type)
FASTOR_MAKE_UNARY_BOOL_OPS(isnan , isnan , std::isnan , Isnan , scalar_type)
FASTOR_MAKE_UNARY_BOOL_OPS(isfinite, isfinite, std::isfinite, Isfinite, scalar_type)
#define FASTOR_MAKE_UNARY_BOOL_OP_ASSIGNMENT(OP, NAME, ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM,\
typename std::enable_if<requires_evaluation_v<OtherDerived>,bool>::type = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Unary ##NAME ## Op<OtherDerived,OtherDIM> &src) {\
using result_type = typename OtherDerived::result_type;\
const result_type tmp(src.expr().self());\
trivial_assign ##ASSIGN_TYPE (dst.self(), OP(tmp));\
}\
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM,\
typename std::enable_if<!requires_evaluation_v<OtherDerived>,bool>::type = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Unary ##NAME ## Op<OtherDerived,OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
// only assignment
FASTOR_MAKE_UNARY_BOOL_OP_ASSIGNMENT(! , Not , )
FASTOR_MAKE_UNARY_BOOL_OP_ASSIGNMENT(isinf , Isinf , )
FASTOR_MAKE_UNARY_BOOL_OP_ASSIGNMENT(isnan , Isnan , )
FASTOR_MAKE_UNARY_BOOL_OP_ASSIGNMENT(isfinite, Isfinite, )
} // end of namespace Fastor
#endif // UNARY_BOOL_OP_H

View File

@@ -0,0 +1,209 @@
#ifndef UNARY_MATH_OP_H
#define UNARY_MATH_OP_H
#include "Fastor/simd_vector/SIMDVector.h"
#include "Fastor/simd_math/simd_math.h"
#include "Fastor/tensor/Tensor.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
#include "Fastor/expressions/expression_traits.h"
namespace Fastor {
// All unary math ops
#define FASTOR_MAKE_UNARY_MATH_OPS(OP_NAME, SIMD_OP, SCALAR_OP, STRUCT_NAME, EVAL_TYPE)\
template<typename Expr, size_t DIM0>\
struct Unary ##STRUCT_NAME ## Op: public AbstractTensor<Unary ##STRUCT_NAME ## Op<Expr, DIM0>,DIM0> {\
private:\
expression_t<Expr> _expr;\
public:\
using scalar_type = typename Expr::scalar_type;\
using simd_vector_type = typename Expr::simd_vector_type;\
using simd_abi_type = typename simd_vector_type::abi_type;\
using result_type = typename Expr::result_type;\
static constexpr FASTOR_INDEX Dimension = DIM0;\
static constexpr FASTOR_INDEX rank() {return DIM0;}\
FASTOR_INLINE FASTOR_INDEX size() const {return _expr.size();}\
FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return _expr.dimension(i);}\
Unary ##STRUCT_NAME ## Op(expression_t<Expr> inexpr) : _expr(inexpr) {}\
FASTOR_INLINE expression_t<Expr> expr() const {return _expr;}\
template<typename U=scalar_type>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i) const {\
return SIMD_OP(_expr.template eval<EVAL_TYPE>(i));\
}\
template<typename U=scalar_type>\
FASTOR_INLINE EVAL_TYPE eval_s(FASTOR_INDEX i) const {\
return SCALAR_OP(_expr.template eval_s<EVAL_TYPE>(i));\
}\
template<typename U=scalar_type>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return SIMD_OP(_expr.template eval<EVAL_TYPE>(i,j));\
}\
template<typename U=scalar_type>\
FASTOR_INLINE EVAL_TYPE eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {\
return SCALAR_OP(_expr.template eval_s<EVAL_TYPE>(i,j));\
}\
template<typename U>\
FASTOR_INLINE SIMDVector<EVAL_TYPE,simd_abi_type> teval(const std::array<int,DIM0> &as) const {\
return SIMD_OP(_expr.template teval<EVAL_TYPE>(as));\
}\
template<typename U>\
FASTOR_INLINE EVAL_TYPE teval_s(const std::array<int,DIM0> &as) const {\
return SCALAR_OP(_expr.template teval_s<EVAL_TYPE>(as));\
}\
};\
template<typename Expr, size_t DIM0,\
typename std::enable_if<!std::is_arithmetic<Expr>::value,bool>::type = 0 >\
FASTOR_INLINE Unary ##STRUCT_NAME ## Op<Expr, DIM0> OP_NAME(const AbstractTensor<Expr,DIM0> &_expr) {\
return Unary ##STRUCT_NAME ## Op<Expr, DIM0>(_expr.self());\
}\
FASTOR_MAKE_UNARY_MATH_OPS(operator+, , , Add, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(operator-, -, -, Sub, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(abs, abs, std::abs, Abs, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(sqrt, sqrt, sqrts, Sqrt, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(cbrt, cbrt, std::cbrt, Cbrt, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(exp, exp, std::exp, Exp, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(exp2, exp2, std::exp2, Exp2, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(expm1, expm1, std::expm1, Expm1, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(log, log, std::log, Log, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(log10, log10, std::log10, Log10, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(log2, log2, std::log2, Log2, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(log1p, log1p, std::log1p, Log1p, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(sin, sin, std::sin, Sin, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(cos, cos, std::cos, Cos, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(tan, tan, std::tan, Tan, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(asin, asin, std::asin, Asin, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(acos, acos, std::acos, Acos, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(atan, atan, std::atan, Atan, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(sinh, sinh, std::sinh, Sinh, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(cosh, cosh, std::cosh, Cosh, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(tanh, tanh, std::tanh, Tanh, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(asinh, asinh, std::asinh, Asinh, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(acosh, acosh, std::acosh, Acosh, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(atanh, atanh, std::atanh, Atanh, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(erf, erf, std::erf, Erf, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(tgamma, tgamma, std::tgamma, Tgamma, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(lgamma, lgamma, std::lgamma, Lgamma, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(ceil, ceil, std::ceil, Ceil, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(round, round, std::round, Round, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(floor, floor, std::floor, Floor, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(trunc, trunc, std::trunc, Trunc, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(conj, conj, std::conj, Conj, scalar_type)
FASTOR_MAKE_UNARY_MATH_OPS(arg , arg , std::arg , Arg , scalar_type)
#define FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(OP, NAME, ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM,\
typename std::enable_if<requires_evaluation_v<OtherDerived>,bool>::type = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Unary ##NAME ## Op<OtherDerived,OtherDIM> &src) {\
assign ##ASSIGN_TYPE (dst.self(), src.expr().self());\
trivial_assign(dst.self(), OP(dst.self()));\
}\
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM,\
typename std::enable_if<!requires_evaluation_v<OtherDerived>,bool>::type = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Unary ##NAME ## Op<OtherDerived,OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
// only assignment
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT( , Add, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(-, Sub, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(abs, Abs, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(sqrt, Sqrt, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(cbrt, Cbrt, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(exp, Exp, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(exp2, Exp2, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(expm1, Expm1, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(log, Log, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(log10, Log10, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(log2, Log2, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(log1p, Log1p, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(sin, Sin, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(cos, Cos, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(tan, Tan, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(asin, Asin, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(acos, Acos, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(atan, Atan, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(sinh, Sinh, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(cosh, Cosh, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(tanh, Tanh, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(asinh, Asinh, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(acosh, Acosh, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(atanh, Atanh, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(erf, Erf, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(tgamma, Tgamma, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(lgamma, Lgamma, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(ceil, Ceil, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(round, Round, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(floor, Floor, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(trunc, Trunc, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(conj, Conj, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENT(arg , Arg , )
// arithmetic assignments
#define FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(OP, NAME, ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM,\
typename std::enable_if<requires_evaluation_v<OtherDerived>,bool>::type = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Unary ##NAME ## Op<OtherDerived,OtherDIM> &src) {\
using result_type = typename Unary ##NAME ## Op<OtherDerived,OtherDIM>::result_type;\
const result_type tmp(src.expr().self());\
trivial_assign ##ASSIGN_TYPE (dst.self(), OP(tmp));\
}\
template<typename Derived, size_t DIM, typename OtherDerived, size_t OtherDIM,\
typename std::enable_if<!requires_evaluation_v<OtherDerived>,bool>::type = false>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const Unary ##NAME ## Op<OtherDerived,OtherDIM> &src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
#define FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENTS(OP, NAME, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT( , Add, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(-, Sub, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(abs, Abs, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(sqrt, Sqrt, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(cbrt, Cbrt, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(exp, Exp, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(exp2, Exp2, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(expm1, Expm1, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(log, Log, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(log10, Log10, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(log2, Log2, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(log1p, Log1p, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(sin, Sin, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(cos, Cos, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(tan, Tan, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(asin, Asin, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(acos, Acos, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(atan, Atan, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(sinh, Sinh, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(cosh, Cosh, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(tanh, Tanh, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(asinh, Asinh, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(acosh, Acosh, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(atanh, Atanh, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(erf, Erf, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(tgamma, Tgamma, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(lgamma, Lgamma, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(ceil, Ceil, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(round, Round, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(floor, Floor, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(trunc, Trunc, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(conj, Conj, ASSIGN_TYPE)\
FASTOR_MAKE_UNARY_MATH_OP_ARITHMETIC_ASSIGNMENT(arg , Arg , ASSIGN_TYPE)\
// FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENTS(OP, NAME, )
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENTS(OP, NAME, _add)
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENTS(OP, NAME, _sub)
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENTS(OP, NAME, _mul)
FASTOR_MAKE_UNARY_MATH_OP_ASSIGNMENTS(OP, NAME, _div)
} // end of namespace Fastor
#endif // UNARY_MATH_OP_H

View File

@@ -0,0 +1,317 @@
#ifndef TENSOR_DIAG_VIEWS_H
#define TENSOR_DIAG_VIEWS_H
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/TensorMap.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
namespace Fastor {
template<template<typename,size_t...> class TensorType, typename T, size_t M, size_t N, size_t DIM>
struct TensorDiagViewExpr<TensorType<T,M,N>,DIM> : public AbstractTensor<TensorDiagViewExpr<TensorType<T,M,N>,DIM>,DIM> {
private:
TensorType<T,M,N>& _expr;
bool _does_alias = false;
constexpr FASTOR_INLINE Tensor<T,M,N> get_tensor() const {return _expr;};
public:
using scalar_type = T;
using simd_vector_type = typename Tensor<T,M,N>::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<T,M>;
using V = SIMDVector<T,simd_abi_type>;
static constexpr FASTOR_INDEX Dimension = 1;
static constexpr FASTOR_INDEX Stride = simd_vector_type::Size;
static constexpr FASTOR_INDEX rank() {return 1;}
constexpr FASTOR_INLINE FASTOR_INDEX size() const {return M;}
constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX ) const {return M;}
constexpr const TensorType<T,M,N>& expr() const {return _expr;}
FASTOR_INLINE TensorViewExpr<TensorType<T,M,N>,2>& noalias() {
_does_alias = true;
return *this;
}
FASTOR_INLINE TensorDiagViewExpr(Tensor<T,M,N> &_ex) : _expr(_ex) {
static_assert(M==N, "MATRIX MUST BE SQUARE FOR DIAGONAL VIEW");
}
// Copy assignment
//---------------------------------------------------------------------------------//
FASTOR_INLINE void operator=(const TensorDiagViewExpr<TensorType<T,M,N>,DIM>& other_src) {
// Diagonal views don't alias
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
// Get around recursive inlining issue
const result_type tmp(other_src);
this->operator=(tmp);
return;
}
#endif
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(other_src.dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) = other_src.template eval_s<T>(i,i);
}
}
// AbstractTensor binders
//---------------------------------------------------------------------------------//
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorDiagViewExpr<TensorType<T,M,N>,2>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) = other_src.template eval_s<T>(i);
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator+=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator+=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator+=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorDiagViewExpr<TensorType<T,M,N>,2>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator+=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) += other_src.template eval_s<T>(i);
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator-=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator-=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator-=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorDiagViewExpr<TensorType<T,M,N>,2>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator-=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) -= other_src.template eval_s<T>(i);
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator*=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator*=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator*=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorDiagViewExpr<TensorType<T,M,N>,2>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator*=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) *= other_src.template eval_s<T>(i);
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator/=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator/=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator/=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorDiagViewExpr<TensorType<T,M,N>,2>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator/=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) /= other_src.template eval_s<T>(i);
}
}
// Scalar binders
//---------------------------------------------------------------------------------//
template<typename U, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator=(U num) {
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) = num;
}
}
template<typename U, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator+=(U num) {
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) += num;
}
}
template<typename U, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator-=(U num) {
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) -= num;
}
}
template<typename U, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator*=(U num) {
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) *= num;
}
}
template<typename U, enable_if_t_<is_arithmetic_v_<U> && !is_integral_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator/=(U num) {
T inum = T(1) / T(num);
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) *= inum;
}
}
template<typename U, enable_if_t_<is_arithmetic_v_<U> && is_integral_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator/=(U num) {
for (FASTOR_INDEX i = 0; i < M; ++i) {
_expr(i,i) /= num;
}
}
// Evaluators
//---------------------------------------------------------------------------------//
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX idx) const {
V _vec;
std::array<int,V::Size> inds;
for (auto j=0; j<V::Size; ++j) {
const size_t it = idx+j;
inds[j] = it*N+it;
}
vector_setter(_vec,_expr.data(),inds);
return _vec;
}
template<typename U=T>
FASTOR_INLINE U eval_s(FASTOR_INDEX idx) const {
return _expr(idx,idx);
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
V _vec;
vector_setter(_vec,_expr.data(),i*N+j);
return _vec;
}
template<typename U=T>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _expr(i,j);
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,2>& as) const {
V _vec;
vector_setter(_vec,_expr.data(),as[0]*N+as[1]);
return _vec;
}
template<typename U=T>
constexpr FASTOR_INLINE U teval_s(const std::array<int,2>& as) const {
return _expr.eval_s(as);
}
};
// Actual definition of diag function
// Note that like other views the input can only be an evaluated tensor
template<typename T, size_t M, size_t N>
TensorDiagViewExpr<Tensor<T,M,N>,2> diag(Tensor<T,M,N> &a) {
return TensorDiagViewExpr<Tensor<T,M,N>,2>(a);
}
template<typename T, size_t M, size_t N>
TensorDiagViewExpr<TensorMap<T,M,N>,2> diag(TensorMap<T,M,N> &a) {
return TensorDiagViewExpr<TensorMap<T,M,N>,2>(a);
}
} // end of namespace Fastor
#endif

View File

@@ -0,0 +1,281 @@
#ifndef TENSOR_FILTER_VIEWS_H
#define TENSOR_FILTER_VIEWS_H
#include "Fastor/tensor/Tensor.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
namespace Fastor {
template<typename T, size_t ... Rest, size_t DIMS>
struct TensorFilterViewExpr<Tensor<T,Rest...>,Tensor<bool,Rest...>,DIMS>:
public AbstractTensor<TensorFilterViewExpr<Tensor<T,Rest...>,Tensor<bool,Rest...>,DIMS>,DIMS> {
private:
Tensor<T,Rest...> &_expr;
const Tensor<bool,Rest...> &fl_expr;
bool _does_alias = false;
constexpr FASTOR_INLINE Tensor<T,Rest...> get_tensor() const {return _expr;}
public:
using scalar_type = T;
using simd_vector_type = typename Tensor<T,Rest...>::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<T,Rest...>;
static constexpr FASTOR_INDEX Dimension = DIMS;
static constexpr FASTOR_INDEX Stride = simd_vector_type::Size;
static constexpr FASTOR_INDEX rank() {return DIMS;}
constexpr FASTOR_INLINE FASTOR_INDEX size() const {return pack_prod<Rest...>::value;}
constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) const {return fl_expr.dimension(i);}
constexpr const Tensor<T,Rest...>& expr() const {return _expr;}
FASTOR_INLINE TensorFilterViewExpr<Tensor<T,Rest...>,Tensor<bool,Rest...>,DIMS>& noalias() {
_does_alias = true;
return *this;
}
constexpr FASTOR_INLINE TensorFilterViewExpr(Tensor<T,Rest...> &_ex, const Tensor<bool,Rest...> &_it) : _expr(_ex), fl_expr(_it) {
static_assert(sizeof...(Rest)==DIMS, "INDEXING TENSOR WITH INCORRECT NUMBER OF ARGUMENTS");
}
// In place operators
//------------------------------------------------------------------------------------//
void operator=(const TensorFilterViewExpr<Tensor<T,Rest...>,Tensor<bool,Rest...>,DIMS> &src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(src.dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] = src.template eval_s<T>(i);
}
}
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
void operator=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
const typename Derived::result_type& tmp = evaluate(src.self());
this->operator=(tmp);
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
void operator=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.self().size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(src.self().dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] = src.self().template eval_s<T>(i);
}
}
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
void operator+=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
const typename Derived::result_type& tmp = evaluate(src.self());
this->operator+=(tmp);
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
void operator+=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.self().size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(src.self().dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] += src.self().template eval_s<T>(i);
}
}
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
void operator-=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
const typename Derived::result_type& tmp = evaluate(src.self());
this->operator-=(tmp);
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
void operator-=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.self().size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(src.self().dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] -= src.self().template eval_s<T>(i);
}
}
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
void operator*=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
const typename Derived::result_type& tmp = evaluate(src.self());
this->operator*=(tmp);
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
void operator*=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.self().size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(src.self().dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] *= src.self().template eval_s<T>(i);
}
}
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
void operator/=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
const typename Derived::result_type& tmp = evaluate(src.self());
this->operator/=(tmp);
}
template<typename Derived, size_t OTHER_DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
void operator/=(const AbstractTensor<Derived,OTHER_DIMS> &src) {
#ifndef NDEBUG
FASTOR_ASSERT(src.self().size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(src.self().dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] /= src.self().template eval_s<T>(i);
}
}
}
//------------------------------------------------------------------------------------//
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
void operator=(U num) {
T tnum = (T)num;
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] = tnum;
}
}
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
void operator+=(U num) {
T tnum = (T)num;
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] += tnum;
}
}
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
void operator-=(U num) {
T tnum = (T)num;
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] -= tnum;
}
}
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U>,bool> = false>
void operator*=(U num) {
T tnum = (T)num;
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] *= tnum;
}
}
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U> && !is_integral_v_<U>,bool> = false>
void operator/=(U num) {
T tnum = T(1)/(T)num;
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] *= tnum;
}
}
}
template<typename U=T, enable_if_t_<is_arithmetic_v_<U> && is_integral_v_<U>,bool> = false>
void operator/=(U num) {
T tnum = (T)num;
for (FASTOR_INDEX i = 0; i <size(); i++) {
if (fl_expr.eval_s(i)) {
_expr.data()[i] /= tnum;
}
}
}
//------------------------------------------------------------------------------------//
//------------------------------------------------------------------------------------//
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
constexpr size_t _Stride = SIMDVector<T,simd_abi_type>::Size;
SIMDVector<U,simd_abi_type> _vec;
U inds[_Stride];
for (FASTOR_INDEX j=0; j<_Stride; ++j)
inds[j] = fl_expr.eval_s(i+j) ? _expr.eval_s(i+j) : 0;
_vec.load(inds,false);
return _vec;
}
template<typename U=T>
FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return fl_expr.eval_s(i) ? _expr.eval_s(i) : 0;
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX k) const {
constexpr size_t _Stride = SIMDVector<T,simd_abi_type>::Size;
SIMDVector<U,simd_abi_type> _vec;
U inds[_Stride];
for (FASTOR_INDEX j=0; j<_Stride; ++j)
inds[j] = fl_expr.eval_s(i,k+j) ? _expr.eval_s(i,k+j) : 0;
_vec.load(inds,false);
return _vec;
}
template<typename U=T>
FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX k) const {
return fl_expr.eval_s(i,k) ? _expr.eval_s(i,k) : 0;
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,DIMS>& as) const {
constexpr size_t _Stride = SIMDVector<T,simd_abi_type>::Size;
SIMDVector<U,simd_abi_type> _vec;
U inds[_Stride];
for (FASTOR_INDEX j=0; j<_Stride; ++j)
inds[j] = fl_expr.teval_s(as) ? _expr.teval_s(as) : 0;
_vec.load(inds,false);
return _vec;
}
template<typename U=T>
FASTOR_INLINE U teval_s(const std::array<int,DIMS>& as) const {
return fl_expr.teval_s(as) ? _expr.teval_s(as) : 0;
}
//------------------------------------------------------------------------------------//
};
} // end of namespace Fastor
#endif // TENSOR_FILTER_VIEWS_H

View File

@@ -0,0 +1,681 @@
#ifndef TENSOR_FIXED_VIEWS_1D_H
#define TENSOR_FIXED_VIEWS_1D_H
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
namespace Fastor {
// 1D const fixed views
//----------------------------------------------------------------------------------------------//
template<typename T, size_t N, int F0, int L0, int S0>
struct TensorConstFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1> :
public AbstractTensor<TensorConstFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>,1> {
private:
const Tensor<T,N> &_expr;
public:
using scalar_type = T;
using simd_vector_type = typename Tensor<T,N>::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<T,range_detector<F0,L0,S0>::value>;
static constexpr FASTOR_INDEX Dimension = 1;
static constexpr FASTOR_INDEX Stride = simd_vector_type::Size;
static constexpr FASTOR_INLINE FASTOR_INDEX size() { return range_detector<F0,L0,S0>::value;}
static constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX ) {return range_detector<F0,L0,S0>::value;}
constexpr const Tensor<T,N>& expr() const {return _expr;}
constexpr FASTOR_INLINE TensorConstFixedViewExpr1D(const Tensor<T,N> &_ex) : _expr(_ex) {}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),S0*i+F0,S0);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return _expr.data()[S0*i+F0];
}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),S0*(i+j)+F0,S0);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _expr.data()[S0*(i+j)+F0];
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,1>& as) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),S0*as[0]+F0,S0);
return _vec;
}
template<typename U=T>
constexpr FASTOR_INLINE U teval_s(const std::array<int,1>& as) const {
return _expr.data()[S0*as[0]+F0];
}
};
// 1D non-const fixed views
//----------------------------------------------------------------------------------------------//
template<typename T, size_t N, int F0, int L0, int S0>
struct TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1> :
public AbstractTensor<TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>,1> {
private:
Tensor<T,N> &_expr;
bool _does_alias = false;
constexpr FASTOR_INLINE Tensor<T,N> get_tensor() const {return _expr;}
public:
using scalar_type = T;
using simd_vector_type = typename Tensor<T,N>::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using result_type = Tensor<T,range_detector<F0,L0,S0>::value>;
static constexpr FASTOR_INDEX Dimension = 1;
static constexpr FASTOR_INDEX Stride = simd_vector_type::Size;
static constexpr FASTOR_INLINE FASTOR_INDEX size() {return range_detector<F0,L0,S0>::value;}
static constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX i) {return range_detector<F0,L0,S0>::value;}
constexpr const Tensor<T,N>& expr() const {return _expr;}
FASTOR_INLINE TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>& noalias() {
_does_alias = true;
return *this;
}
constexpr FASTOR_INLINE TensorFixedViewExpr1D(Tensor<T,N> &_ex) : _expr(_ex) {}
//----------------------------------------------------------------------------------//
FASTOR_HINT_INLINE void operator=(const TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1> &other_src) {
#ifndef FASTOR_NO_ALIAS
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>(tmp_this_tensor);
// Assign other to temporary
tmp = other_src;
// assign temporary to this
this->operator=(tmp);
return;
}
#endif
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(other_src.dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
_vec_other.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] = other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] = _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] = other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] = other_src.template eval_s<T>(i);
}
#endif
}
}
//----------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------//
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator=(const AbstractTensor<Derived,DIMS> &other) {
#ifndef FASTOR_NO_ALIAS
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR(is_boolean_expression_v<Derived>) {
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] = other_src.template eval_s<T>(i);
}
return;
}
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
_vec_other.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] = other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] = _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] = other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] = other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator+=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator+=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator+=(const AbstractTensor<Derived,DIMS> &other) {
#ifndef FASTOR_NO_ALIAS
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator+=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) + other_src.template eval<T>(i);
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] += other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] += _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] += other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] += other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator-=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator-=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator-=(const AbstractTensor<Derived,DIMS> &other) {
#ifndef FASTOR_NO_ALIAS
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator-=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) - other_src.template eval<T>(i);
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] -= other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] -= _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] -= other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] -= other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator*=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator*=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator*=(const AbstractTensor<Derived,DIMS> &other) {
#ifndef FASTOR_NO_ALIAS
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) * other_src.template eval<T>(i);
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] *= other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] *= _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] *= other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] *= other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator/=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator/=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator/=(const AbstractTensor<Derived,DIMS> &other) {
#ifndef FASTOR_NO_ALIAS
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorFixedViewExpr1D<Tensor<T,N>,fseq<F0,L0,S0>,1>(tmp_this_tensor);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator/=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) / other_src.template eval<T>(i);
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] /= other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] /= _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] /= other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] /= other_src.template eval_s<T>(i);
}
#endif
}
}
//----------------------------------------------------------------------------------//
// Scalar binders
//----------------------------------------------------------------------------------//
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
_vec_other.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] = num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] = _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] = num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] = num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator+=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) + _vec_other;
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] += num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] += _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] += num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] += num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator-=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) - _vec_other;
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] -= num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] -= _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] -= num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] -= num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator*=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) * _vec_other;
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] *= num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] *= _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] *= num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] *= num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U> && !is_integral_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator/=(U num) {
T inum = T(1) / static_cast<T>(num);
simd_vector_type _vec_other(inum);
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) * _vec_other;
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] *= inum;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] *= _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] *= inum;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] *= inum;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U> && is_integral_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator/=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR (S0 == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) / _vec_other;
_vec.store(&_data[i+F0],false);
}
for (; i <size(); i++) {
_data[i+F0] /= num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<SIMDVector<T,simd_abi_type>::Size; ++j) {
_data[S0*(i+j) + F0] /= _vec_other[j];
}
}
for (; i <size(); i++) {
_data[S0*i+F0] /= num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
_data[S0*i+F0] /= num;
}
#endif
}
}
//----------------------------------------------------------------------------------//
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),S0*i+F0,S0);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return _expr.data()[S0*i+F0];
}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),S0*(i+j)+F0,S0);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _expr.data()[S0*(i+j)+F0];
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,1>& as) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),S0*as[0]+F0,S0);
return _vec;
}
template<typename U=T>
constexpr FASTOR_INLINE U teval_s(const std::array<int,1>& as) const {
return _expr.data()[S0*as[0]+F0];
}
};
}
#endif // TENSOR_FIXED_VIEWS_1D_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
#ifndef TENSOR_VIEWS_H
#define TENSOR_VIEWS_H
#include "Fastor/expressions/views/tensor_views_1d.h"
#include "Fastor/expressions/views/tensor_views_2d.h"
#include "Fastor/expressions/views/tensor_views_nd.h"
#include "Fastor/expressions/views/tensor_views_assignment.h"
#endif // TENSOR_VIEWS_H

View File

@@ -0,0 +1,739 @@
#ifndef TENSOR_VIEWS_1D_H
#define TENSOR_VIEWS_1D_H
#include "Fastor/tensor/Tensor.h"
#include "Fastor/tensor/Ranges.h"
#include "Fastor/expressions/linalg_ops/linalg_traits.h"
namespace Fastor {
// 1D const views
//-------------------------------------------------------------------------------------//
template<typename T, size_t N>
struct TensorConstViewExpr<Tensor<T,N>,1>: public AbstractTensor<TensorConstViewExpr<Tensor<T,N>,1>,1> {
private:
const Tensor<T,N> &_expr;
seq _seq;
public:
using scalar_type = T;
using simd_vector_type = typename Tensor<T,N>::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using V = simd_vector_type;
using result_type = Tensor<T,N>;
static constexpr FASTOR_INDEX Dimension = 1;
static constexpr FASTOR_INDEX Stride = simd_vector_type::Size;
static constexpr FASTOR_INDEX rank() {return 1;}
constexpr FASTOR_INLINE FASTOR_INDEX size() const {return _seq.size();}
constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX ) const {return _seq.size();}
constexpr const Tensor<T,N>& expr() const {return _expr;}
FASTOR_INLINE TensorConstViewExpr(const Tensor<T,N> &_ex, const seq &_s) : _expr(_ex), _seq(_s) {
if (_seq._last < 0) _seq._last += N + /*including the end point*/ 1;
if (_seq._first < 0) _seq._first += N + /*including the end point*/ 1;
}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),i*_seq._step+_seq._first,_seq._step);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return _expr.data()[i*_seq._step+_seq._first];
}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),(i+j)*_seq._step+_seq._first,_seq._step);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _expr.data()[(i+j)*_seq._step+_seq._first];
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,1>& as) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),as[0]*_seq._step+_seq._first,_seq._step);
return _vec;
}
template<typename U=T>
constexpr FASTOR_INLINE U teval_s(const std::array<int,1>& as) const {
return _expr.data()[as[0]*_seq._step+_seq._first];
}
};
// 1D non-const views
//-------------------------------------------------------------------------------------//
template<typename T, size_t N>
struct TensorViewExpr<Tensor<T,N>,1>: public AbstractTensor<TensorViewExpr<Tensor<T,N>,1>,1> {
private:
Tensor<T,N> &_expr;
seq _seq;
bool _does_alias = false;
constexpr FASTOR_INLINE Tensor<T,N> get_tensor() const {return _expr;}
public:
using scalar_type = T;
using simd_vector_type = typename Tensor<T,N>::simd_vector_type;
using simd_abi_type = typename simd_vector_type::abi_type;
using V = simd_vector_type;
using result_type = Tensor<T,N>;
static constexpr FASTOR_INDEX Dimension = 1;
static constexpr FASTOR_INDEX Stride = simd_vector_type::Size;
static constexpr FASTOR_INDEX rank() {return 1;}
constexpr FASTOR_INLINE FASTOR_INDEX size() const {return _seq.size();}
constexpr FASTOR_INLINE FASTOR_INDEX dimension(FASTOR_INDEX ) const {return _seq.size();}
constexpr const Tensor<T,N>& expr() const {return _expr;}
FASTOR_INLINE TensorViewExpr<Tensor<T,N>,1>& noalias() {
_does_alias = true;
return *this;
}
FASTOR_INLINE TensorViewExpr(Tensor<T,N> &_ex, const seq &_s) : _expr(_ex), _seq(_s) {
if (_seq._last < 0) _seq._last += N + /*including the end point*/ 1;
if (_seq._first < 0) _seq._first += N + /*including the end point*/ 1;
}
// View evalution operators
// Copy assignment operators [Needed in addition to generic AbstractTensor overload]
//----------------------------------------------------------------------------------//
FASTOR_HINT_INLINE void operator=(const TensorViewExpr<Tensor<T,N>,1> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorViewExpr<Tensor<T,N>,1>(tmp_this_tensor,_seq);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator=(tmp);
return;
}
#endif
#ifndef NDEBUG
FASTOR_ASSERT(other.size()==this->size(), "TENSOR SIZE MISMATCH");
// Check if shape of tensors match - for this 1D case for loop unnecessary
for (FASTOR_INDEX i=0; i<Dimension; ++i) {
FASTOR_ASSERT(other.dimension(i)==dimension(i), "TENSOR SHAPE MISMATCH");
}
#endif
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = other.template eval<T>(i);
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] = other.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other.template eval<T>(i);
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] = _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] = other.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] = other.template eval_s<T>(i);
}
#endif
}
}
//----------------------------------------------------------------------------------//
// AbstractTensor binders
//----------------------------------------------------------------------------------//
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorViewExpr<Tensor<T,N>,1>(tmp_this_tensor,_seq);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
FASTOR_IF_CONSTEXPR(is_boolean_expression_v<Derived>) {
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] = other_src.template eval_s<T>(i);
}
return;
}
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = other_src.template eval<T>(i);
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] = other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] = _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] = other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] = other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator+=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator+=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator+=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorViewExpr<Tensor<T,N>,1>(tmp_this_tensor,_seq);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator+=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) + other_src.template eval<T>(i);
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] += other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] += _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] += other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] += other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator-=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator-=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator-=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorViewExpr<Tensor<T,N>,1>(tmp_this_tensor,_seq);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator-=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) - other_src.template eval<T>(i);
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] -= other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] -= _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] -= other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] -= other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator*=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator*=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator*=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorViewExpr<Tensor<T,N>,1>(tmp_this_tensor,_seq);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator*=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) * other_src.template eval<T>(i);
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] *= other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] *= _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] *= other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] *= other_src.template eval_s<T>(i);
}
#endif
}
}
template<typename Derived, size_t DIMS, enable_if_t_<requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator/=(const AbstractTensor<Derived,DIMS> &other) {
const typename Derived::result_type& tmp = evaluate(other.self());
this->operator/=(tmp);
}
template<typename Derived, size_t DIMS, enable_if_t_<!requires_evaluation_v<Derived>,bool> = false>
FASTOR_HINT_INLINE void operator/=(const AbstractTensor<Derived,DIMS> &other) {
#if !(FASTOR_NO_ALIAS)
if (_does_alias) {
_does_alias = false;
// Evaluate this into a temporary
auto tmp_this_tensor = get_tensor();
auto tmp = TensorViewExpr<Tensor<T,N>,1>(tmp_this_tensor,_seq);
// Assign other to temporary
tmp = other;
// assign temporary to this
this->operator/=(tmp);
return;
}
#endif
const Derived& other_src = other.self();
#ifndef NDEBUG
FASTOR_ASSERT(other_src.size()==this->size(), "TENSOR SIZE MISMATCH");
#endif
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) / other_src.template eval<T>(i);
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] /= other_src.template eval_s<T>(i);
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec_other = other_src.template eval<T>(i);
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] /= _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] /= other_src.template eval_s<T>(i);
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] /= other_src.template eval_s<T>(i);
}
#endif
}
}
//----------------------------------------------------------------------------------//
// scalar binders
//----------------------------------------------------------------------------------//
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
_vec_other.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] = num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] = _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] = num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] = num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator+=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) + _vec_other;
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] += num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] += _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] += num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] += num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator-=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) - _vec_other;
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] -= num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] -= _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] -= num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] -= num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator*=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) * _vec_other;
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] *= num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] *= _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] *= num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] *= num;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U> && !is_integral_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator/=(U num) {
T inum = T(1) / static_cast<T>(num);
simd_vector_type _vec_other(inum);
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) * _vec_other;
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] *= inum;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] *= _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] *= inum;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] *= inum;
}
#endif
}
}
template<typename U=T, enable_if_t_<is_primitive_v_<U> && is_integral_v_<U>,bool> = false>
FASTOR_HINT_INLINE void operator/=(U num) {
simd_vector_type _vec_other(static_cast<T>(num));
T *FASTOR_RESTRICT _data = _expr.data();
if (_seq._step == 1) {
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
auto _vec = this->template eval<T>(i) / _vec_other;
_vec.store(&_data[i+_seq._first],false);
}
for (; i <size(); i++) {
_data[i+_seq._first] /= num;
}
}
else {
#ifdef FASTOR_USE_VECTORISED_EXPR_ASSIGN
FASTOR_INDEX i;
for (i = 0; i <ROUND_DOWN(size(),Stride); i+=Stride) {
for (auto j=0; j<simd_vector_type::Size; ++j) {
auto idx = (i+j)*_seq._step+_seq._first;
_data[idx] /= _vec_other[j];
}
}
for (; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] /= num;
}
#else
for (FASTOR_INDEX i = 0; i <size(); i++) {
auto idx = i*_seq._step+_seq._first;
_data[idx] /= num;
}
#endif
}
}
//----------------------------------------------------------------------------------//
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),i*_seq._step+_seq._first,_seq._step);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i) const {
return _expr.data()[i*_seq._step+_seq._first];
}
template<typename U>
FASTOR_INLINE SIMDVector<U,simd_abi_type> eval(FASTOR_INDEX i, FASTOR_INDEX j) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),(i+j)*_seq._step+_seq._first,_seq._step);
return _vec;
}
template<typename U>
constexpr FASTOR_INLINE U eval_s(FASTOR_INDEX i, FASTOR_INDEX j) const {
return _expr.data()[(i+j)*_seq._step+_seq._first];
}
template<typename U=T>
FASTOR_INLINE SIMDVector<U,simd_abi_type> teval(const std::array<int,1>& as) const {
SIMDVector<U,simd_abi_type> _vec;
vector_setter(_vec,_expr.data(),as[0]*_seq._step+_seq._first,_seq._step);
return _vec;
}
template<typename U=T>
constexpr FASTOR_INLINE U teval_s(const std::array<int,1>& as) const {
return _expr.data()[as[0]*_seq._step+_seq._first];
}
};
} // end of namespace Fastor
#endif // TENSOR_VIEWS_1D_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
#ifndef TENSOR_VIEWS_ASSIGNMENT_H
#define TENSOR_VIEWS_ASSIGNMENT_H
#include "Fastor/expressions/views/tensor_views.h"
#include "Fastor/expressions/views/tensor_fixed_views_1d.h"
#include "Fastor/expressions/views/tensor_fixed_views_2d.h"
#include "Fastor/expressions/views/tensor_random_views.h"
namespace Fastor {
#define FASTOR_MAKE_ALL_TENSOR_VIEWS_ASSIGNMENT(ASSIGN_TYPE)\
template<typename Derived, size_t DIM, typename TensorType, typename Seq>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorConstFixedViewExpr1D<TensorType,Seq,1>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename Seq>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorFixedViewExpr1D<TensorType,Seq,1>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename Seq0, typename Seq1>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorConstFixedViewExpr2D<TensorType,Seq0,Seq1,2>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename Seq0, typename Seq1>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorFixedViewExpr2D<TensorType,Seq0,Seq1,2>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename ... Fseq>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorConstFixedViewExprnD<TensorType,Fseq...>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename ... Fseq>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorFixedViewExprnD<TensorType,Fseq...>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, size_t OtherDIM>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorConstViewExpr<TensorType,OtherDIM>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, size_t OtherDIM>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorViewExpr<TensorType,OtherDIM>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename TensorIndexType>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorConstRandomViewExpr<TensorType,TensorIndexType,DIM>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename TensorIndexType>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorRandomViewExpr<TensorType,TensorIndexType,DIM>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, typename TensorIndexType>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorFilterViewExpr<TensorType,TensorIndexType,DIM>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
template<typename Derived, size_t DIM, typename TensorType, size_t OtherDIM>\
FASTOR_INLINE void assign ##ASSIGN_TYPE (AbstractTensor<Derived,DIM> &dst, const TensorDiagViewExpr<TensorType,OtherDIM>& src) {\
trivial_assign ##ASSIGN_TYPE (dst.self(), src.self());\
}\
FASTOR_MAKE_ALL_TENSOR_VIEWS_ASSIGNMENT( )
FASTOR_MAKE_ALL_TENSOR_VIEWS_ASSIGNMENT(_add)
FASTOR_MAKE_ALL_TENSOR_VIEWS_ASSIGNMENT(_sub)
FASTOR_MAKE_ALL_TENSOR_VIEWS_ASSIGNMENT(_mul)
FASTOR_MAKE_ALL_TENSOR_VIEWS_ASSIGNMENT(_div)
} // end of namespace Fastor
#endif // TENSOR_VIEWS_ASSIGNMENT_H

File diff suppressed because it is too large Load Diff