diff --git a/Eigen/src/QR/ColPivotingHouseholderQR.h b/Eigen/src/QR/ColPivotingHouseholderQR.h index c4c7d2d55..0898b5d1f 100644 --- a/Eigen/src/QR/ColPivotingHouseholderQR.h +++ b/Eigen/src/QR/ColPivotingHouseholderQR.h @@ -351,7 +351,6 @@ bool ColPivotingHouseholderQR::solve( } const int rows = m_qr.rows(); - const int cols = b.cols(); ei_assert(b.rows() == rows); typename OtherDerived::PlainMatrixType c(b); diff --git a/test/main.h b/test/main.h index 8c93e856c..51b719814 100644 --- a/test/main.h +++ b/test/main.h @@ -248,18 +248,22 @@ template void createRandomMatrixOfRank(int desired_rank, int rows, int cols, MatrixType& m) { typedef typename ei_traits::Scalar Scalar; - typedef Matrix VectorType; + enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; - MatrixType a = MatrixType::Random(rows,rows); + typedef Matrix VectorType; + typedef Matrix MatrixAType; + typedef Matrix MatrixBType; + + MatrixAType a = MatrixAType::Random(rows,rows); MatrixType d = MatrixType::Identity(rows,cols); - MatrixType b = MatrixType::Random(cols,cols); + MatrixBType b = MatrixBType::Random(cols,cols); // set the diagonal such that only desired_rank non-zero entries reamain const int diag_size = std::min(d.rows(),d.cols()); d.diagonal().segment(desired_rank, diag_size-desired_rank) = VectorType::Zero(diag_size-desired_rank); - HouseholderQR qra(a); - HouseholderQR qrb(b); + HouseholderQR qra(a); + HouseholderQR qrb(b); m = qra.matrixQ() * d * qrb.matrixQ(); } diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp index 588a41e56..e0edad842 100644 --- a/test/qr_colpivoting.cpp +++ b/test/qr_colpivoting.cpp @@ -63,6 +63,40 @@ template void qr() VERIFY(!qr.solve(m3, &m2)); } +template void qr_fixedsize() +{ + enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; + typedef typename MatrixType::Scalar Scalar; + int rank = ei_random(1, std::min(int(Rows), int(Cols))-1); + Matrix m1; + createRandomMatrixOfRank(rank,Rows,Cols,m1); + ColPivotingHouseholderQR > qr(m1); + VERIFY_IS_APPROX(rank, qr.rank()); + VERIFY(Cols - qr.rank() == qr.dimensionOfKernel()); + VERIFY(!qr.isInjective()); + VERIFY(!qr.isInvertible()); + VERIFY(!qr.isSurjective()); + + Matrix r = qr.matrixQR(); + // FIXME need better way to construct trapezoid + for(int i = 0; i < Rows; i++) for(int j = 0; j < Cols; j++) if(i>j) r(i,j) = Scalar(0); + + Matrix b = qr.matrixQ() * r; + + Matrix c = MatrixType::Zero(Rows,Cols); + + for(int i = 0; i < Cols; ++i) c.col(qr.colsPermutation().coeff(i)) = b.col(i); + VERIFY_IS_APPROX(m1, c); + + Matrix m2 = Matrix::Random(Cols,Cols2); + Matrix m3 = m1*m2; + m2 = Matrix::Random(Cols,Cols2); + VERIFY(qr.solve(m3, &m2)); + VERIFY_IS_APPROX(m3, m1*m2); + m3 = Matrix::Random(Rows,Cols2); + VERIFY(!qr.solve(m3, &m2)); +} + template void qr_invertible() { typedef typename NumTraits::Real RealScalar; @@ -121,6 +155,9 @@ void test_qr_colpivoting() CALL_SUBTEST( qr() ); CALL_SUBTEST( qr() ); } + + CALL_SUBTEST(( qr_fixedsize, 4 >() )); + CALL_SUBTEST(( qr_fixedsize, 3 >() )); for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST( qr_invertible() );