MOAB  4.9.3pre
FullPivHouseholderQR.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_FULLPIVOTINGHOUSEHOLDERQR_H
00012 #define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
00013 
00014 namespace Eigen { 
00015 
00016 namespace internal {
00017 
00018 template<typename _MatrixType> struct traits<FullPivHouseholderQR<_MatrixType> >
00019  : traits<_MatrixType>
00020 {
00021   enum { Flags = 0 };
00022 };
00023 
00024 template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType;
00025 
00026 template<typename MatrixType>
00027 struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
00028 {
00029   typedef typename MatrixType::PlainObject ReturnType;
00030 };
00031 
00032 } // end namespace internal
00033 
00055 template<typename _MatrixType> class FullPivHouseholderQR
00056 {
00057   public:
00058 
00059     typedef _MatrixType MatrixType;
00060     enum {
00061       RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00062       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00063       Options = MatrixType::Options,
00064       MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00065       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
00066     };
00067     typedef typename MatrixType::Scalar Scalar;
00068     typedef typename MatrixType::RealScalar RealScalar;
00069     // FIXME should be int
00070     typedef typename MatrixType::StorageIndex StorageIndex;
00071     typedef internal::FullPivHouseholderQRMatrixQReturnType<MatrixType> MatrixQReturnType;
00072     typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
00073     typedef Matrix<StorageIndex, 1,
00074                    EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime,RowsAtCompileTime), RowMajor, 1,
00075                    EIGEN_SIZE_MIN_PREFER_FIXED(MaxColsAtCompileTime,MaxRowsAtCompileTime)> IntDiagSizeVectorType;
00076     typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
00077     typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
00078     typedef typename internal::plain_col_type<MatrixType>::type ColVectorType;
00079     typedef typename MatrixType::PlainObject PlainObject;
00080 
00086     FullPivHouseholderQR()
00087       : m_qr(),
00088         m_hCoeffs(),
00089         m_rows_transpositions(),
00090         m_cols_transpositions(),
00091         m_cols_permutation(),
00092         m_temp(),
00093         m_isInitialized(false),
00094         m_usePrescribedThreshold(false) {}
00095 
00102     FullPivHouseholderQR(Index rows, Index cols)
00103       : m_qr(rows, cols),
00104         m_hCoeffs((std::min)(rows,cols)),
00105         m_rows_transpositions((std::min)(rows,cols)),
00106         m_cols_transpositions((std::min)(rows,cols)),
00107         m_cols_permutation(cols),
00108         m_temp(cols),
00109         m_isInitialized(false),
00110         m_usePrescribedThreshold(false) {}
00111 
00124     template<typename InputType>
00125     explicit FullPivHouseholderQR(const EigenBase<InputType>& matrix)
00126       : m_qr(matrix.rows(), matrix.cols()),
00127         m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
00128         m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
00129         m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
00130         m_cols_permutation(matrix.cols()),
00131         m_temp(matrix.cols()),
00132         m_isInitialized(false),
00133         m_usePrescribedThreshold(false)
00134     {
00135       compute(matrix.derived());
00136     }
00137 
00156     template<typename Rhs>
00157     inline const Solve<FullPivHouseholderQR, Rhs>
00158     solve(const MatrixBase<Rhs>& b) const
00159     {
00160       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00161       return Solve<FullPivHouseholderQR, Rhs>(*this, b.derived());
00162     }
00163 
00166     MatrixQReturnType matrixQ(void) const;
00167 
00170     const MatrixType& matrixQR() const
00171     {
00172       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00173       return m_qr;
00174     }
00175 
00176     template<typename InputType>
00177     FullPivHouseholderQR& compute(const EigenBase<InputType>& matrix);
00178 
00180     const PermutationType& colsPermutation() const
00181     {
00182       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00183       return m_cols_permutation;
00184     }
00185 
00187     const IntDiagSizeVectorType& rowsTranspositions() const
00188     {
00189       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00190       return m_rows_transpositions;
00191     }
00192 
00206     typename MatrixType::RealScalar absDeterminant() const;
00207 
00220     typename MatrixType::RealScalar logAbsDeterminant() const;
00221 
00228     inline Index rank() const
00229     {
00230       using std::abs;
00231       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00232       RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
00233       Index result = 0;
00234       for(Index i = 0; i < m_nonzero_pivots; ++i)
00235         result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
00236       return result;
00237     }
00238 
00245     inline Index dimensionOfKernel() const
00246     {
00247       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00248       return cols() - rank();
00249     }
00250 
00258     inline bool isInjective() const
00259     {
00260       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00261       return rank() == cols();
00262     }
00263 
00271     inline bool isSurjective() const
00272     {
00273       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00274       return rank() == rows();
00275     }
00276 
00283     inline bool isInvertible() const
00284     {
00285       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00286       return isInjective() && isSurjective();
00287     }
00288 
00294     inline const Inverse<FullPivHouseholderQR> inverse() const
00295     {
00296       eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00297       return Inverse<FullPivHouseholderQR>(*this);
00298     }
00299 
00300     inline Index rows() const { return m_qr.rows(); }
00301     inline Index cols() const { return m_qr.cols(); }
00302     
00307     const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
00308 
00326     FullPivHouseholderQR& setThreshold(const RealScalar& threshold)
00327     {
00328       m_usePrescribedThreshold = true;
00329       m_prescribedThreshold = threshold;
00330       return *this;
00331     }
00332 
00341     FullPivHouseholderQR& setThreshold(Default_t)
00342     {
00343       m_usePrescribedThreshold = false;
00344       return *this;
00345     }
00346 
00351     RealScalar threshold() const
00352     {
00353       eigen_assert(m_isInitialized || m_usePrescribedThreshold);
00354       return m_usePrescribedThreshold ? m_prescribedThreshold
00355       // this formula comes from experimenting (see "LU precision tuning" thread on the list)
00356       // and turns out to be identical to Higham's formula used already in LDLt.
00357                                       : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
00358     }
00359 
00367     inline Index nonzeroPivots() const
00368     {
00369       eigen_assert(m_isInitialized && "LU is not initialized.");
00370       return m_nonzero_pivots;
00371     }
00372 
00376     RealScalar maxPivot() const { return m_maxpivot; }
00377     
00378     #ifndef EIGEN_PARSED_BY_DOXYGEN
00379     template<typename RhsType, typename DstType>
00380     EIGEN_DEVICE_FUNC
00381     void _solve_impl(const RhsType &rhs, DstType &dst) const;
00382     #endif
00383 
00384   protected:
00385     
00386     static void check_template_parameters()
00387     {
00388       EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
00389     }
00390     
00391     void computeInPlace();
00392     
00393     MatrixType m_qr;
00394     HCoeffsType m_hCoeffs;
00395     IntDiagSizeVectorType m_rows_transpositions;
00396     IntDiagSizeVectorType m_cols_transpositions;
00397     PermutationType m_cols_permutation;
00398     RowVectorType m_temp;
00399     bool m_isInitialized, m_usePrescribedThreshold;
00400     RealScalar m_prescribedThreshold, m_maxpivot;
00401     Index m_nonzero_pivots;
00402     RealScalar m_precision;
00403     Index m_det_pq;
00404 };
00405 
00406 template<typename MatrixType>
00407 typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::absDeterminant() const
00408 {
00409   using std::abs;
00410   eigen_assert(m_isInitialized && "FullPivHouseholderQR 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 abs(m_qr.diagonal().prod());
00413 }
00414 
00415 template<typename MatrixType>
00416 typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDeterminant() const
00417 {
00418   eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00419   eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
00420   return m_qr.diagonal().cwiseAbs().array().log().sum();
00421 }
00422 
00429 template<typename MatrixType>
00430 template<typename InputType>
00431 FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const EigenBase<InputType>& matrix)
00432 {
00433   check_template_parameters();
00434   
00435   m_qr = matrix.derived();
00436   
00437   computeInPlace();
00438   
00439   return *this;
00440 }
00441 
00442 template<typename MatrixType>
00443 void FullPivHouseholderQR<MatrixType>::computeInPlace()
00444 {
00445   using std::abs;
00446   Index rows = m_qr.rows();
00447   Index cols = m_qr.cols();
00448   Index size = (std::min)(rows,cols);
00449 
00450   
00451   m_hCoeffs.resize(size);
00452 
00453   m_temp.resize(cols);
00454 
00455   m_precision = NumTraits<Scalar>::epsilon() * RealScalar(size);
00456 
00457   m_rows_transpositions.resize(size);
00458   m_cols_transpositions.resize(size);
00459   Index number_of_transpositions = 0;
00460 
00461   RealScalar biggest(0);
00462 
00463   m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
00464   m_maxpivot = RealScalar(0);
00465 
00466   for (Index k = 0; k < size; ++k)
00467   {
00468     Index row_of_biggest_in_corner, col_of_biggest_in_corner;
00469     typedef internal::scalar_score_coeff_op<Scalar> Scoring;
00470     typedef typename Scoring::result_type Score;
00471 
00472     Score score = m_qr.bottomRightCorner(rows-k, cols-k)
00473                       .unaryExpr(Scoring())
00474                       .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
00475     row_of_biggest_in_corner += k;
00476     col_of_biggest_in_corner += k;
00477     RealScalar biggest_in_corner = internal::abs_knowing_score<Scalar>()(m_qr(row_of_biggest_in_corner, col_of_biggest_in_corner), score);
00478     if(k==0) biggest = biggest_in_corner;
00479 
00480     // if the corner is negligible, then we have less than full rank, and we can finish early
00481     if(internal::isMuchSmallerThan(biggest_in_corner, biggest, m_precision))
00482     {
00483       m_nonzero_pivots = k;
00484       for(Index i = k; i < size; i++)
00485       {
00486         m_rows_transpositions.coeffRef(i) = i;
00487         m_cols_transpositions.coeffRef(i) = i;
00488         m_hCoeffs.coeffRef(i) = Scalar(0);
00489       }
00490       break;
00491     }
00492 
00493     m_rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
00494     m_cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
00495     if(k != row_of_biggest_in_corner) {
00496       m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
00497       ++number_of_transpositions;
00498     }
00499     if(k != col_of_biggest_in_corner) {
00500       m_qr.col(k).swap(m_qr.col(col_of_biggest_in_corner));
00501       ++number_of_transpositions;
00502     }
00503 
00504     RealScalar beta;
00505     m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
00506     m_qr.coeffRef(k,k) = beta;
00507 
00508     // remember the maximum absolute value of diagonal coefficients
00509     if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
00510 
00511     m_qr.bottomRightCorner(rows-k, cols-k-1)
00512         .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
00513   }
00514 
00515   m_cols_permutation.setIdentity(cols);
00516   for(Index k = 0; k < size; ++k)
00517     m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));
00518 
00519   m_det_pq = (number_of_transpositions%2) ? -1 : 1;
00520   m_isInitialized = true;
00521 }
00522 
00523 #ifndef EIGEN_PARSED_BY_DOXYGEN
00524 template<typename _MatrixType>
00525 template<typename RhsType, typename DstType>
00526 void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
00527 {
00528   eigen_assert(rhs.rows() == rows());
00529   const Index l_rank = rank();
00530 
00531   // FIXME introduce nonzeroPivots() and use it here. and more generally,
00532   // make the same improvements in this dec as in FullPivLU.
00533   if(l_rank==0)
00534   {
00535     dst.setZero();
00536     return;
00537   }
00538 
00539   typename RhsType::PlainObject c(rhs);
00540 
00541   Matrix<Scalar,1,RhsType::ColsAtCompileTime> temp(rhs.cols());
00542   for (Index k = 0; k < l_rank; ++k)
00543   {
00544     Index remainingSize = rows()-k;
00545     c.row(k).swap(c.row(m_rows_transpositions.coeff(k)));
00546     c.bottomRightCorner(remainingSize, rhs.cols())
00547       .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1),
00548                                m_hCoeffs.coeff(k), &temp.coeffRef(0));
00549   }
00550 
00551   m_qr.topLeftCorner(l_rank, l_rank)
00552       .template triangularView<Upper>()
00553       .solveInPlace(c.topRows(l_rank));
00554 
00555   for(Index i = 0; i < l_rank; ++i) dst.row(m_cols_permutation.indices().coeff(i)) = c.row(i);
00556   for(Index i = l_rank; i < cols(); ++i) dst.row(m_cols_permutation.indices().coeff(i)).setZero();
00557 }
00558 #endif
00559 
00560 namespace internal {
00561   
00562 template<typename DstXprType, typename MatrixType, typename Scalar>
00563 struct Assignment<DstXprType, Inverse<FullPivHouseholderQR<MatrixType> >, internal::assign_op<Scalar>, Dense2Dense, Scalar>
00564 {
00565   typedef FullPivHouseholderQR<MatrixType> QrType;
00566   typedef Inverse<QrType> SrcXprType;
00567   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar> &)
00568   {    
00569     dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
00570   }
00571 };
00572 
00579 template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType
00580   : public ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
00581 {
00582 public:
00583   typedef typename FullPivHouseholderQR<MatrixType>::IntDiagSizeVectorType IntDiagSizeVectorType;
00584   typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
00585   typedef Matrix<typename MatrixType::Scalar, 1, MatrixType::RowsAtCompileTime, RowMajor, 1,
00586                  MatrixType::MaxRowsAtCompileTime> WorkVectorType;
00587 
00588   FullPivHouseholderQRMatrixQReturnType(const MatrixType&       qr,
00589                                         const HCoeffsType&      hCoeffs,
00590                                         const IntDiagSizeVectorType& rowsTranspositions)
00591     : m_qr(qr),
00592       m_hCoeffs(hCoeffs),
00593       m_rowsTranspositions(rowsTranspositions)
00594   {}
00595 
00596   template <typename ResultType>
00597   void evalTo(ResultType& result) const
00598   {
00599     const Index rows = m_qr.rows();
00600     WorkVectorType workspace(rows);
00601     evalTo(result, workspace);
00602   }
00603 
00604   template <typename ResultType>
00605   void evalTo(ResultType& result, WorkVectorType& workspace) const
00606   {
00607     using numext::conj;
00608     // compute the product H'_0 H'_1 ... H'_n-1,
00609     // where H_k is the k-th Householder transformation I - h_k v_k v_k'
00610     // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
00611     const Index rows = m_qr.rows();
00612     const Index cols = m_qr.cols();
00613     const Index size = (std::min)(rows, cols);
00614     workspace.resize(rows);
00615     result.setIdentity(rows, rows);
00616     for (Index k = size-1; k >= 0; k--)
00617     {
00618       result.block(k, k, rows-k, rows-k)
00619             .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k));
00620       result.row(k).swap(result.row(m_rowsTranspositions.coeff(k)));
00621     }
00622   }
00623 
00624   Index rows() const { return m_qr.rows(); }
00625   Index cols() const { return m_qr.rows(); }
00626 
00627 protected:
00628   typename MatrixType::Nested m_qr;
00629   typename HCoeffsType::Nested m_hCoeffs;
00630   typename IntDiagSizeVectorType::Nested m_rowsTranspositions;
00631 };
00632 
00633 // template<typename MatrixType>
00634 // struct evaluator<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
00635 //  : public evaluator<ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> > >
00636 // {};
00637 
00638 } // end namespace internal
00639 
00640 template<typename MatrixType>
00641 inline typename FullPivHouseholderQR<MatrixType>::MatrixQReturnType FullPivHouseholderQR<MatrixType>::matrixQ() const
00642 {
00643   eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
00644   return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions);
00645 }
00646 
00647 #ifndef __CUDACC__
00648 
00652 template<typename Derived>
00653 const FullPivHouseholderQR<typename MatrixBase<Derived>::PlainObject>
00654 MatrixBase<Derived>::fullPivHouseholderQr() const
00655 {
00656   return FullPivHouseholderQR<PlainObject>(eval());
00657 }
00658 #endif // __CUDACC__
00659 
00660 } // end namespace Eigen
00661 
00662 #endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines