mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-04-16 14:49:39 +08:00
bug #1592: makes partial min/max reductions trigger an assertion on inputs with a zero reduction length (+doc and tests)
This commit is contained in:
parent
f8bc5cb39e
commit
027e44ed24
@ -173,6 +173,14 @@ struct member_redux {
|
||||
* Example: \include MatrixBase_colwise_iterator_cxx11.cpp
|
||||
* Output: \verbinclude MatrixBase_colwise_iterator_cxx11.out
|
||||
*
|
||||
* For a partial reduction on an empty input, some rules apply.
|
||||
* For the sake of clarity, let's consider a vertical reduction:
|
||||
* - If the number of columns is zero, then a 1x0 row-major vector expression is returned.
|
||||
* - Otherwise, if the number of rows is zero, then
|
||||
* - a row vector of zeros is returned for sum-like reductions (sum, squaredNorm, norm, etc.)
|
||||
* - a row vector of ones is returned for a product reduction (e.g., <code>MatrixXd(n,0).colwise().prod()</code>)
|
||||
* - an assert is triggered for all other reductions (minCoeff,maxCoeff,redux(bin_op))
|
||||
*
|
||||
* \sa DenseBase::colwise(), DenseBase::rowwise(), class PartialReduxExpr
|
||||
*/
|
||||
template<typename ExpressionType, int Direction> class VectorwiseOp
|
||||
@ -294,13 +302,19 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
||||
* The template parameter \a BinaryOp is the type of the functor
|
||||
* of the custom redux operator. Note that func must be an associative operator.
|
||||
*
|
||||
* \warning the size along the reduction direction must be strictly positive,
|
||||
* otherwise an assertion is triggered.
|
||||
*
|
||||
* \sa class VectorwiseOp, DenseBase::colwise(), DenseBase::rowwise()
|
||||
*/
|
||||
template<typename BinaryOp>
|
||||
EIGEN_DEVICE_FUNC
|
||||
const typename ReduxReturnType<BinaryOp>::Type
|
||||
redux(const BinaryOp& func = BinaryOp()) const
|
||||
{ return typename ReduxReturnType<BinaryOp>::Type(_expression(), internal::member_redux<BinaryOp,Scalar>(func)); }
|
||||
{
|
||||
eigen_assert(redux_length()>0 && "you are using an empty matrix");
|
||||
return typename ReduxReturnType<BinaryOp>::Type(_expression(), internal::member_redux<BinaryOp,Scalar>(func));
|
||||
}
|
||||
|
||||
typedef typename ReturnType<internal::member_minCoeff>::Type MinCoeffReturnType;
|
||||
typedef typename ReturnType<internal::member_maxCoeff>::Type MaxCoeffReturnType;
|
||||
@ -325,6 +339,9 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
||||
/** \returns a row (or column) vector expression of the smallest coefficient
|
||||
* of each column (or row) of the referenced expression.
|
||||
*
|
||||
* \warning the size along the reduction direction must be strictly positive,
|
||||
* otherwise an assertion is triggered.
|
||||
*
|
||||
* \warning the result is undefined if \c *this contains NaN.
|
||||
*
|
||||
* Example: \include PartialRedux_minCoeff.cpp
|
||||
@ -333,11 +350,17 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
||||
* \sa DenseBase::minCoeff() */
|
||||
EIGEN_DEVICE_FUNC
|
||||
const MinCoeffReturnType minCoeff() const
|
||||
{ return MinCoeffReturnType(_expression()); }
|
||||
{
|
||||
eigen_assert(redux_length()>0 && "you are using an empty matrix");
|
||||
return MinCoeffReturnType(_expression());
|
||||
}
|
||||
|
||||
/** \returns a row (or column) vector expression of the largest coefficient
|
||||
* of each column (or row) of the referenced expression.
|
||||
*
|
||||
* \warning the size along the reduction direction must be strictly positive,
|
||||
* otherwise an assertion is triggered.
|
||||
*
|
||||
* \warning the result is undefined if \c *this contains NaN.
|
||||
*
|
||||
* Example: \include PartialRedux_maxCoeff.cpp
|
||||
@ -346,7 +369,10 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
||||
* \sa DenseBase::maxCoeff() */
|
||||
EIGEN_DEVICE_FUNC
|
||||
const MaxCoeffReturnType maxCoeff() const
|
||||
{ return MaxCoeffReturnType(_expression()); }
|
||||
{
|
||||
eigen_assert(redux_length()>0 && "you are using an empty matrix");
|
||||
return MaxCoeffReturnType(_expression());
|
||||
}
|
||||
|
||||
/** \returns a row (or column) vector expression of the squared norm
|
||||
* of each column (or row) of the referenced expression.
|
||||
@ -690,6 +716,10 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
||||
const HNormalizedReturnType hnormalized() const;
|
||||
|
||||
protected:
|
||||
Index redux_length() const
|
||||
{
|
||||
return Direction==Vertical ? m_matrix.rows() : m_matrix.cols();
|
||||
}
|
||||
ExpressionTypeNested m_matrix;
|
||||
};
|
||||
|
||||
|
@ -134,6 +134,7 @@ template<typename MatrixType> void vectorwiseop_matrix(const MatrixType& m)
|
||||
typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
|
||||
typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealColVectorType;
|
||||
typedef Matrix<RealScalar, 1, MatrixType::ColsAtCompileTime> RealRowVectorType;
|
||||
typedef Matrix<Scalar,Dynamic,Dynamic> MatrixX;
|
||||
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
@ -247,6 +248,26 @@ template<typename MatrixType> void vectorwiseop_matrix(const MatrixType& m)
|
||||
m1 = m1.rowwise() - (m1.colwise().sum()/RealScalar(m1.rows()));
|
||||
VERIFY_IS_APPROX( m1, m2 );
|
||||
VERIFY_EVALUATION_COUNT( m2 = (m1.rowwise() - m1.colwise().sum()/RealScalar(m1.rows())), (MatrixType::RowsAtCompileTime!=1 ? 1 : 0) );
|
||||
|
||||
// test empty expressions
|
||||
VERIFY_IS_APPROX(m1.matrix().middleCols(0,0).rowwise().sum().eval(), MatrixX::Zero(rows,1));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleRows(0,0).colwise().sum().eval(), MatrixX::Zero(1,cols));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleCols(0,fix<0>).rowwise().sum().eval(), MatrixX::Zero(rows,1));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleRows(0,fix<0>).colwise().sum().eval(), MatrixX::Zero(1,cols));
|
||||
|
||||
VERIFY_IS_APPROX(m1.matrix().middleCols(0,0).rowwise().prod().eval(), MatrixX::Ones(rows,1));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleRows(0,0).colwise().prod().eval(), MatrixX::Ones(1,cols));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleCols(0,fix<0>).rowwise().prod().eval(), MatrixX::Ones(rows,1));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleRows(0,fix<0>).colwise().prod().eval(), MatrixX::Ones(1,cols));
|
||||
|
||||
VERIFY_IS_APPROX(m1.matrix().middleCols(0,0).rowwise().squaredNorm().eval(), MatrixX::Zero(rows,1));
|
||||
|
||||
VERIFY_RAISES_ASSERT(m1.real().middleCols(0,0).rowwise().minCoeff().eval());
|
||||
VERIFY_RAISES_ASSERT(m1.real().middleRows(0,0).colwise().maxCoeff().eval());
|
||||
VERIFY_IS_EQUAL(m1.real().middleRows(0,0).rowwise().maxCoeff().eval().rows(),0);
|
||||
VERIFY_IS_EQUAL(m1.real().middleCols(0,0).colwise().maxCoeff().eval().cols(),0);
|
||||
VERIFY_IS_EQUAL(m1.real().middleRows(0,fix<0>).rowwise().maxCoeff().eval().rows(),0);
|
||||
VERIFY_IS_EQUAL(m1.real().middleCols(0,fix<0>).colwise().maxCoeff().eval().cols(),0);
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(vectorwiseop)
|
||||
@ -256,6 +277,7 @@ EIGEN_DECLARE_TEST(vectorwiseop)
|
||||
CALL_SUBTEST_3( vectorwiseop_array(ArrayXXf(3, 4)) );
|
||||
CALL_SUBTEST_4( vectorwiseop_matrix(Matrix4cf()) );
|
||||
CALL_SUBTEST_5( vectorwiseop_matrix(Matrix4f()) );
|
||||
CALL_SUBTEST_5( vectorwiseop_matrix(Vector4f()) );
|
||||
CALL_SUBTEST_5( vectorwiseop_matrix(Matrix<float,4,5>()) );
|
||||
CALL_SUBTEST_6( vectorwiseop_matrix(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_7( vectorwiseop_matrix(VectorXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
|
@ -16,9 +16,13 @@ template<typename MatrixType> void zeroReduction(const MatrixType& m) {
|
||||
VERIFY(!m.any());
|
||||
VERIFY(m.prod()==1);
|
||||
VERIFY(m.sum()==0);
|
||||
VERIFY(m.norm()==0);
|
||||
VERIFY(m.squaredNorm()==0);
|
||||
VERIFY(m.count()==0);
|
||||
VERIFY(m.allFinite());
|
||||
VERIFY(!m.hasNaN());
|
||||
VERIFY_RAISES_ASSERT( m.minCoeff() );
|
||||
VERIFY_RAISES_ASSERT( m.maxCoeff() );
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user