mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-04-20 08:39:37 +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
|
* Example: \include MatrixBase_colwise_iterator_cxx11.cpp
|
||||||
* Output: \verbinclude MatrixBase_colwise_iterator_cxx11.out
|
* 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
|
* \sa DenseBase::colwise(), DenseBase::rowwise(), class PartialReduxExpr
|
||||||
*/
|
*/
|
||||||
template<typename ExpressionType, int Direction> class VectorwiseOp
|
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
|
* The template parameter \a BinaryOp is the type of the functor
|
||||||
* of the custom redux operator. Note that func must be an associative operator.
|
* 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()
|
* \sa class VectorwiseOp, DenseBase::colwise(), DenseBase::rowwise()
|
||||||
*/
|
*/
|
||||||
template<typename BinaryOp>
|
template<typename BinaryOp>
|
||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
const typename ReduxReturnType<BinaryOp>::Type
|
const typename ReduxReturnType<BinaryOp>::Type
|
||||||
redux(const BinaryOp& func = BinaryOp()) const
|
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_minCoeff>::Type MinCoeffReturnType;
|
||||||
typedef typename ReturnType<internal::member_maxCoeff>::Type MaxCoeffReturnType;
|
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
|
/** \returns a row (or column) vector expression of the smallest coefficient
|
||||||
* of each column (or row) of the referenced expression.
|
* 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.
|
* \warning the result is undefined if \c *this contains NaN.
|
||||||
*
|
*
|
||||||
* Example: \include PartialRedux_minCoeff.cpp
|
* Example: \include PartialRedux_minCoeff.cpp
|
||||||
@ -333,11 +350,17 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
|||||||
* \sa DenseBase::minCoeff() */
|
* \sa DenseBase::minCoeff() */
|
||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
const MinCoeffReturnType minCoeff() const
|
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
|
/** \returns a row (or column) vector expression of the largest coefficient
|
||||||
* of each column (or row) of the referenced expression.
|
* 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.
|
* \warning the result is undefined if \c *this contains NaN.
|
||||||
*
|
*
|
||||||
* Example: \include PartialRedux_maxCoeff.cpp
|
* Example: \include PartialRedux_maxCoeff.cpp
|
||||||
@ -346,7 +369,10 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
|||||||
* \sa DenseBase::maxCoeff() */
|
* \sa DenseBase::maxCoeff() */
|
||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
const MaxCoeffReturnType maxCoeff() const
|
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
|
/** \returns a row (or column) vector expression of the squared norm
|
||||||
* of each column (or row) of the referenced expression.
|
* of each column (or row) of the referenced expression.
|
||||||
@ -690,6 +716,10 @@ template<typename ExpressionType, int Direction> class VectorwiseOp
|
|||||||
const HNormalizedReturnType hnormalized() const;
|
const HNormalizedReturnType hnormalized() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Index redux_length() const
|
||||||
|
{
|
||||||
|
return Direction==Vertical ? m_matrix.rows() : m_matrix.cols();
|
||||||
|
}
|
||||||
ExpressionTypeNested m_matrix;
|
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<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
|
||||||
typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealColVectorType;
|
typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealColVectorType;
|
||||||
typedef Matrix<RealScalar, 1, MatrixType::ColsAtCompileTime> RealRowVectorType;
|
typedef Matrix<RealScalar, 1, MatrixType::ColsAtCompileTime> RealRowVectorType;
|
||||||
|
typedef Matrix<Scalar,Dynamic,Dynamic> MatrixX;
|
||||||
|
|
||||||
Index rows = m.rows();
|
Index rows = m.rows();
|
||||||
Index cols = m.cols();
|
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()));
|
m1 = m1.rowwise() - (m1.colwise().sum()/RealScalar(m1.rows()));
|
||||||
VERIFY_IS_APPROX( m1, m2 );
|
VERIFY_IS_APPROX( m1, m2 );
|
||||||
VERIFY_EVALUATION_COUNT( m2 = (m1.rowwise() - m1.colwise().sum()/RealScalar(m1.rows())), (MatrixType::RowsAtCompileTime!=1 ? 1 : 0) );
|
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)
|
EIGEN_DECLARE_TEST(vectorwiseop)
|
||||||
@ -256,6 +277,7 @@ EIGEN_DECLARE_TEST(vectorwiseop)
|
|||||||
CALL_SUBTEST_3( vectorwiseop_array(ArrayXXf(3, 4)) );
|
CALL_SUBTEST_3( vectorwiseop_array(ArrayXXf(3, 4)) );
|
||||||
CALL_SUBTEST_4( vectorwiseop_matrix(Matrix4cf()) );
|
CALL_SUBTEST_4( vectorwiseop_matrix(Matrix4cf()) );
|
||||||
CALL_SUBTEST_5( vectorwiseop_matrix(Matrix4f()) );
|
CALL_SUBTEST_5( vectorwiseop_matrix(Matrix4f()) );
|
||||||
|
CALL_SUBTEST_5( vectorwiseop_matrix(Vector4f()) );
|
||||||
CALL_SUBTEST_5( vectorwiseop_matrix(Matrix<float,4,5>()) );
|
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_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))) );
|
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.any());
|
||||||
VERIFY(m.prod()==1);
|
VERIFY(m.prod()==1);
|
||||||
VERIFY(m.sum()==0);
|
VERIFY(m.sum()==0);
|
||||||
|
VERIFY(m.norm()==0);
|
||||||
|
VERIFY(m.squaredNorm()==0);
|
||||||
VERIFY(m.count()==0);
|
VERIFY(m.count()==0);
|
||||||
VERIFY(m.allFinite());
|
VERIFY(m.allFinite());
|
||||||
VERIFY(!m.hasNaN());
|
VERIFY(!m.hasNaN());
|
||||||
|
VERIFY_RAISES_ASSERT( m.minCoeff() );
|
||||||
|
VERIFY_RAISES_ASSERT( m.maxCoeff() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user