Refactoring of the cost model:

- Dynamic is now an invalid value
 - introduce a HugeCost constant to be used for runtime-cost values or arbitrarily huge cost
 - add sanity checks for cost values: must be >=0 and not too large
This change provides several benefits:
 - it fixes shortcoming is some cost computation where the Dynamic case was not properly handled.
 - it simplifies cost computation logic, and should avoid future similar shortcomings.
 - it allows to distinguish between different level of dynamic/huge/infinite cost
 - it should enable further simplifications in the computation of costs (save compilation time)
This commit is contained in:
Gael Guennebaud 2015-10-28 11:42:14 +01:00
parent 827d8a9bad
commit 77ff3386b7
22 changed files with 139 additions and 68 deletions

View File

@ -98,10 +98,10 @@ private:
enum { enum {
UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1),
MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic
&& int(SrcEvaluator::CoeffReadCost) != Dynamic && int(SrcEvaluator::CoeffReadCost) < HugeCost
&& int(Dst::SizeAtCompileTime) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit), && int(Dst::SizeAtCompileTime) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit),
MayUnrollInner = int(InnerSize) != Dynamic MayUnrollInner = int(InnerSize) != Dynamic
&& int(SrcEvaluator::CoeffReadCost) != Dynamic && int(SrcEvaluator::CoeffReadCost) < HugeCost
&& int(InnerSize) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit) && int(InnerSize) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit)
}; };

View File

@ -83,8 +83,8 @@ inline bool DenseBase<Derived>::all() const
typedef internal::evaluator<Derived> Evaluator; typedef internal::evaluator<Derived> Evaluator;
enum { enum {
unroll = SizeAtCompileTime != Dynamic unroll = SizeAtCompileTime != Dynamic
&& Evaluator::CoeffReadCost != Dynamic && Evaluator::CoeffReadCost < HugeCost
&& NumTraits<Scalar>::AddCost != Dynamic && NumTraits<Scalar>::AddCost < HugeCost
&& SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits<Scalar>::AddCost) <= EIGEN_UNROLLING_LIMIT && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits<Scalar>::AddCost) <= EIGEN_UNROLLING_LIMIT
}; };
Evaluator evaluator(derived()); Evaluator evaluator(derived());
@ -109,8 +109,8 @@ inline bool DenseBase<Derived>::any() const
typedef internal::evaluator<Derived> Evaluator; typedef internal::evaluator<Derived> Evaluator;
enum { enum {
unroll = SizeAtCompileTime != Dynamic unroll = SizeAtCompileTime != Dynamic
&& Evaluator::CoeffReadCost != Dynamic && Evaluator::CoeffReadCost < HugeCost
&& NumTraits<Scalar>::AddCost != Dynamic && NumTraits<Scalar>::AddCost < HugeCost
&& SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits<Scalar>::AddCost) <= EIGEN_UNROLLING_LIMIT && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits<Scalar>::AddCost) <= EIGEN_UNROLLING_LIMIT
}; };
Evaluator evaluator(derived()); Evaluator evaluator(derived());

View File

@ -137,11 +137,15 @@ struct evaluator<PlainObjectBase<Derived> >
m_outerStride(IsVectorAtCompileTime ? 0 m_outerStride(IsVectorAtCompileTime ? 0
: int(IsRowMajor) ? ColsAtCompileTime : int(IsRowMajor) ? ColsAtCompileTime
: RowsAtCompileTime) : RowsAtCompileTime)
{} {
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
EIGEN_DEVICE_FUNC explicit evaluator(const PlainObjectType& m) EIGEN_DEVICE_FUNC explicit evaluator(const PlainObjectType& m)
: m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const
{ {
@ -327,7 +331,9 @@ struct evaluator<CwiseNullaryOp<NullaryOp,PlainObjectType> >
EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n) EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n)
: m_functor(n.functor()) : m_functor(n.functor())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::CoeffReturnType CoeffReturnType;
@ -376,7 +382,10 @@ struct unary_evaluator<CwiseUnaryOp<UnaryOp, ArgType>, IndexBased >
EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op)
: m_functor(op.functor()), : m_functor(op.functor()),
m_argImpl(op.nestedExpression()) m_argImpl(op.nestedExpression())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<UnaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::CoeffReturnType CoeffReturnType;
@ -449,7 +458,10 @@ struct binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>, IndexBased, IndexBase
: m_functor(xpr.functor()), : m_functor(xpr.functor()),
m_lhsImpl(xpr.lhs()), m_lhsImpl(xpr.lhs()),
m_rhsImpl(xpr.rhs()) m_rhsImpl(xpr.rhs())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::CoeffReturnType CoeffReturnType;
@ -502,7 +514,10 @@ struct unary_evaluator<CwiseUnaryView<UnaryOp, ArgType>, IndexBased>
EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op)
: m_unaryOp(op.functor()), : m_unaryOp(op.functor()),
m_argImpl(op.nestedExpression()) m_argImpl(op.nestedExpression())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<UnaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
typedef typename XprType::Scalar Scalar; typedef typename XprType::Scalar Scalar;
typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::CoeffReturnType CoeffReturnType;
@ -559,6 +574,7 @@ struct mapbase_evaluator : evaluator_base<Derived>
{ {
EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator<Derived>::Flags&PacketAccessBit, internal::inner_stride_at_compile_time<Derived>::ret==1), EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator<Derived>::Flags&PacketAccessBit, internal::inner_stride_at_compile_time<Derived>::ret==1),
PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
} }
EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const
@ -713,7 +729,10 @@ struct evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel> >
Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator<ArgType>::Alignment, Alignment0) Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator<ArgType>::Alignment, Alignment0)
}; };
typedef block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel> block_evaluator_type; typedef block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel> block_evaluator_type;
EIGEN_DEVICE_FUNC explicit evaluator(const XprType& block) : block_evaluator_type(block) {} EIGEN_DEVICE_FUNC explicit evaluator(const XprType& block) : block_evaluator_type(block)
{
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
}; };
// no direct-access => dispatch to a unary evaluator // no direct-access => dispatch to a unary evaluator
@ -831,7 +850,7 @@ struct evaluator<Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType> >
typedef Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType> XprType; typedef Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType> XprType;
enum { enum {
CoeffReadCost = evaluator<ConditionMatrixType>::CoeffReadCost CoeffReadCost = evaluator<ConditionMatrixType>::CoeffReadCost
+ EIGEN_SIZE_MAX(evaluator<ThenMatrixType>::CoeffReadCost, + EIGEN_PLAIN_ENUM_MAX(evaluator<ThenMatrixType>::CoeffReadCost,
evaluator<ElseMatrixType>::CoeffReadCost), evaluator<ElseMatrixType>::CoeffReadCost),
Flags = (unsigned int)evaluator<ThenMatrixType>::Flags & evaluator<ElseMatrixType>::Flags & HereditaryBits, Flags = (unsigned int)evaluator<ThenMatrixType>::Flags & evaluator<ElseMatrixType>::Flags & HereditaryBits,
@ -843,7 +862,9 @@ struct evaluator<Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType> >
: m_conditionImpl(select.conditionMatrix()), : m_conditionImpl(select.conditionMatrix()),
m_thenImpl(select.thenMatrix()), m_thenImpl(select.thenMatrix()),
m_elseImpl(select.elseMatrix()) m_elseImpl(select.elseMatrix())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::CoeffReturnType CoeffReturnType;
@ -965,11 +986,11 @@ struct evaluator<PartialReduxExpr<ArgType, MemberOp, Direction> >
typedef typename ArgType::Scalar InputScalar; typedef typename ArgType::Scalar InputScalar;
typedef typename XprType::Scalar Scalar; typedef typename XprType::Scalar Scalar;
enum { enum {
TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(XprType::ColsAtCompileTime) TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(ArgType::ColsAtCompileTime)
}; };
typedef typename MemberOp::template Cost<InputScalar,int(TraversalSize)> CostOpType; typedef typename MemberOp::template Cost<InputScalar,int(TraversalSize)> CostOpType;
enum { enum {
CoeffReadCost = TraversalSize==Dynamic ? Dynamic CoeffReadCost = TraversalSize==Dynamic ? HugeCost
: TraversalSize * evaluator<ArgType>::CoeffReadCost + int(CostOpType::value), : TraversalSize * evaluator<ArgType>::CoeffReadCost + int(CostOpType::value),
Flags = (traits<XprType>::Flags&RowMajorBit) | (evaluator<ArgType>::Flags&HereditaryBits), Flags = (traits<XprType>::Flags&RowMajorBit) | (evaluator<ArgType>::Flags&HereditaryBits),
@ -979,7 +1000,10 @@ struct evaluator<PartialReduxExpr<ArgType, MemberOp, Direction> >
EIGEN_DEVICE_FUNC explicit evaluator(const XprType xpr) EIGEN_DEVICE_FUNC explicit evaluator(const XprType xpr)
: m_arg(xpr.nestedExpression()), m_functor(xpr.functor()) : m_arg(xpr.nestedExpression()), m_functor(xpr.functor())
{} {
EIGEN_INTERNAL_CHECK_COST_VALUE(TraversalSize==Dynamic ? HugeCost : int(CostOpType::value));
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::CoeffReturnType CoeffReturnType;

View File

@ -157,9 +157,9 @@ struct NumTraits<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> >
IsInteger = NumTraits<Scalar>::IsInteger, IsInteger = NumTraits<Scalar>::IsInteger,
IsSigned = NumTraits<Scalar>::IsSigned, IsSigned = NumTraits<Scalar>::IsSigned,
RequireInitialization = 1, RequireInitialization = 1,
ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::ReadCost, ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::ReadCost,
AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::AddCost, AddCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::AddCost,
MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::MulCost MulCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::MulCost
}; };
static inline RealScalar epsilon() { return NumTraits<RealScalar>::epsilon(); } static inline RealScalar epsilon() { return NumTraits<RealScalar>::epsilon(); }

View File

@ -422,7 +422,11 @@ struct product_evaluator<Product<Lhs, Rhs, LazyProduct>, ProductTag, DenseShape,
m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed, m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed,
// or perhaps declare them on the fly on the packet method... We have experiment to check what's best. // or perhaps declare them on the fly on the packet method... We have experiment to check what's best.
m_innerDim(xpr.lhs().cols()) m_innerDim(xpr.lhs().cols())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::MulCost);
EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::AddCost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
// Everything below here is taken from CoeffBasedProduct.h // Everything below here is taken from CoeffBasedProduct.h
@ -447,11 +451,11 @@ struct product_evaluator<Product<Lhs, Rhs, LazyProduct>, ProductTag, DenseShape,
LhsCoeffReadCost = LhsEtorType::CoeffReadCost, LhsCoeffReadCost = LhsEtorType::CoeffReadCost,
RhsCoeffReadCost = RhsEtorType::CoeffReadCost, RhsCoeffReadCost = RhsEtorType::CoeffReadCost,
CoeffReadCost = InnerSize==0 ? NumTraits<Scalar>::ReadCost CoeffReadCost = InnerSize==0 ? NumTraits<Scalar>::ReadCost
: (InnerSize == Dynamic || LhsCoeffReadCost==Dynamic || RhsCoeffReadCost==Dynamic || NumTraits<Scalar>::AddCost==Dynamic || NumTraits<Scalar>::MulCost==Dynamic) ? Dynamic : InnerSize == Dynamic ? HugeCost
: InnerSize * (NumTraits<Scalar>::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) : InnerSize * (NumTraits<Scalar>::MulCost + LhsCoeffReadCost + RhsCoeffReadCost)
+ (InnerSize - 1) * NumTraits<Scalar>::AddCost, + (InnerSize - 1) * NumTraits<Scalar>::AddCost,
Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, Unroll = CoeffReadCost < HugeCost && CoeffReadCost <= EIGEN_UNROLLING_LIMIT,
LhsFlags = LhsEtorType::Flags, LhsFlags = LhsEtorType::Flags,
RhsFlags = RhsEtorType::Flags, RhsFlags = RhsEtorType::Flags,
@ -736,6 +740,8 @@ public:
diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag)
: m_diagImpl(diag), m_matImpl(mat) : m_diagImpl(diag), m_matImpl(mat)
{ {
EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::MulCost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
} }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const

View File

@ -51,9 +51,9 @@ public:
public: public:
enum { enum {
Cost = ( Derived::SizeAtCompileTime == Dynamic Cost = ( Derived::SizeAtCompileTime == Dynamic
|| Derived::CoeffReadCost == Dynamic || Derived::CoeffReadCost >= HugeCost
|| (Derived::SizeAtCompileTime!=1 && functor_traits<Func>::Cost == Dynamic) || (Derived::SizeAtCompileTime!=1 && functor_traits<Func>::Cost >= HugeCost)
) ? Dynamic ) ? HugeCost
: Derived::SizeAtCompileTime * Derived::CoeffReadCost : Derived::SizeAtCompileTime * Derived::CoeffReadCost
+ (Derived::SizeAtCompileTime-1) * functor_traits<Func>::Cost, + (Derived::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))
@ -61,7 +61,7 @@ public:
public: public:
enum { enum {
Unrolling = Cost != Dynamic && Cost <= UnrollingLimit Unrolling = Cost < HugeCost && Cost <= UnrollingLimit
? CompleteUnrolling ? CompleteUnrolling
: NoUnrolling : NoUnrolling
}; };

View File

@ -110,8 +110,8 @@ void DenseBase<Derived>::visit(Visitor& visitor) const
ThisEvaluator thisEval(derived()); ThisEvaluator thisEval(derived());
enum { unroll = SizeAtCompileTime != Dynamic enum { unroll = SizeAtCompileTime != Dynamic
&& ThisEvaluator::CoeffReadCost != Dynamic && ThisEvaluator::CoeffReadCost < HugeCost
&& (SizeAtCompileTime == 1 || internal::functor_traits<Visitor>::Cost != Dynamic) && (SizeAtCompileTime == 1 || internal::functor_traits<Visitor>::Cost < HugeCost)
&& SizeAtCompileTime * ThisEvaluator::CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits<Visitor>::Cost && SizeAtCompileTime * ThisEvaluator::CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits<Visitor>::Cost
<= EIGEN_UNROLLING_LIMIT }; <= EIGEN_UNROLLING_LIMIT };
return internal::visitor_impl<Visitor, ThisEvaluator, return internal::visitor_impl<Visitor, ThisEvaluator,

View File

@ -30,6 +30,14 @@ const int DynamicIndex = 0xffffff;
*/ */
const int Infinity = -1; const int Infinity = -1;
/** This value means that the cost to evaluate an expression coefficient is either very expensive or
* cannot be known at compile time.
*
* This value has to be positive to (1) simplify cost computation, and (2) allow to distinguish between a very expensive and very very expensive expressions.
* It thus must also be large enough to make sure unrolling won't happen and that sub expressions will be evaluated, but not too large to avoid overflow.
*/
const int HugeCost = 1000;
/** \defgroup flags Flags /** \defgroup flags Flags
* \ingroup Core_Module * \ingroup Core_Module
* *

View File

@ -93,7 +93,8 @@
THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH, THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH,
OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG,
IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY, IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY,
STORAGE_LAYOUT_DOES_NOT_MATCH STORAGE_LAYOUT_DOES_NOT_MATCH,
EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT__INVALID_COST_VALUE
}; };
}; };
@ -200,5 +201,9 @@
>::value), \ >::value), \
YOU_CANNOT_MIX_ARRAYS_AND_MATRICES) YOU_CANNOT_MIX_ARRAYS_AND_MATRICES)
// Check that a cost value is positive, and that is stay within a reasonable range
// TODO this check could be enabled for internal debugging only
#define EIGEN_INTERNAL_CHECK_COST_VALUE(C) \
EIGEN_STATIC_ASSERT((C)>=0 && (C)<2*HugeCost*HugeCost, EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT__INVALID_COST_VALUE);
#endif // EIGEN_STATIC_ASSERT_H #endif // EIGEN_STATIC_ASSERT_H

View File

@ -397,28 +397,20 @@ struct transfer_constness
template<typename T, int n, typename PlainObject = typename plain_object_eval<T>::type> struct nested_eval template<typename T, int n, typename PlainObject = typename plain_object_eval<T>::type> struct nested_eval
{ {
enum { enum {
// For the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values.
// the choice of 10000 makes it larger than any practical fixed value and even most dynamic values.
// in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues
// (poor choice of temporaries).
// It's important that this value can still be squared without integer overflowing.
DynamicAsInteger = 10000,
ScalarReadCost = NumTraits<typename traits<T>::Scalar>::ReadCost, ScalarReadCost = NumTraits<typename traits<T>::Scalar>::ReadCost,
ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost),
CoeffReadCost = evaluator<T>::CoeffReadCost, // NOTE What if an evaluator evaluate itself into a tempory? CoeffReadCost = evaluator<T>::CoeffReadCost, // NOTE What if an evaluator evaluate itself into a tempory?
// Then CoeffReadCost will be small (e.g., 1) but we still have to evaluate, especially if n>1. // Then CoeffReadCost will be small (e.g., 1) but we still have to evaluate, especially if n>1.
// This situation is already taken care by the EvalBeforeNestingBit flag, which is turned ON // This situation is already taken care by the EvalBeforeNestingBit flag, which is turned ON
// for all evaluator creating a temporary. This flag is then propagated by the parent evaluators. // for all evaluator creating a temporary. This flag is then propagated by the parent evaluators.
// Another solution could be to count the number of temps? // Another solution could be to count the number of temps?
CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), NAsInteger = n == Dynamic ? HugeCost : n,
NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, CostEval = (NAsInteger+1) * ScalarReadCost + CoeffReadCost,
CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, CostNoEval = NAsInteger * CoeffReadCost
CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger
}; };
typedef typename conditional< typedef typename conditional<
( (int(evaluator<T>::Flags) & EvalBeforeNestingBit) || ( (int(evaluator<T>::Flags) & EvalBeforeNestingBit) ||
(int(CostEvalAsInteger) < int(CostNoEvalAsInteger)) ), (int(CostEval) < int(CostNoEval)) ),
PlainObject, PlainObject,
typename ref_selector<T>::type typename ref_selector<T>::type
>::type type; >::type type;

View File

@ -226,8 +226,14 @@ struct evaluator<SparseCompressedBase<Derived> >
Flags = Derived::Flags Flags = Derived::Flags
}; };
evaluator() : m_matrix(0) {} evaluator() : m_matrix(0)
explicit evaluator(const Derived &mat) : m_matrix(&mat) {} {
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
explicit evaluator(const Derived &mat) : m_matrix(&mat)
{
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
inline Index nonZerosEstimate() const { inline Index nonZerosEstimate() const {
return m_matrix->nonZeros(); return m_matrix->nonZeros();

View File

@ -139,7 +139,10 @@ public:
: m_functor(xpr.functor()), : m_functor(xpr.functor()),
m_lhsImpl(xpr.lhs()), m_lhsImpl(xpr.lhs()),
m_rhsImpl(xpr.rhs()) m_rhsImpl(xpr.rhs())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
inline Index nonZerosEstimate() const { inline Index nonZerosEstimate() const {
return m_lhsImpl.nonZerosEstimate() + m_rhsImpl.nonZerosEstimate(); return m_lhsImpl.nonZerosEstimate() + m_rhsImpl.nonZerosEstimate();
@ -220,7 +223,10 @@ public:
: m_functor(xpr.functor()), : m_functor(xpr.functor()),
m_lhsImpl(xpr.lhs()), m_lhsImpl(xpr.lhs()),
m_rhsImpl(xpr.rhs()) m_rhsImpl(xpr.rhs())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
inline Index nonZerosEstimate() const { inline Index nonZerosEstimate() const {
return (std::min)(m_lhsImpl.nonZerosEstimate(), m_rhsImpl.nonZerosEstimate()); return (std::min)(m_lhsImpl.nonZerosEstimate(), m_rhsImpl.nonZerosEstimate());
@ -289,7 +295,10 @@ public:
: m_functor(xpr.functor()), : m_functor(xpr.functor()),
m_lhsImpl(xpr.lhs()), m_lhsImpl(xpr.lhs()),
m_rhsImpl(xpr.rhs()) m_rhsImpl(xpr.rhs())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
inline Index nonZerosEstimate() const { inline Index nonZerosEstimate() const {
return m_rhsImpl.nonZerosEstimate(); return m_rhsImpl.nonZerosEstimate();
@ -359,7 +368,10 @@ public:
: m_functor(xpr.functor()), : m_functor(xpr.functor()),
m_lhsImpl(xpr.lhs()), m_lhsImpl(xpr.lhs()),
m_rhsImpl(xpr.rhs()) m_rhsImpl(xpr.rhs())
{ } {
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
inline Index nonZerosEstimate() const { inline Index nonZerosEstimate() const {
return m_lhsImpl.nonZerosEstimate(); return m_lhsImpl.nonZerosEstimate();

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library // This file is part of Eigen, a lightweight C++ template library
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr> // Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
// //
// This Source Code Form is subject to the terms of the Mozilla // This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed // Public License v. 2.0. If a copy of the MPL was not distributed
@ -29,7 +29,11 @@ struct unary_evaluator<CwiseUnaryOp<UnaryOp,ArgType>, IteratorBased>
Flags = XprType::Flags Flags = XprType::Flags
}; };
explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression())
{
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<UnaryOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
inline Index nonZerosEstimate() const { inline Index nonZerosEstimate() const {
return m_argImpl.nonZerosEstimate(); return m_argImpl.nonZerosEstimate();
@ -108,7 +112,11 @@ struct unary_evaluator<CwiseUnaryView<ViewOp,ArgType>, IteratorBased>
Flags = XprType::Flags Flags = XprType::Flags
}; };
explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression())
{
EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<ViewOp>::Cost);
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
protected: protected:
typedef typename evaluator<ArgType>::InnerIterator EvalIterator; typedef typename evaluator<ArgType>::InnerIterator EvalIterator;

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library // This file is part of Eigen, a lightweight C++ template library
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr> // Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
// //
// This Source Code Form is subject to the terms of the Mozilla // This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed // Public License v. 2.0. If a copy of the MPL was not distributed
@ -221,7 +221,7 @@ protected:
public: public:
enum { enum {
Flags = NeedToTranspose ? RowMajorBit : 0, Flags = NeedToTranspose ? RowMajorBit : 0,
CoeffReadCost = Dynamic CoeffReadCost = HugeCost
}; };
class InnerIterator : public LhsIterator class InnerIterator : public LhsIterator
@ -263,12 +263,16 @@ public:
sparse_dense_outer_product_evaluator(const Lhs1 &lhs, const ActualRhs &rhs) sparse_dense_outer_product_evaluator(const Lhs1 &lhs, const ActualRhs &rhs)
: m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs)
{} {
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
// transpose case // transpose case
sparse_dense_outer_product_evaluator(const ActualRhs &rhs, const Lhs1 &lhs) sparse_dense_outer_product_evaluator(const ActualRhs &rhs, const Lhs1 &lhs)
: m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs)
{} {
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
protected: protected:
const LhsArg m_lhs; const LhsArg m_lhs;

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library // This file is part of Eigen, a lightweight C++ template library
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2009-2014 Gael Guennebaud <gael.guennebaud@inria.fr> // Copyright (C) 2009-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
// //
// This Source Code Form is subject to the terms of the Mozilla // This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed // Public License v. 2.0. If a copy of the MPL was not distributed
@ -39,7 +39,7 @@ struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, Diagonal
: public sparse_diagonal_product_evaluator<Rhs, typename Lhs::DiagonalVectorType, Rhs::Flags&RowMajorBit?SDP_AsScalarProduct:SDP_AsCwiseProduct> : public sparse_diagonal_product_evaluator<Rhs, typename Lhs::DiagonalVectorType, Rhs::Flags&RowMajorBit?SDP_AsScalarProduct:SDP_AsCwiseProduct>
{ {
typedef Product<Lhs, Rhs, DefaultProduct> XprType; typedef Product<Lhs, Rhs, DefaultProduct> XprType;
enum { CoeffReadCost = Dynamic, Flags = Rhs::Flags&RowMajorBit, Alignment = 0 }; // FIXME CoeffReadCost & Flags enum { CoeffReadCost = HugeCost, Flags = Rhs::Flags&RowMajorBit, Alignment = 0 }; // FIXME CoeffReadCost & Flags
typedef sparse_diagonal_product_evaluator<Rhs, typename Lhs::DiagonalVectorType, Rhs::Flags&RowMajorBit?SDP_AsScalarProduct:SDP_AsCwiseProduct> Base; typedef sparse_diagonal_product_evaluator<Rhs, typename Lhs::DiagonalVectorType, Rhs::Flags&RowMajorBit?SDP_AsScalarProduct:SDP_AsCwiseProduct> Base;
explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {} explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {}
@ -50,7 +50,7 @@ struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, SparseSh
: public sparse_diagonal_product_evaluator<Lhs, Transpose<const typename Rhs::DiagonalVectorType>, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> : public sparse_diagonal_product_evaluator<Lhs, Transpose<const typename Rhs::DiagonalVectorType>, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct>
{ {
typedef Product<Lhs, Rhs, DefaultProduct> XprType; typedef Product<Lhs, Rhs, DefaultProduct> XprType;
enum { CoeffReadCost = Dynamic, Flags = Lhs::Flags&RowMajorBit, Alignment = 0 }; // FIXME CoeffReadCost & Flags enum { CoeffReadCost = HugeCost, Flags = Lhs::Flags&RowMajorBit, Alignment = 0 }; // FIXME CoeffReadCost & Flags
typedef sparse_diagonal_product_evaluator<Lhs, Transpose<const typename Rhs::DiagonalVectorType>, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> Base; typedef sparse_diagonal_product_evaluator<Lhs, Transpose<const typename Rhs::DiagonalVectorType>, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> Base;
explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal().transpose()) {} explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal().transpose()) {}

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library // This file is part of Eigen, a lightweight C++ template library
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr> // Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
// //
// This Source Code Form is subject to the terms of the Mozilla // This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed // Public License v. 2.0. If a copy of the MPL was not distributed

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library // This file is part of Eigen, a lightweight C++ template library
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2009-2014 Gael Guennebaud <gael.guennebaud@inria.fr> // Copyright (C) 2009-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr> // Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
// //
// This Source Code Form is subject to the terms of the Mozilla // This Source Code Form is subject to the terms of the Mozilla

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library // This file is part of Eigen, a lightweight C++ template library
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr> // Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
// //
// This Source Code Form is subject to the terms of the Mozilla // This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed // Public License v. 2.0. If a copy of the MPL was not distributed
@ -41,7 +41,6 @@ struct traits<SparseVector<_Scalar, _Options, _StorageIndex> >
MaxRowsAtCompileTime = RowsAtCompileTime, MaxRowsAtCompileTime = RowsAtCompileTime,
MaxColsAtCompileTime = ColsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime,
Flags = _Options | NestByRefBit | LvalueBit | (IsColVector ? 0 : RowMajorBit) | CompressedAccessBit, Flags = _Options | NestByRefBit | LvalueBit | (IsColVector ? 0 : RowMajorBit) | CompressedAccessBit,
CoeffReadCost = NumTraits<Scalar>::ReadCost,
SupportedAccessPatterns = InnerRandomAccessPattern SupportedAccessPatterns = InnerRandomAccessPattern
}; };
}; };
@ -380,7 +379,10 @@ struct evaluator<SparseVector<_Scalar,_Options,_Index> >
Flags = SparseVectorType::Flags Flags = SparseVectorType::Flags
}; };
explicit evaluator(const SparseVectorType &mat) : m_matrix(mat) {} explicit evaluator(const SparseVectorType &mat) : m_matrix(mat)
{
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
}
inline Index nonZerosEstimate() const { inline Index nonZerosEstimate() const {
return m_matrix.nonZeros(); return m_matrix.nonZeros();

View File

@ -74,7 +74,6 @@ template<typename MatrixType> void matrixRedux(const MatrixType& m)
Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> m2(rows,rows); Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> m2(rows,rows);
m2.setRandom(); m2.setRandom();
VERIFY_EVALUATION_COUNT( ((m1.matrix()*m1.matrix().transpose())+m2).sum(), (MatrixType::SizeAtCompileTime==Dynamic ? 1 : 0) ); VERIFY_EVALUATION_COUNT( ((m1.matrix()*m1.matrix().transpose())+m2).sum(), (MatrixType::SizeAtCompileTime==Dynamic ? 1 : 0) );
} }
template<typename VectorType> void vectorRedux(const VectorType& w) template<typename VectorType> void vectorRedux(const VectorType& w)

View File

@ -217,6 +217,11 @@ template<typename MatrixType> void vectorwiseop_matrix(const MatrixType& m)
VERIFY_IS_APPROX( (m1 * m1.transpose()).colwise().sum(), m1m1.colwise().sum()); VERIFY_IS_APPROX( (m1 * m1.transpose()).colwise().sum(), m1m1.colwise().sum());
Matrix<Scalar,1,MatrixType::RowsAtCompileTime> tmp(rows); Matrix<Scalar,1,MatrixType::RowsAtCompileTime> tmp(rows);
VERIFY_EVALUATION_COUNT( tmp = (m1 * m1.transpose()).colwise().sum(), (MatrixType::RowsAtCompileTime==Dynamic ? 1 : 0)); VERIFY_EVALUATION_COUNT( tmp = (m1 * m1.transpose()).colwise().sum(), (MatrixType::RowsAtCompileTime==Dynamic ? 1 : 0));
m2 = m1.rowwise() - (m1.colwise().sum()/m1.rows()).eval();
m1 = m1.rowwise() - (m1.colwise().sum()/m1.rows());
VERIFY_IS_APPROX( m1, m2 );
VERIFY_EVALUATION_COUNT( m2 = (m1.rowwise() - m1.colwise().sum()/m1.rows()), (MatrixType::RowsAtCompileTime==Dynamic ? 1 : 0) );
} }
void test_vectorwiseop() void test_vectorwiseop()

View File

@ -240,7 +240,7 @@ struct traits<KroneckerProductSparse<_Lhs,_Rhs> >
Flags = ((LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) Flags = ((LhsFlags | RhsFlags) & HereditaryBits & RemovedBits)
| EvalBeforeNestingBit | EvalBeforeAssigningBit, | EvalBeforeNestingBit | EvalBeforeAssigningBit,
CoeffReadCost = Dynamic CoeffReadCost = HugeCost
}; };
typedef SparseMatrix<Scalar, 0, StorageIndex> ReturnType; typedef SparseMatrix<Scalar, 0, StorageIndex> ReturnType;

View File

@ -49,7 +49,7 @@ struct internal::traits<SkylineProduct<LhsNested, RhsNested, ProductMode> > {
| EvalBeforeAssigningBit | EvalBeforeAssigningBit
| EvalBeforeNestingBit, | EvalBeforeNestingBit,
CoeffReadCost = Dynamic CoeffReadCost = HugeCost
}; };
typedef typename internal::conditional<ResultIsSkyline, typedef typename internal::conditional<ResultIsSkyline,