MOAB  4.9.3pre
ColPivHouseholderQR.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2008-2009 Gael Guennebaud <[email protected]>
00005 // Copyright (C) 2009 Benoit Jacob <[email protected]>
00006 //
00007 // This Source Code Form is subject to the terms of the Mozilla
00008 // Public License v. 2.0. If a copy of the MPL was not distributed
00009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00010 
00011 #ifndef EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
00012 #define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
00013 
00014 namespace Eigen {
00015 
00016 namespace internal {
00017 template<typename _MatrixType> struct traits<ColPivHouseholderQR<_MatrixType> >
00018  : traits<_MatrixType>
00019 {
00020   enum { Flags = 0 };
00021 };
00022 
00023 } // end namespace internal
00024 
00046 template<typename _MatrixType> class ColPivHouseholderQR
00047 {
00048   public:
00049 
00050     typedef _MatrixType MatrixType;
00051     enum {
00052       RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00053       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00054       Options = MatrixType::Options,
00055       MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00056       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
00057     };
00058     typedef typename MatrixType::Scalar Scalar;
00059     typedef typename MatrixType::RealScalar RealScalar;
00060     // FIXME should be int
00061     typedef typename MatrixType::StorageIndex StorageIndex;
00062     typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, Options, MaxRowsAtCompileTime, MaxRowsAtCompileTime> MatrixQType;
00063     typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
00064     typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
00065     typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
00066     typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
00067     typedef typename internal::plain_row_type<MatrixType, RealScalar>::type RealRowVectorType;
00068     typedef HouseholderSequence<MatrixType,typename internal::remove_all<typename HCoeffsType::ConjugateReturnType>::type> HouseholderSequenceType;
00069     typedef typename MatrixType::PlainObject PlainObject;
00070 
00071   private:
00072 
00073     typedef typename PermutationType::StorageIndex PermIndexType;
00074 
00075   public:
00076 
00083     ColPivHouseholderQR()
00084       : m_qr(),
00085         m_hCoeffs(),
00086         m_colsPermutation(),
00087         m_colsTranspositions(),
00088         m_temp(),
00089         m_colNormsUpdated(),
00090         m_colNormsDirect(),
00091         m_isInitialized(false),
00092         m_usePrescribedThreshold(false) {}
00093 
00100     ColPivHouseholderQR(Index rows, Index cols)
00101       : m_qr(rows, cols),
00102         m_hCoeffs((std::min)(rows,cols)),
00103         m_colsPermutation(PermIndexType(cols)),
00104         m_colsTranspositions(cols),
00105         m_temp(cols),
00106         m_colNormsUpdated(cols),
00107         m_colNormsDirect(cols),
00108         m_isInitialized(false),
00109         m_usePrescribedThreshold(false) {}
00110 
00123     template<typename InputType>
00124     explicit ColPivHouseholderQR(const EigenBase<InputType>& matrix)
00125       : m_qr(matrix.rows(), matrix.cols()),
00126         m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
00127         m_colsPermutation(PermIndexType(matrix.cols())),
00128         m_colsTranspositions(matrix.cols()),
00129         m_temp(matrix.cols()),
00130         m_colNormsUpdated(matrix.cols()),
00131         m_colNormsDirect(matrix.cols()),
00132         m_isInitialized(false),
00133         m_usePrescribedThreshold(false)
00134     {
00135       compute(matrix.derived());
00136     }
00137 
00155     template<typename Rhs>
00156     inline const Solve<ColPivHouseholderQR, Rhs>
00157     solve(const MatrixBase<Rhs>& b) const
00158     {
00159       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00160       return Solve<ColPivHouseholderQR, Rhs>(*this, b.derived());
00161     }
00162 
00163     HouseholderSequenceType householderQ() const;
00164     HouseholderSequenceType matrixQ() const
00165     {
00166       return householderQ();
00167     }
00168 
00171     const MatrixType& matrixQR() const
00172     {
00173       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00174       return m_qr;
00175     }
00176 
00186     const MatrixType& matrixR() const
00187     {
00188       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00189       return m_qr;
00190     }
00191 
00192     template<typename InputType>
00193     ColPivHouseholderQR& compute(const EigenBase<InputType>& matrix);
00194 
00196     const PermutationType& colsPermutation() const
00197     {
00198       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00199       return m_colsPermutation;
00200     }
00201 
00215     typename MatrixType::RealScalar absDeterminant() const;
00216 
00229     typename MatrixType::RealScalar logAbsDeterminant() const;
00230 
00237     inline Index rank() const
00238     {
00239       using std::abs;
00240       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00241       RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
00242       Index result = 0;
00243       for(Index i = 0; i < m_nonzero_pivots; ++i)
00244         result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
00245       return result;
00246     }
00247 
00254     inline Index dimensionOfKernel() const
00255     {
00256       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00257       return cols() - rank();
00258     }
00259 
00267     inline bool isInjective() const
00268     {
00269       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00270       return rank() == cols();
00271     }
00272 
00280     inline bool isSurjective() const
00281     {
00282       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00283       return rank() == rows();
00284     }
00285 
00292     inline bool isInvertible() const
00293     {
00294       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00295       return isInjective() && isSurjective();
00296     }
00297 
00303     inline const Inverse<ColPivHouseholderQR> inverse() const
00304     {
00305       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00306       return Inverse<ColPivHouseholderQR>(*this);
00307     }
00308 
00309     inline Index rows() const { return m_qr.rows(); }
00310     inline Index cols() const { return m_qr.cols(); }
00311 
00316     const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
00317 
00335     ColPivHouseholderQR& setThreshold(const RealScalar& threshold)
00336     {
00337       m_usePrescribedThreshold = true;
00338       m_prescribedThreshold = threshold;
00339       return *this;
00340     }
00341 
00350     ColPivHouseholderQR& setThreshold(Default_t)
00351     {
00352       m_usePrescribedThreshold = false;
00353       return *this;
00354     }
00355 
00360     RealScalar threshold() const
00361     {
00362       eigen_assert(m_isInitialized || m_usePrescribedThreshold);
00363       return m_usePrescribedThreshold ? m_prescribedThreshold
00364       // this formula comes from experimenting (see "LU precision tuning" thread on the list)
00365       // and turns out to be identical to Higham's formula used already in LDLt.
00366                                       : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
00367     }
00368 
00376     inline Index nonzeroPivots() const
00377     {
00378       eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00379       return m_nonzero_pivots;
00380     }
00381 
00385     RealScalar maxPivot() const { return m_maxpivot; }
00386 
00393     ComputationInfo info() const
00394     {
00395       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
00396       return Success;
00397     }
00398 
00399     #ifndef EIGEN_PARSED_BY_DOXYGEN
00400     template<typename RhsType, typename DstType>
00401     EIGEN_DEVICE_FUNC
00402     void _solve_impl(const RhsType &rhs, DstType &dst) const;
00403     #endif
00404 
00405   protected:
00406 
00407     friend class CompleteOrthogonalDecomposition<MatrixType>;
00408 
00409     static void check_template_parameters()
00410     {
00411       EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
00412     }
00413 
00414     void computeInPlace();
00415 
00416     MatrixType m_qr;
00417     HCoeffsType m_hCoeffs;
00418     PermutationType m_colsPermutation;
00419     IntRowVectorType m_colsTranspositions;
00420     RowVectorType m_temp;
00421     RealRowVectorType m_colNormsUpdated;
00422     RealRowVectorType m_colNormsDirect;
00423     bool m_isInitialized, m_usePrescribedThreshold;
00424     RealScalar m_prescribedThreshold, m_maxpivot;
00425     Index m_nonzero_pivots;
00426     Index m_det_pq;
00427 };
00428 
00429 template<typename MatrixType>
00430 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::absDeterminant() const
00431 {
00432   using std::abs;
00433   eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00434   eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
00435   return abs(m_qr.diagonal().prod());
00436 }
00437 
00438 template<typename MatrixType>
00439 typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDeterminant() const
00440 {
00441   eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00442   eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
00443   return m_qr.diagonal().cwiseAbs().array().log().sum();
00444 }
00445 
00452 template<typename MatrixType>
00453 template<typename InputType>
00454 ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const EigenBase<InputType>& matrix)
00455 {
00456   check_template_parameters();
00457 
00458   // the column permutation is stored as int indices, so just to be sure:
00459   eigen_assert(matrix.cols()<=NumTraits<int>::highest());
00460 
00461   m_qr = matrix;
00462 
00463   computeInPlace();
00464 
00465   return *this;
00466 }
00467 
00468 template<typename MatrixType>
00469 void ColPivHouseholderQR<MatrixType>::computeInPlace()
00470 {
00471   using std::abs;
00472 
00473   Index rows = m_qr.rows();
00474   Index cols = m_qr.cols();
00475   Index size = m_qr.diagonalSize();
00476 
00477   m_hCoeffs.resize(size);
00478 
00479   m_temp.resize(cols);
00480 
00481   m_colsTranspositions.resize(m_qr.cols());
00482   Index number_of_transpositions = 0;
00483 
00484   m_colNormsUpdated.resize(cols);
00485   m_colNormsDirect.resize(cols);
00486   for (Index k = 0; k < cols; ++k) {
00487     // colNormsDirect(k) caches the most recent directly computed norm of
00488     // column k.
00489     m_colNormsDirect.coeffRef(k) = m_qr.col(k).norm();
00490     m_colNormsUpdated.coeffRef(k) = m_colNormsDirect.coeffRef(k);
00491   }
00492 
00493   RealScalar threshold_helper =  numext::abs2(m_colNormsUpdated.maxCoeff() * NumTraits<Scalar>::epsilon()) / RealScalar(rows);
00494   RealScalar norm_downdate_threshold = numext::sqrt(NumTraits<Scalar>::epsilon());
00495 
00496   m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
00497   m_maxpivot = RealScalar(0);
00498 
00499   for(Index k = 0; k < size; ++k)
00500   {
00501     // first, we look up in our table m_colNormsUpdated which column has the biggest norm
00502     Index biggest_col_index;
00503     RealScalar biggest_col_sq_norm = numext::abs2(m_colNormsUpdated.tail(cols-k).maxCoeff(&biggest_col_index));
00504     biggest_col_index += k;
00505 
00506     // Track the number of meaningful pivots but do not stop the decomposition to make
00507     // sure that the initial matrix is properly reproduced. See bug 941.
00508     if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
00509       m_nonzero_pivots = k;
00510 
00511     // apply the transposition to the columns
00512     m_colsTranspositions.coeffRef(k) = biggest_col_index;
00513     if(k != biggest_col_index) {
00514       m_qr.col(k).swap(m_qr.col(biggest_col_index));
00515       std::swap(m_colNormsUpdated.coeffRef(k), m_colNormsUpdated.coeffRef(biggest_col_index));
00516       std::swap(m_colNormsDirect.coeffRef(k), m_colNormsDirect.coeffRef(biggest_col_index));
00517       ++number_of_transpositions;
00518     }
00519 
00520     // generate the householder vector, store it below the diagonal
00521     RealScalar beta;
00522     m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
00523 
00524     // apply the householder transformation to the diagonal coefficient
00525     m_qr.coeffRef(k,k) = beta;
00526 
00527     // remember the maximum absolute value of diagonal coefficients
00528     if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
00529 
00530     // apply the householder transformation
00531     m_qr.bottomRightCorner(rows-k, cols-k-1)
00532         .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
00533 
00534     // update our table of norms of the columns
00535     for (Index j = k + 1; j < cols; ++j) {
00536       // The following implements the stable norm downgrade step discussed in
00537       // http://www.netlib.org/lapack/lawnspdf/lawn176.pdf
00538       // and used in LAPACK routines xGEQPF and xGEQP3.
00539       // See lines 278-297 in http://www.netlib.org/lapack/explore-html/dc/df4/sgeqpf_8f_source.html
00540       if (m_colNormsUpdated.coeffRef(j) != 0) {
00541         RealScalar temp = abs(m_qr.coeffRef(k, j)) / m_colNormsUpdated.coeffRef(j);
00542         temp = (RealScalar(1) + temp) * (RealScalar(1) - temp);
00543         temp = temp < 0 ? 0 : temp;
00544         RealScalar temp2 = temp * numext::abs2(m_colNormsUpdated.coeffRef(j) /
00545                                                m_colNormsDirect.coeffRef(j));
00546         if (temp2 <= norm_downdate_threshold) {
00547           // The updated norm has become too inaccurate so re-compute the column
00548           // norm directly.
00549           m_colNormsDirect.coeffRef(j) = m_qr.col(j).tail(rows - k - 1).norm();
00550           m_colNormsUpdated.coeffRef(j) = m_colNormsDirect.coeffRef(j);
00551         } else {
00552           m_colNormsUpdated.coeffRef(j) *= numext::sqrt(temp);
00553         }
00554       }
00555     }
00556   }
00557 
00558   m_colsPermutation.setIdentity(PermIndexType(cols));
00559   for(PermIndexType k = 0; k < size/*m_nonzero_pivots*/; ++k)
00560     m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(m_colsTranspositions.coeff(k)));
00561 
00562   m_det_pq = (number_of_transpositions%2) ? -1 : 1;
00563   m_isInitialized = true;
00564 }
00565 
00566 #ifndef EIGEN_PARSED_BY_DOXYGEN
00567 template<typename _MatrixType>
00568 template<typename RhsType, typename DstType>
00569 void ColPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
00570 {
00571   eigen_assert(rhs.rows() == rows());
00572 
00573   const Index nonzero_pivots = nonzeroPivots();
00574 
00575   if(nonzero_pivots == 0)
00576   {
00577     dst.setZero();
00578     return;
00579   }
00580 
00581   typename RhsType::PlainObject c(rhs);
00582 
00583   // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T
00584   c.applyOnTheLeft(householderSequence(m_qr, m_hCoeffs)
00585                     .setLength(nonzero_pivots)
00586                     .transpose()
00587     );
00588 
00589   m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
00590       .template triangularView<Upper>()
00591       .solveInPlace(c.topRows(nonzero_pivots));
00592 
00593   for(Index i = 0; i < nonzero_pivots; ++i) dst.row(m_colsPermutation.indices().coeff(i)) = c.row(i);
00594   for(Index i = nonzero_pivots; i < cols(); ++i) dst.row(m_colsPermutation.indices().coeff(i)).setZero();
00595 }
00596 #endif
00597 
00598 namespace internal {
00599 
00600 template<typename DstXprType, typename MatrixType, typename Scalar>
00601 struct Assignment<DstXprType, Inverse<ColPivHouseholderQR<MatrixType> >, internal::assign_op<Scalar>, Dense2Dense, Scalar>
00602 {
00603   typedef ColPivHouseholderQR<MatrixType> QrType;
00604   typedef Inverse<QrType> SrcXprType;
00605   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar> &)
00606   {
00607     dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
00608   }
00609 };
00610 
00611 } // end namespace internal
00612 
00616 template<typename MatrixType>
00617 typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType>
00618   ::householderQ() const
00619 {
00620   eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
00621   return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
00622 }
00623 
00624 #ifndef __CUDACC__
00625 
00629 template<typename Derived>
00630 const ColPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
00631 MatrixBase<Derived>::colPivHouseholderQr() const
00632 {
00633   return ColPivHouseholderQR<PlainObject>(eval());
00634 }
00635 #endif // __CUDACC__
00636 
00637 } // end namespace Eigen
00638 
00639 #endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines