Add Fastor library
This commit is contained in:
247
noarch/include/Fastor/expressions/binary_ops/binary_add_op.h
Normal file
247
noarch/include/Fastor/expressions/binary_ops/binary_add_op.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
262
noarch/include/Fastor/expressions/binary_ops/binary_cmp_ops.h
Normal file
262
noarch/include/Fastor/expressions/binary_ops/binary_cmp_ops.h
Normal 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
|
||||
306
noarch/include/Fastor/expressions/binary_ops/binary_div_op.h
Normal file
306
noarch/include/Fastor/expressions/binary_ops/binary_div_op.h
Normal 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
|
||||
|
||||
261
noarch/include/Fastor/expressions/binary_ops/binary_math_ops.h
Normal file
261
noarch/include/Fastor/expressions/binary_ops/binary_math_ops.h
Normal 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
|
||||
245
noarch/include/Fastor/expressions/binary_ops/binary_mul_op.h
Normal file
245
noarch/include/Fastor/expressions/binary_ops/binary_mul_op.h
Normal 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
|
||||
|
||||
246
noarch/include/Fastor/expressions/binary_ops/binary_sub_op.h
Normal file
246
noarch/include/Fastor/expressions/binary_ops/binary_sub_op.h
Normal 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
|
||||
|
||||
327
noarch/include/Fastor/expressions/expression_traits.h
Normal file
327
noarch/include/Fastor/expressions/expression_traits.h
Normal 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
|
||||
27
noarch/include/Fastor/expressions/expressions.h
Normal file
27
noarch/include/Fastor/expressions/expressions.h
Normal 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
|
||||
|
||||
191
noarch/include/Fastor/expressions/linalg_ops/binary_cross_op.h
Normal file
191
noarch/include/Fastor/expressions/linalg_ops/binary_cross_op.h
Normal 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
|
||||
627
noarch/include/Fastor/expressions/linalg_ops/binary_matmul_op.h
Normal file
627
noarch/include/Fastor/expressions/linalg_ops/binary_matmul_op.h
Normal 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
|
||||
197
noarch/include/Fastor/expressions/linalg_ops/binary_solve_op.h
Normal file
197
noarch/include/Fastor/expressions/linalg_ops/binary_solve_op.h
Normal 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
|
||||
@@ -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
|
||||
24
noarch/include/Fastor/expressions/linalg_ops/linalg_ops.h
Normal file
24
noarch/include/Fastor/expressions/linalg_ops/linalg_ops.h
Normal 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
|
||||
273
noarch/include/Fastor/expressions/linalg_ops/linalg_traits.h
Normal file
273
noarch/include/Fastor/expressions/linalg_ops/linalg_traits.h
Normal 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
|
||||
160
noarch/include/Fastor/expressions/linalg_ops/unary_adj_op.h
Normal file
160
noarch/include/Fastor/expressions/linalg_ops/unary_adj_op.h
Normal 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
|
||||
160
noarch/include/Fastor/expressions/linalg_ops/unary_cof_op.h
Normal file
160
noarch/include/Fastor/expressions/linalg_ops/unary_cof_op.h
Normal 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
|
||||
178
noarch/include/Fastor/expressions/linalg_ops/unary_ctrans_op.h
Normal file
178
noarch/include/Fastor/expressions/linalg_ops/unary_ctrans_op.h
Normal 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
|
||||
86
noarch/include/Fastor/expressions/linalg_ops/unary_det_op.h
Normal file
86
noarch/include/Fastor/expressions/linalg_ops/unary_det_op.h
Normal 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
|
||||
731
noarch/include/Fastor/expressions/linalg_ops/unary_inv_op.h
Normal file
731
noarch/include/Fastor/expressions/linalg_ops/unary_inv_op.h
Normal 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
|
||||
970
noarch/include/Fastor/expressions/linalg_ops/unary_lu_op.h
Normal file
970
noarch/include/Fastor/expressions/linalg_ops/unary_lu_op.h
Normal 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
|
||||
106
noarch/include/Fastor/expressions/linalg_ops/unary_norm_op.h
Normal file
106
noarch/include/Fastor/expressions/linalg_ops/unary_norm_op.h
Normal 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
|
||||
409
noarch/include/Fastor/expressions/linalg_ops/unary_piv_op.h
Normal file
409
noarch/include/Fastor/expressions/linalg_ops/unary_piv_op.h
Normal 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,©A.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,©A.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(©A.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(©A.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(©A.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(©A.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,©A.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
|
||||
198
noarch/include/Fastor/expressions/linalg_ops/unary_qr_op.h
Normal file
198
noarch/include/Fastor/expressions/linalg_ops/unary_qr_op.h
Normal 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
|
||||
Gram–Schmidt 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
|
||||
163
noarch/include/Fastor/expressions/linalg_ops/unary_svd_op.h
Normal file
163
noarch/include/Fastor/expressions/linalg_ops/unary_svd_op.h
Normal 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
|
||||
@@ -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
|
||||
173
noarch/include/Fastor/expressions/linalg_ops/unary_trans_op.h
Normal file
173
noarch/include/Fastor/expressions/linalg_ops/unary_trans_op.h
Normal 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
|
||||
101
noarch/include/Fastor/expressions/unary_ops/unary_bool_ops.h
Normal file
101
noarch/include/Fastor/expressions/unary_ops/unary_bool_ops.h
Normal 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
|
||||
|
||||
209
noarch/include/Fastor/expressions/unary_ops/unary_math_ops.h
Normal file
209
noarch/include/Fastor/expressions/unary_ops/unary_math_ops.h
Normal 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
|
||||
|
||||
317
noarch/include/Fastor/expressions/views/tensor_diag_views.h
Normal file
317
noarch/include/Fastor/expressions/views/tensor_diag_views.h
Normal 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
|
||||
281
noarch/include/Fastor/expressions/views/tensor_filter_views.h
Normal file
281
noarch/include/Fastor/expressions/views/tensor_filter_views.h
Normal 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
|
||||
681
noarch/include/Fastor/expressions/views/tensor_fixed_views_1d.h
Normal file
681
noarch/include/Fastor/expressions/views/tensor_fixed_views_1d.h
Normal 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
|
||||
1121
noarch/include/Fastor/expressions/views/tensor_fixed_views_2d.h
Normal file
1121
noarch/include/Fastor/expressions/views/tensor_fixed_views_2d.h
Normal file
File diff suppressed because it is too large
Load Diff
1645
noarch/include/Fastor/expressions/views/tensor_fixed_views_nd.h
Normal file
1645
noarch/include/Fastor/expressions/views/tensor_fixed_views_nd.h
Normal file
File diff suppressed because it is too large
Load Diff
1152
noarch/include/Fastor/expressions/views/tensor_random_views.h
Normal file
1152
noarch/include/Fastor/expressions/views/tensor_random_views.h
Normal file
File diff suppressed because it is too large
Load Diff
10
noarch/include/Fastor/expressions/views/tensor_views.h
Normal file
10
noarch/include/Fastor/expressions/views/tensor_views.h
Normal 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
|
||||
739
noarch/include/Fastor/expressions/views/tensor_views_1d.h
Normal file
739
noarch/include/Fastor/expressions/views/tensor_views_1d.h
Normal 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
|
||||
1163
noarch/include/Fastor/expressions/views/tensor_views_2d.h
Normal file
1163
noarch/include/Fastor/expressions/views/tensor_views_2d.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
1680
noarch/include/Fastor/expressions/views/tensor_views_nd.h
Normal file
1680
noarch/include/Fastor/expressions/views/tensor_views_nd.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user