mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
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:
@@ -30,6 +30,14 @@ const int DynamicIndex = 0xffffff;
|
||||
*/
|
||||
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
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
|
||||
@@ -93,7 +93,8 @@
|
||||
THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH,
|
||||
OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG,
|
||||
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), \
|
||||
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
|
||||
|
||||
@@ -397,28 +397,20 @@ struct transfer_constness
|
||||
template<typename T, int n, typename PlainObject = typename plain_object_eval<T>::type> struct nested_eval
|
||||
{
|
||||
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,
|
||||
ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost),
|
||||
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.
|
||||
// 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.
|
||||
// Another solution could be to count the number of temps?
|
||||
CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost),
|
||||
NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n,
|
||||
CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger,
|
||||
CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger
|
||||
NAsInteger = n == Dynamic ? HugeCost : n,
|
||||
CostEval = (NAsInteger+1) * ScalarReadCost + CoeffReadCost,
|
||||
CostNoEval = NAsInteger * CoeffReadCost
|
||||
};
|
||||
|
||||
typedef typename conditional<
|
||||
( (int(evaluator<T>::Flags) & EvalBeforeNestingBit) ||
|
||||
(int(CostEvalAsInteger) < int(CostNoEvalAsInteger)) ),
|
||||
(int(CostEval) < int(CostNoEval)) ),
|
||||
PlainObject,
|
||||
typename ref_selector<T>::type
|
||||
>::type type;
|
||||
|
||||
Reference in New Issue
Block a user