00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
00012 #define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
00013
00014 namespace Eigen {
00015
00037 template<typename _MatrixType> class ColPivHouseholderQR
00038 {
00039 public:
00040
00041 typedef _MatrixType MatrixType;
00042 enum {
00043 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00044 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00045 Options = MatrixType::Options,
00046 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00047 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
00048 };
00049 typedef typename MatrixType::Scalar Scalar;
00050 typedef typename MatrixType::RealScalar RealScalar;
00051 typedef typename MatrixType::Index Index;
00052 typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, Options, MaxRowsAtCompileTime, MaxRowsAtCompileTime> MatrixQType;
00053 typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
00054 typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
00055 typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
00056 typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
00057 typedef typename internal::plain_row_type<MatrixType, RealScalar>::type RealRowVectorType;
00058 typedef HouseholderSequence<MatrixType,typename internal::remove_all<typename HCoeffsType::ConjugateReturnType>::type> HouseholderSequenceType;
00059
00060 private:
00061
00062 typedef typename PermutationType::Index PermIndexType;
00063
00064 public:
00065
00072 ColPivHouseholderQR()
00073 : m_qr(),
00074 m_hCoeffs(),
00075 m_colsPermutation(),
00076 m_colsTranspositions(),
00077 m_temp(),
00078 m_colSqNorms(),
00079 m_isInitialized(false) {}
00080
00087 ColPivHouseholderQR(Index rows, Index cols)
00088 : m_qr(rows, cols),
00089 m_hCoeffs((std::min)(rows,cols)),
00090 m_colsPermutation(PermIndexType(cols)),
00091 m_colsTranspositions(cols),
00092 m_temp(cols),
00093 m_colSqNorms(cols),
00094 m_isInitialized(false),
00095 m_usePrescribedThreshold(false) {}
00096
00109 ColPivHouseholderQR(const MatrixType& matrix)
00110 : m_qr(matrix.rows(), matrix.cols()),
00111 m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
00112 m_colsPermutation(PermIndexType(matrix.cols())),
00113 m_colsTranspositions(matrix.cols()),
00114 m_temp(matrix.cols()),
00115 m_colSqNorms(matrix.cols()),
00116 m_isInitialized(false),
00117 m_usePrescribedThreshold(false)
00118 {
00119 compute(matrix);
00120 }
00121
00139 template<typename Rhs>
00140 inline const internal::solve_retval<ColPivHouseholderQR, Rhs>
00141 solve(const MatrixBase<Rhs>& b) const
00142 {
00143 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00144 return internal::solve_retval<ColPivHouseholderQR, Rhs>(*this, b.derived());
00145 }
00146
00147 HouseholderSequenceType householderQ(void) const;
00148 HouseholderSequenceType matrixQ(void) const
00149 {
00150 return householderQ();
00151 }
00152
00155 const MatrixType& matrixQR() const
00156 {
00157 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00158 return m_qr;
00159 }
00160
00170 const MatrixType& matrixR() const
00171 {
00172 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00173 return m_qr;
00174 }
00175
00176 ColPivHouseholderQR& compute(const MatrixType& matrix);
00177
00179 const PermutationType& colsPermutation() const
00180 {
00181 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00182 return m_colsPermutation;
00183 }
00184
00198 typename MatrixType::RealScalar absDeterminant() const;
00199
00212 typename MatrixType::RealScalar logAbsDeterminant() const;
00213
00220 inline Index rank() const
00221 {
00222 using std::abs;
00223 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00224 RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
00225 Index result = 0;
00226 for(Index i = 0; i < m_nonzero_pivots; ++i)
00227 result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
00228 return result;
00229 }
00230
00237 inline Index dimensionOfKernel() const
00238 {
00239 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00240 return cols() - rank();
00241 }
00242
00250 inline bool isInjective() const
00251 {
00252 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00253 return rank() == cols();
00254 }
00255
00263 inline bool isSurjective() const
00264 {
00265 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00266 return rank() == rows();
00267 }
00268
00275 inline bool isInvertible() const
00276 {
00277 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00278 return isInjective() && isSurjective();
00279 }
00280
00286 inline const
00287 internal::solve_retval<ColPivHouseholderQR, typename MatrixType::IdentityReturnType>
00288 inverse() const
00289 {
00290 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00291 return internal::solve_retval<ColPivHouseholderQR,typename MatrixType::IdentityReturnType>
00292 (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()));
00293 }
00294
00295 inline Index rows() const { return m_qr.rows(); }
00296 inline Index cols() const { return m_qr.cols(); }
00297
00302 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
00303
00321 ColPivHouseholderQR& setThreshold(const RealScalar& threshold)
00322 {
00323 m_usePrescribedThreshold = true;
00324 m_prescribedThreshold = threshold;
00325 return *this;
00326 }
00327
00336 ColPivHouseholderQR& setThreshold(Default_t)
00337 {
00338 m_usePrescribedThreshold = false;
00339 return *this;
00340 }
00341
00346 RealScalar threshold() const
00347 {
00348 eigen_assert(m_isInitialized || m_usePrescribedThreshold);
00349 return m_usePrescribedThreshold ? m_prescribedThreshold
00350
00351
00352 : NumTraits<Scalar>::epsilon() * m_qr.diagonalSize();
00353 }
00354
00362 inline Index nonzeroPivots() const
00363 {
00364 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00365 return m_nonzero_pivots;
00366 }
00367
00371 RealScalar maxPivot() const { return m_maxpivot; }
00372
00379 ComputationInfo info() const
00380 {
00381 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
00382 return Success;
00383 }
00384
00385 protected:
00386 MatrixType m_qr;
00387 HCoeffsType m_hCoeffs;
00388 PermutationType m_colsPermutation;
00389 IntRowVectorType m_colsTranspositions;
00390 RowVectorType m_temp;
00391 RealRowVectorType m_colSqNorms;
00392 bool m_isInitialized, m_usePrescribedThreshold;
00393 RealScalar m_prescribedThreshold, m_maxpivot;
00394 Index m_nonzero_pivots;
00395 Index m_det_pq;
00396 };
00397
00398 template<typename MatrixType>
00399 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::absDeterminant() const
00400 {
00401 using std::abs;
00402 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00403 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
00404 return abs(m_qr.diagonal().prod());
00405 }
00406
00407 template<typename MatrixType>
00408 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDeterminant() const
00409 {
00410 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00411 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
00412 return m_qr.diagonal().cwiseAbs().array().log().sum();
00413 }
00414
00421 template<typename MatrixType>
00422 ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
00423 {
00424 using std::abs;
00425 Index rows = matrix.rows();
00426 Index cols = matrix.cols();
00427 Index size = matrix.diagonalSize();
00428
00429
00430 eigen_assert(cols<=NumTraits<int>::highest());
00431
00432 m_qr = matrix;
00433 m_hCoeffs.resize(size);
00434
00435 m_temp.resize(cols);
00436
00437 m_colsTranspositions.resize(matrix.cols());
00438 Index number_of_transpositions = 0;
00439
00440 m_colSqNorms.resize(cols);
00441 for(Index k = 0; k < cols; ++k)
00442 m_colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm();
00443
00444 RealScalar threshold_helper = m_colSqNorms.maxCoeff() * numext::abs2(NumTraits<Scalar>::epsilon()) / RealScalar(rows);
00445
00446 m_nonzero_pivots = size;
00447 m_maxpivot = RealScalar(0);
00448
00449 for(Index k = 0; k < size; ++k)
00450 {
00451
00452 Index biggest_col_index;
00453 RealScalar biggest_col_sq_norm = m_colSqNorms.tail(cols-k).maxCoeff(&biggest_col_index);
00454 biggest_col_index += k;
00455
00456
00457
00458
00459
00460 biggest_col_sq_norm = m_qr.col(biggest_col_index).tail(rows-k).squaredNorm();
00461
00462
00463 m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm;
00464
00465
00466
00467
00468
00469
00470 if(biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
00471 {
00472 m_nonzero_pivots = k;
00473 m_hCoeffs.tail(size-k).setZero();
00474 m_qr.bottomRightCorner(rows-k,cols-k)
00475 .template triangularView<StrictlyLower>()
00476 .setZero();
00477 break;
00478 }
00479
00480
00481 m_colsTranspositions.coeffRef(k) = biggest_col_index;
00482 if(k != biggest_col_index) {
00483 m_qr.col(k).swap(m_qr.col(biggest_col_index));
00484 std::swap(m_colSqNorms.coeffRef(k), m_colSqNorms.coeffRef(biggest_col_index));
00485 ++number_of_transpositions;
00486 }
00487
00488
00489 RealScalar beta;
00490 m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
00491
00492
00493 m_qr.coeffRef(k,k) = beta;
00494
00495
00496 if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
00497
00498
00499 m_qr.bottomRightCorner(rows-k, cols-k-1)
00500 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
00501
00502
00503 m_colSqNorms.tail(cols-k-1) -= m_qr.row(k).tail(cols-k-1).cwiseAbs2();
00504 }
00505
00506 m_colsPermutation.setIdentity(PermIndexType(cols));
00507 for(PermIndexType k = 0; k < m_nonzero_pivots; ++k)
00508 m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(m_colsTranspositions.coeff(k)));
00509
00510 m_det_pq = (number_of_transpositions%2) ? -1 : 1;
00511 m_isInitialized = true;
00512
00513 return *this;
00514 }
00515
00516 namespace internal {
00517
00518 template<typename _MatrixType, typename Rhs>
00519 struct solve_retval<ColPivHouseholderQR<_MatrixType>, Rhs>
00520 : solve_retval_base<ColPivHouseholderQR<_MatrixType>, Rhs>
00521 {
00522 EIGEN_MAKE_SOLVE_HELPERS(ColPivHouseholderQR<_MatrixType>,Rhs)
00523
00524 template<typename Dest> void evalTo(Dest& dst) const
00525 {
00526 eigen_assert(rhs().rows() == dec().rows());
00527
00528 const Index cols = dec().cols(),
00529 nonzero_pivots = dec().nonzeroPivots();
00530
00531 if(nonzero_pivots == 0)
00532 {
00533 dst.setZero();
00534 return;
00535 }
00536
00537 typename Rhs::PlainObject c(rhs());
00538
00539
00540 c.applyOnTheLeft(householderSequence(dec().matrixQR(), dec().hCoeffs())
00541 .setLength(dec().nonzeroPivots())
00542 .transpose()
00543 );
00544
00545 dec().matrixR()
00546 .topLeftCorner(nonzero_pivots, nonzero_pivots)
00547 .template triangularView<Upper>()
00548 .solveInPlace(c.topRows(nonzero_pivots));
00549
00550 for(Index i = 0; i < nonzero_pivots; ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i);
00551 for(Index i = nonzero_pivots; i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero();
00552 }
00553 };
00554
00555 }
00556
00558 template<typename MatrixType>
00559 typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType>
00560 ::householderQ() const
00561 {
00562 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00563 return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()).setLength(m_nonzero_pivots);
00564 }
00565
00570 template<typename Derived>
00571 const ColPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
00572 MatrixBase<Derived>::colPivHouseholderQr() const
00573 {
00574 return ColPivHouseholderQR<PlainObject>(eval());
00575 }
00576
00577 }
00578
00579 #endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H