Simplify redux_evaluator using inheritance, and properly rename parameters in reducers.

This commit is contained in:
Gael Guennebaud 2018-07-02 11:50:41 +02:00
parent d428a199ab
commit d625564936

View File

@ -23,22 +23,22 @@ namespace internal {
* Part 1 : the logic deciding a strategy for vectorization and unrolling * Part 1 : the logic deciding a strategy for vectorization and unrolling
***************************************************************************/ ***************************************************************************/
template<typename Func, typename Derived> template<typename Func, typename Evaluator>
struct redux_traits struct redux_traits
{ {
public: public:
typedef typename find_best_packet<typename Derived::Scalar,Derived::SizeAtCompileTime>::type PacketType; typedef typename find_best_packet<typename Evaluator::Scalar,Evaluator::SizeAtCompileTime>::type PacketType;
enum { enum {
PacketSize = unpacket_traits<PacketType>::size, PacketSize = unpacket_traits<PacketType>::size,
InnerMaxSize = int(Derived::IsRowMajor) InnerMaxSize = int(Evaluator::IsRowMajor)
? Derived::MaxColsAtCompileTime ? Evaluator::MaxColsAtCompileTime
: Derived::MaxRowsAtCompileTime : Evaluator::MaxRowsAtCompileTime
}; };
enum { enum {
MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) MightVectorize = (int(Evaluator::Flags)&ActualPacketAccessBit)
&& (functor_traits<Func>::PacketAccess), && (functor_traits<Func>::PacketAccess),
MayLinearVectorize = bool(MightVectorize) && (int(Derived::Flags)&LinearAccessBit), MayLinearVectorize = bool(MightVectorize) && (int(Evaluator::Flags)&LinearAccessBit),
MaySliceVectorize = bool(MightVectorize) && int(InnerMaxSize)>=3*PacketSize MaySliceVectorize = bool(MightVectorize) && int(InnerMaxSize)>=3*PacketSize
}; };
@ -51,8 +51,8 @@ public:
public: public:
enum { enum {
Cost = Derived::SizeAtCompileTime == Dynamic ? HugeCost Cost = Evaluator::SizeAtCompileTime == Dynamic ? HugeCost
: Derived::SizeAtCompileTime * Derived::CoeffReadCost + (Derived::SizeAtCompileTime-1) * functor_traits<Func>::Cost, : Evaluator::SizeAtCompileTime * Evaluator::CoeffReadCost + (Evaluator::SizeAtCompileTime-1) * functor_traits<Func>::Cost,
UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize))
}; };
@ -64,9 +64,9 @@ public:
#ifdef EIGEN_DEBUG_ASSIGN #ifdef EIGEN_DEBUG_ASSIGN
static void debug() static void debug()
{ {
std::cerr << "Xpr: " << typeid(typename Derived::XprType).name() << std::endl; std::cerr << "Xpr: " << typeid(typename Evaluator::XprType).name() << std::endl;
std::cerr.setf(std::ios::hex, std::ios::basefield); std::cerr.setf(std::ios::hex, std::ios::basefield);
EIGEN_DEBUG_VAR(Derived::Flags) EIGEN_DEBUG_VAR(Evaluator::Flags)
std::cerr.unsetf(std::ios::hex); std::cerr.unsetf(std::ios::hex);
EIGEN_DEBUG_VAR(InnerMaxSize) EIGEN_DEBUG_VAR(InnerMaxSize)
EIGEN_DEBUG_VAR(PacketSize) EIGEN_DEBUG_VAR(PacketSize)
@ -87,88 +87,88 @@ public:
/*** no vectorization ***/ /*** no vectorization ***/
template<typename Func, typename Derived, int Start, int Length> template<typename Func, typename Evaluator, int Start, int Length>
struct redux_novec_unroller struct redux_novec_unroller
{ {
enum { enum {
HalfLength = Length/2 HalfLength = Length/2
}; };
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
EIGEN_DEVICE_FUNC EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) static EIGEN_STRONG_INLINE Scalar run(const Evaluator &eval, const Func& func)
{ {
return func(redux_novec_unroller<Func, Derived, Start, HalfLength>::run(mat,func), return func(redux_novec_unroller<Func, Evaluator, Start, HalfLength>::run(eval,func),
redux_novec_unroller<Func, Derived, Start+HalfLength, Length-HalfLength>::run(mat,func)); redux_novec_unroller<Func, Evaluator, Start+HalfLength, Length-HalfLength>::run(eval,func));
} }
}; };
template<typename Func, typename Derived, int Start> template<typename Func, typename Evaluator, int Start>
struct redux_novec_unroller<Func, Derived, Start, 1> struct redux_novec_unroller<Func, Evaluator, Start, 1>
{ {
enum { enum {
outer = Start / Derived::InnerSizeAtCompileTime, outer = Start / Evaluator::InnerSizeAtCompileTime,
inner = Start % Derived::InnerSizeAtCompileTime inner = Start % Evaluator::InnerSizeAtCompileTime
}; };
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
EIGEN_DEVICE_FUNC EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) static EIGEN_STRONG_INLINE Scalar run(const Evaluator &eval, const Func&)
{ {
return mat.coeffByOuterInner(outer, inner); return eval.coeffByOuterInner(outer, inner);
} }
}; };
// This is actually dead code and will never be called. It is required // This is actually dead code and will never be called. It is required
// to prevent false warnings regarding failed inlining though // to prevent false warnings regarding failed inlining though
// for 0 length run() will never be called at all. // for 0 length run() will never be called at all.
template<typename Func, typename Derived, int Start> template<typename Func, typename Evaluator, int Start>
struct redux_novec_unroller<Func, Derived, Start, 0> struct redux_novec_unroller<Func, Evaluator, Start, 0>
{ {
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
EIGEN_DEVICE_FUNC EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } static EIGEN_STRONG_INLINE Scalar run(const Evaluator&, const Func&) { return Scalar(); }
}; };
/*** vectorization ***/ /*** vectorization ***/
template<typename Func, typename Derived, int Start, int Length> template<typename Func, typename Evaluator, int Start, int Length>
struct redux_vec_unroller struct redux_vec_unroller
{ {
enum { enum {
PacketSize = redux_traits<Func, Derived>::PacketSize, PacketSize = redux_traits<Func, Evaluator>::PacketSize,
HalfLength = Length/2 HalfLength = Length/2
}; };
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
typedef typename redux_traits<Func, Derived>::PacketType PacketScalar; typedef typename redux_traits<Func, Evaluator>::PacketType PacketScalar;
static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func) static EIGEN_STRONG_INLINE PacketScalar run(const Evaluator &eval, const Func& func)
{ {
return func.packetOp( return func.packetOp(
redux_vec_unroller<Func, Derived, Start, HalfLength>::run(mat,func), redux_vec_unroller<Func, Evaluator, Start, HalfLength>::run(eval,func),
redux_vec_unroller<Func, Derived, Start+HalfLength, Length-HalfLength>::run(mat,func) ); redux_vec_unroller<Func, Evaluator, Start+HalfLength, Length-HalfLength>::run(eval,func) );
} }
}; };
template<typename Func, typename Derived, int Start> template<typename Func, typename Evaluator, int Start>
struct redux_vec_unroller<Func, Derived, Start, 1> struct redux_vec_unroller<Func, Evaluator, Start, 1>
{ {
enum { enum {
index = Start * redux_traits<Func, Derived>::PacketSize, index = Start * redux_traits<Func, Evaluator>::PacketSize,
outer = index / int(Derived::InnerSizeAtCompileTime), outer = index / int(Evaluator::InnerSizeAtCompileTime),
inner = index % int(Derived::InnerSizeAtCompileTime), inner = index % int(Evaluator::InnerSizeAtCompileTime),
alignment = Derived::Alignment alignment = Evaluator::Alignment
}; };
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
typedef typename redux_traits<Func, Derived>::PacketType PacketScalar; typedef typename redux_traits<Func, Evaluator>::PacketType PacketScalar;
static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) static EIGEN_STRONG_INLINE PacketScalar run(const Evaluator &eval, const Func&)
{ {
return mat.template packetByOuterInner<alignment,PacketScalar>(outer, inner); return eval.template packetByOuterInner<alignment,PacketScalar>(outer, inner);
} }
}; };
@ -176,53 +176,54 @@ struct redux_vec_unroller<Func, Derived, Start, 1>
* Part 3 : implementation of all cases * Part 3 : implementation of all cases
***************************************************************************/ ***************************************************************************/
template<typename Func, typename Derived, template<typename Func, typename Evaluator,
int Traversal = redux_traits<Func, Derived>::Traversal, int Traversal = redux_traits<Func, Evaluator>::Traversal,
int Unrolling = redux_traits<Func, Derived>::Unrolling int Unrolling = redux_traits<Func, Evaluator>::Unrolling
> >
struct redux_impl; struct redux_impl;
template<typename Func, typename Derived> template<typename Func, typename Evaluator>
struct redux_impl<Func, Derived, DefaultTraversal, NoUnrolling> struct redux_impl<Func, Evaluator, DefaultTraversal, NoUnrolling>
{ {
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE
Scalar run(const Evaluator &eval, const Func& func)
{ {
eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); eigen_assert(eval.rows()>0 && eval.cols()>0 && "you are using an empty matrix");
Scalar res; Scalar res;
res = mat.coeffByOuterInner(0, 0); res = eval.coeffByOuterInner(0, 0);
for(Index i = 1; i < mat.innerSize(); ++i) for(Index i = 1; i < eval.innerSize(); ++i)
res = func(res, mat.coeffByOuterInner(0, i)); res = func(res, eval.coeffByOuterInner(0, i));
for(Index i = 1; i < mat.outerSize(); ++i) for(Index i = 1; i < eval.outerSize(); ++i)
for(Index j = 0; j < mat.innerSize(); ++j) for(Index j = 0; j < eval.innerSize(); ++j)
res = func(res, mat.coeffByOuterInner(i, j)); res = func(res, eval.coeffByOuterInner(i, j));
return res; return res;
} }
}; };
template<typename Func, typename Derived> template<typename Func, typename Evaluator>
struct redux_impl<Func,Derived, DefaultTraversal, CompleteUnrolling> struct redux_impl<Func,Evaluator, DefaultTraversal, CompleteUnrolling>
: public redux_novec_unroller<Func,Derived, 0, Derived::SizeAtCompileTime> : redux_novec_unroller<Func,Evaluator, 0, Evaluator::SizeAtCompileTime>
{}; {};
template<typename Func, typename Derived> template<typename Func, typename Evaluator>
struct redux_impl<Func, Derived, LinearVectorizedTraversal, NoUnrolling> struct redux_impl<Func, Evaluator, LinearVectorizedTraversal, NoUnrolling>
{ {
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
typedef typename redux_traits<Func, Derived>::PacketType PacketScalar; typedef typename redux_traits<Func, Evaluator>::PacketType PacketScalar;
static Scalar run(const Derived &mat, const Func& func) static Scalar run(const Evaluator &eval, const Func& func)
{ {
const Index size = mat.size(); const Index size = eval.size();
const Index packetSize = redux_traits<Func, Derived>::PacketSize; const Index packetSize = redux_traits<Func, Evaluator>::PacketSize;
const int packetAlignment = unpacket_traits<PacketScalar>::alignment; const int packetAlignment = unpacket_traits<PacketScalar>::alignment;
enum { enum {
alignment0 = (bool(Derived::Flags & DirectAccessBit) && bool(packet_traits<Scalar>::AlignedOnScalar)) ? int(packetAlignment) : int(Unaligned), alignment0 = (bool(Evaluator::Flags & DirectAccessBit) && bool(packet_traits<Scalar>::AlignedOnScalar)) ? int(packetAlignment) : int(Unaligned),
alignment = EIGEN_PLAIN_ENUM_MAX(alignment0, Derived::Alignment) alignment = EIGEN_PLAIN_ENUM_MAX(alignment0, Evaluator::Alignment)
}; };
const Index alignedStart = internal::first_default_aligned(mat.nestedExpression()); const Index alignedStart = internal::first_default_aligned(eval.nestedExpression());
const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize);
const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize);
const Index alignedEnd2 = alignedStart + alignedSize2; const Index alignedEnd2 = alignedStart + alignedSize2;
@ -230,34 +231,34 @@ struct redux_impl<Func, Derived, LinearVectorizedTraversal, NoUnrolling>
Scalar res; Scalar res;
if(alignedSize) if(alignedSize)
{ {
PacketScalar packet_res0 = mat.template packet<alignment,PacketScalar>(alignedStart); PacketScalar packet_res0 = eval.template packet<alignment,PacketScalar>(alignedStart);
if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop
{ {
PacketScalar packet_res1 = mat.template packet<alignment,PacketScalar>(alignedStart+packetSize); PacketScalar packet_res1 = eval.template packet<alignment,PacketScalar>(alignedStart+packetSize);
for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize)
{ {
packet_res0 = func.packetOp(packet_res0, mat.template packet<alignment,PacketScalar>(index)); packet_res0 = func.packetOp(packet_res0, eval.template packet<alignment,PacketScalar>(index));
packet_res1 = func.packetOp(packet_res1, mat.template packet<alignment,PacketScalar>(index+packetSize)); packet_res1 = func.packetOp(packet_res1, eval.template packet<alignment,PacketScalar>(index+packetSize));
} }
packet_res0 = func.packetOp(packet_res0,packet_res1); packet_res0 = func.packetOp(packet_res0,packet_res1);
if(alignedEnd>alignedEnd2) if(alignedEnd>alignedEnd2)
packet_res0 = func.packetOp(packet_res0, mat.template packet<alignment,PacketScalar>(alignedEnd2)); packet_res0 = func.packetOp(packet_res0, eval.template packet<alignment,PacketScalar>(alignedEnd2));
} }
res = func.predux(packet_res0); res = func.predux(packet_res0);
for(Index index = 0; index < alignedStart; ++index) for(Index index = 0; index < alignedStart; ++index)
res = func(res,mat.coeff(index)); res = func(res,eval.coeff(index));
for(Index index = alignedEnd; index < size; ++index) for(Index index = alignedEnd; index < size; ++index)
res = func(res,mat.coeff(index)); res = func(res,eval.coeff(index));
} }
else // too small to vectorize anything. else // too small to vectorize anything.
// since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize. // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize.
{ {
res = mat.coeff(0); res = eval.coeff(0);
for(Index index = 1; index < size; ++index) for(Index index = 1; index < size; ++index)
res = func(res,mat.coeff(index)); res = func(res,eval.coeff(index));
} }
return res; return res;
@ -265,77 +266,80 @@ struct redux_impl<Func, Derived, LinearVectorizedTraversal, NoUnrolling>
}; };
// NOTE: for SliceVectorizedTraversal we simply bypass unrolling // NOTE: for SliceVectorizedTraversal we simply bypass unrolling
template<typename Func, typename Derived, int Unrolling> template<typename Func, typename Evaluator, int Unrolling>
struct redux_impl<Func, Derived, SliceVectorizedTraversal, Unrolling> struct redux_impl<Func, Evaluator, SliceVectorizedTraversal, Unrolling>
{ {
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
typedef typename redux_traits<Func, Derived>::PacketType PacketType; typedef typename redux_traits<Func, Evaluator>::PacketType PacketType;
EIGEN_DEVICE_FUNC static Scalar run(const Derived &mat, const Func& func) EIGEN_DEVICE_FUNC static Scalar run(const Evaluator &eval, const Func& func)
{ {
eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); eigen_assert(eval.rows()>0 && eval.cols()>0 && "you are using an empty matrix");
const Index innerSize = mat.innerSize(); const Index innerSize = eval.innerSize();
const Index outerSize = mat.outerSize(); const Index outerSize = eval.outerSize();
enum { enum {
packetSize = redux_traits<Func, Derived>::PacketSize packetSize = redux_traits<Func, Evaluator>::PacketSize
}; };
const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize;
Scalar res; Scalar res;
if(packetedInnerSize) if(packetedInnerSize)
{ {
PacketType packet_res = mat.template packet<Unaligned,PacketType>(0,0); PacketType packet_res = eval.template packet<Unaligned,PacketType>(0,0);
for(Index j=0; j<outerSize; ++j) for(Index j=0; j<outerSize; ++j)
for(Index i=(j==0?packetSize:0); i<packetedInnerSize; i+=Index(packetSize)) for(Index i=(j==0?packetSize:0); i<packetedInnerSize; i+=Index(packetSize))
packet_res = func.packetOp(packet_res, mat.template packetByOuterInner<Unaligned,PacketType>(j,i)); packet_res = func.packetOp(packet_res, eval.template packetByOuterInner<Unaligned,PacketType>(j,i));
res = func.predux(packet_res); res = func.predux(packet_res);
for(Index j=0; j<outerSize; ++j) for(Index j=0; j<outerSize; ++j)
for(Index i=packetedInnerSize; i<innerSize; ++i) for(Index i=packetedInnerSize; i<innerSize; ++i)
res = func(res, mat.coeffByOuterInner(j,i)); res = func(res, eval.coeffByOuterInner(j,i));
} }
else // too small to vectorize anything. else // too small to vectorize anything.
// since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize. // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize.
{ {
res = redux_impl<Func, Derived, DefaultTraversal, NoUnrolling>::run(mat, func); res = redux_impl<Func, Evaluator, DefaultTraversal, NoUnrolling>::run(eval, func);
} }
return res; return res;
} }
}; };
template<typename Func, typename Derived> template<typename Func, typename Evaluator>
struct redux_impl<Func, Derived, LinearVectorizedTraversal, CompleteUnrolling> struct redux_impl<Func, Evaluator, LinearVectorizedTraversal, CompleteUnrolling>
{ {
typedef typename Derived::Scalar Scalar; typedef typename Evaluator::Scalar Scalar;
typedef typename redux_traits<Func, Derived>::PacketType PacketScalar; typedef typename redux_traits<Func, Evaluator>::PacketType PacketScalar;
enum { enum {
PacketSize = redux_traits<Func, Derived>::PacketSize, PacketSize = redux_traits<Func, Evaluator>::PacketSize,
Size = Derived::SizeAtCompileTime, Size = Evaluator::SizeAtCompileTime,
VectorizedSize = (Size / PacketSize) * PacketSize VectorizedSize = (Size / PacketSize) * PacketSize
}; };
EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func)
EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE
Scalar run(const Evaluator &eval, const Func& func)
{ {
eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); eigen_assert(eval.rows()>0 && eval.cols()>0 && "you are using an empty matrix");
if (VectorizedSize > 0) { if (VectorizedSize > 0) {
Scalar res = func.predux(redux_vec_unroller<Func, Derived, 0, Size / PacketSize>::run(mat,func)); Scalar res = func.predux(redux_vec_unroller<Func, Evaluator, 0, Size / PacketSize>::run(eval,func));
if (VectorizedSize != Size) if (VectorizedSize != Size)
res = func(res,redux_novec_unroller<Func, Derived, VectorizedSize, Size-VectorizedSize>::run(mat,func)); res = func(res,redux_novec_unroller<Func, Evaluator, VectorizedSize, Size-VectorizedSize>::run(eval,func));
return res; return res;
} }
else { else {
return redux_novec_unroller<Func, Derived, 0, Size>::run(mat,func); return redux_novec_unroller<Func, Evaluator, 0, Size>::run(eval,func);
} }
} }
}; };
// evaluator adaptor // evaluator adaptor
template<typename _XprType> template<typename _XprType>
class redux_evaluator class redux_evaluator : public internal::evaluator<_XprType>
{ {
typedef internal::evaluator<_XprType> Base;
public: public:
typedef _XprType XprType; typedef _XprType XprType;
EIGEN_DEVICE_FUNC explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} EIGEN_DEVICE_FUNC explicit redux_evaluator(const XprType &xpr) : Base(xpr), m_xpr(xpr) {}
typedef typename XprType::Scalar Scalar; typedef typename XprType::Scalar Scalar;
typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::CoeffReturnType CoeffReturnType;
@ -346,12 +350,10 @@ public:
MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime,
MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, MaxColsAtCompileTime = XprType::MaxColsAtCompileTime,
// TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator
Flags = evaluator<XprType>::Flags & ~DirectAccessBit, Flags = Base::Flags & ~DirectAccessBit,
IsRowMajor = XprType::IsRowMajor, IsRowMajor = XprType::IsRowMajor,
SizeAtCompileTime = XprType::SizeAtCompileTime, SizeAtCompileTime = XprType::SizeAtCompileTime,
InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime
CoeffReadCost = evaluator<XprType>::CoeffReadCost,
Alignment = evaluator<XprType>::Alignment
}; };
EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); }
@ -360,34 +362,17 @@ public:
EIGEN_DEVICE_FUNC Index innerSize() const { return m_xpr.innerSize(); } EIGEN_DEVICE_FUNC Index innerSize() const { return m_xpr.innerSize(); }
EIGEN_DEVICE_FUNC Index outerSize() const { return m_xpr.outerSize(); } EIGEN_DEVICE_FUNC Index outerSize() const { return m_xpr.outerSize(); }
EIGEN_DEVICE_FUNC
CoeffReturnType coeff(Index row, Index col) const
{ return m_evaluator.coeff(row, col); }
EIGEN_DEVICE_FUNC
CoeffReturnType coeff(Index index) const
{ return m_evaluator.coeff(index); }
template<int LoadMode, typename PacketType>
PacketType packet(Index row, Index col) const
{ return m_evaluator.template packet<LoadMode,PacketType>(row, col); }
template<int LoadMode, typename PacketType>
PacketType packet(Index index) const
{ return m_evaluator.template packet<LoadMode,PacketType>(index); }
EIGEN_DEVICE_FUNC EIGEN_DEVICE_FUNC
CoeffReturnType coeffByOuterInner(Index outer, Index inner) const CoeffReturnType coeffByOuterInner(Index outer, Index inner) const
{ return m_evaluator.coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } { return Base::coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); }
template<int LoadMode, typename PacketType> template<int LoadMode, typename PacketType>
PacketType packetByOuterInner(Index outer, Index inner) const PacketType packetByOuterInner(Index outer, Index inner) const
{ return m_evaluator.template packet<LoadMode,PacketType>(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } { return Base::template packet<LoadMode,PacketType>(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); }
const XprType & nestedExpression() const { return m_xpr; } const XprType & nestedExpression() const { return m_xpr; }
protected: protected:
internal::evaluator<XprType> m_evaluator;
const XprType &m_xpr; const XprType &m_xpr;
}; };