fix sum()/prod() on empty matrix making sure this does not affect fixed sized object, extend related unit tests including partial reduction

This commit is contained in:
Gael Guennebaud 2010-07-16 14:02:20 +02:00
parent 6a370f50c7
commit 044424b0e2
3 changed files with 23 additions and 1 deletions

View File

@ -183,7 +183,7 @@ struct ei_redux_impl<Func, Derived, DefaultTraversal, NoUnrolling>
typedef typename Derived::Index Index;
static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func)
{
ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using a non initialized matrix");
ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix");
Scalar res;
res = mat.coeffByOuterInner(0, 0);
for(Index i = 1; i < mat.innerSize(); ++i)
@ -210,6 +210,7 @@ struct ei_redux_impl<Func, Derived, LinearVectorizedTraversal, NoUnrolling>
static Scalar run(const Derived& mat, const Func& func)
{
const Index size = mat.size();
ei_assert(size && "you are using an empty matrix");
const Index packetSize = ei_packet_traits<Scalar>::size;
const Index alignedStart = ei_first_aligned(mat);
enum {
@ -253,6 +254,7 @@ struct ei_redux_impl<Func, Derived, SliceVectorizedTraversal, NoUnrolling>
static Scalar run(const Derived& mat, const Func& func)
{
ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix");
const Index innerSize = mat.innerSize();
const Index outerSize = mat.outerSize();
enum {
@ -294,6 +296,7 @@ struct ei_redux_impl<Func, Derived, LinearVectorizedTraversal, CompleteUnrolling
};
EIGEN_STRONG_INLINE static Scalar run(const Derived& mat, const Func& func)
{
ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix");
Scalar res = func.predux(ei_redux_vec_unroller<Func, Derived, 0, Size / PacketSize>::run(mat,func));
if (VectorizedSize != Size)
res = func(res,ei_redux_novec_unroller<Func, Derived, VectorizedSize, Size-VectorizedSize>::run(mat,func));
@ -345,6 +348,8 @@ template<typename Derived>
EIGEN_STRONG_INLINE typename ei_traits<Derived>::Scalar
DenseBase<Derived>::sum() const
{
if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0))
return Scalar(0);
return this->redux(Eigen::ei_scalar_sum_op<Scalar>());
}
@ -370,6 +375,8 @@ template<typename Derived>
EIGEN_STRONG_INLINE typename ei_traits<Derived>::Scalar
DenseBase<Derived>::prod() const
{
if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0))
return Scalar(1);
return this->redux(Eigen::ei_scalar_product_op<Scalar>());
}

View File

@ -72,6 +72,10 @@ template<typename MatrixType> void array_for_matrix(const MatrixType& m)
VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
m3 = m1;
VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);
// empty objects
VERIFY_IS_APPROX(m1.block(0,0,0,cols).colwise().sum(), RowVectorType::Zero(cols));
VERIFY_IS_APPROX(m1.block(0,0,rows,0).rowwise().prod(), ColVectorType::Ones(rows));
}
template<typename MatrixType> void comparisons(const MatrixType& m)

View File

@ -64,6 +64,10 @@ template<typename MatrixType> void matrixRedux(const MatrixType& m)
VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).prod(), m1.block(r0,c0,r1,c1).eval().prod());
VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().minCoeff(), m1.block(r0,c0,r1,c1).real().eval().minCoeff());
VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().maxCoeff(), m1.block(r0,c0,r1,c1).real().eval().maxCoeff());
// test empty objects
VERIFY_IS_APPROX(m1.block(r0,c0,0,0).sum(), Scalar(0));
VERIFY_IS_APPROX(m1.block(r0,c0,0,0).prod(), Scalar(1));
}
template<typename VectorType> void vectorRedux(const VectorType& w)
@ -124,6 +128,13 @@ template<typename VectorType> void vectorRedux(const VectorType& w)
VERIFY_IS_APPROX(minc, v.real().segment(i, size-2*i).minCoeff());
VERIFY_IS_APPROX(maxc, v.real().segment(i, size-2*i).maxCoeff());
}
// test empty objects
VERIFY_IS_APPROX(v.head(0).sum(), Scalar(0));
VERIFY_IS_APPROX(v.tail(0).prod(), Scalar(1));
VERIFY_RAISES_ASSERT(v.head(0).mean());
VERIFY_RAISES_ASSERT(v.head(0).minCoeff());
VERIFY_RAISES_ASSERT(v.head(0).maxCoeff());
}
void test_redux()