MOAB  4.9.3pre
CompleteOrthogonalDecomposition.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) 2016 Rasmus Munk Larsen <[email protected]>
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #ifndef EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
00011 #define EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
00012 
00013 namespace Eigen {
00014 
00015 namespace internal {
00016 template <typename _MatrixType>
00017 struct traits<CompleteOrthogonalDecomposition<_MatrixType> >
00018     : traits<_MatrixType> {
00019   enum { Flags = 0 };
00020 };
00021 
00022 }  // end namespace internal
00023 
00044 template <typename _MatrixType>
00045 class CompleteOrthogonalDecomposition {
00046  public:
00047   typedef _MatrixType MatrixType;
00048   enum {
00049     RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00050     ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00051     Options = MatrixType::Options,
00052     MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00053     MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
00054   };
00055   typedef typename MatrixType::Scalar Scalar;
00056   typedef typename MatrixType::RealScalar RealScalar;
00057   typedef typename MatrixType::StorageIndex StorageIndex;
00058   typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, Options,
00059                  MaxRowsAtCompileTime, MaxRowsAtCompileTime>
00060       MatrixQType;
00061   typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
00062   typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime>
00063       PermutationType;
00064   typedef typename internal::plain_row_type<MatrixType, Index>::type
00065       IntRowVectorType;
00066   typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
00067   typedef typename internal::plain_row_type<MatrixType, RealScalar>::type
00068       RealRowVectorType;
00069   typedef HouseholderSequence<
00070       MatrixType, typename internal::remove_all<
00071                       typename HCoeffsType::ConjugateReturnType>::type>
00072       HouseholderSequenceType;
00073   typedef typename MatrixType::PlainObject PlainObject;
00074 
00075  private:
00076   typedef typename PermutationType::Index PermIndexType;
00077 
00078  public:
00086   CompleteOrthogonalDecomposition() : m_cpqr(), m_zCoeffs(), m_temp() {}
00087 
00094   CompleteOrthogonalDecomposition(Index rows, Index cols)
00095       : m_cpqr(rows, cols), m_zCoeffs((std::min)(rows, cols)), m_temp(cols) {}
00096 
00113   template <typename InputType>
00114   explicit CompleteOrthogonalDecomposition(const EigenBase<InputType>& matrix)
00115       : m_cpqr(matrix.rows(), matrix.cols()),
00116         m_zCoeffs((std::min)(matrix.rows(), matrix.cols())),
00117         m_temp(matrix.cols()) {
00118     compute(matrix.derived());
00119   }
00120 
00130   template <typename Rhs>
00131   inline const Solve<CompleteOrthogonalDecomposition, Rhs> solve(
00132       const MatrixBase<Rhs>& b) const {
00133     eigen_assert(m_cpqr.m_isInitialized &&
00134                  "CompleteOrthogonalDecomposition is not initialized.");
00135     return Solve<CompleteOrthogonalDecomposition, Rhs>(*this, b.derived());
00136   }
00137 
00138   HouseholderSequenceType householderQ(void) const;
00139   HouseholderSequenceType matrixQ(void) const { return m_cpqr.householderQ(); }
00140 
00143   MatrixType matrixZ() const {
00144     MatrixType Z = MatrixType::Identity(m_cpqr.cols(), m_cpqr.cols());
00145     applyZAdjointOnTheLeftInPlace(Z);
00146     return Z.adjoint();
00147   }
00148 
00152   const MatrixType& matrixQTZ() const { return m_cpqr.matrixQR(); }
00153 
00165   const MatrixType& matrixT() const { return m_cpqr.matrixQR(); }
00166 
00167   template <typename InputType>
00168   CompleteOrthogonalDecomposition& compute(const EigenBase<InputType>& matrix);
00169 
00171   const PermutationType& colsPermutation() const {
00172     return m_cpqr.colsPermutation();
00173   }
00174 
00188   typename MatrixType::RealScalar absDeterminant() const;
00189 
00203   typename MatrixType::RealScalar logAbsDeterminant() const;
00204 
00212   inline Index rank() const { return m_cpqr.rank(); }
00213 
00221   inline Index dimensionOfKernel() const { return m_cpqr.dimensionOfKernel(); }
00222 
00230   inline bool isInjective() const { return m_cpqr.isInjective(); }
00231 
00239   inline bool isSurjective() const { return m_cpqr.isSurjective(); }
00240 
00248   inline bool isInvertible() const { return m_cpqr.isInvertible(); }
00249 
00255   inline const Inverse<CompleteOrthogonalDecomposition> pseudoInverse() const
00256   {
00257     return Inverse<CompleteOrthogonalDecomposition>(*this);
00258   }
00259 
00260   inline Index rows() const { return m_cpqr.rows(); }
00261   inline Index cols() const { return m_cpqr.cols(); }
00262 
00268   inline const HCoeffsType& hCoeffs() const { return m_cpqr.hCoeffs(); }
00269 
00275   const HCoeffsType& zCoeffs() const { return m_zCoeffs; }
00276 
00296   CompleteOrthogonalDecomposition& setThreshold(const RealScalar& threshold) {
00297     m_cpqr.setThreshold(threshold);
00298     return *this;
00299   }
00300 
00309   CompleteOrthogonalDecomposition& setThreshold(Default_t) {
00310     m_cpqr.setThreshold(Default);
00311     return *this;
00312   }
00313 
00318   RealScalar threshold() const { return m_cpqr.threshold(); }
00319 
00327   inline Index nonzeroPivots() const { return m_cpqr.nonzeroPivots(); }
00328 
00332   inline RealScalar maxPivot() const { return m_cpqr.maxPivot(); }
00333 
00342   ComputationInfo info() const {
00343     eigen_assert(m_cpqr.m_isInitialized && "Decomposition is not initialized.");
00344     return Success;
00345   }
00346 
00347 #ifndef EIGEN_PARSED_BY_DOXYGEN
00348   template <typename RhsType, typename DstType>
00349   EIGEN_DEVICE_FUNC void _solve_impl(const RhsType& rhs, DstType& dst) const;
00350 #endif
00351 
00352  protected:
00353   static void check_template_parameters() {
00354     EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
00355   }
00356 
00359   template <typename Rhs>
00360   void applyZAdjointOnTheLeftInPlace(Rhs& rhs) const;
00361 
00362   ColPivHouseholderQR<MatrixType> m_cpqr;
00363   HCoeffsType m_zCoeffs;
00364   RowVectorType m_temp;
00365 };
00366 
00367 template <typename MatrixType>
00368 typename MatrixType::RealScalar
00369 CompleteOrthogonalDecomposition<MatrixType>::absDeterminant() const {
00370   return m_cpqr.absDeterminant();
00371 }
00372 
00373 template <typename MatrixType>
00374 typename MatrixType::RealScalar
00375 CompleteOrthogonalDecomposition<MatrixType>::logAbsDeterminant() const {
00376   return m_cpqr.logAbsDeterminant();
00377 }
00378 
00386 template <typename MatrixType>
00387 template <typename InputType>
00388 CompleteOrthogonalDecomposition<MatrixType>& CompleteOrthogonalDecomposition<
00389     MatrixType>::compute(const EigenBase<InputType>& matrix) {
00390   check_template_parameters();
00391 
00392   // the column permutation is stored as int indices, so just to be sure:
00393   eigen_assert(matrix.cols() <= NumTraits<int>::highest());
00394 
00395   // Compute the column pivoted QR factorization A P = Q R.
00396   m_cpqr.compute(matrix);
00397 
00398   const Index rank = m_cpqr.rank();
00399   const Index cols = matrix.cols();
00400   if (rank < cols) {
00401     // We have reduced the (permuted) matrix to the form
00402     //   [R11 R12]
00403     //   [ 0  R22]
00404     // where R11 is r-by-r (r = rank) upper triangular, R12 is
00405     // r-by-(n-r), and R22 is empty or the norm of R22 is negligible.
00406     // We now compute the complete orthogonal decomposition by applying
00407     // Householder transformations from the right to the upper trapezoidal
00408     // matrix X = [R11 R12] to zero out R12 and obtain the factorization
00409     // [R11 R12] = [T11 0] * Z, where T11 is r-by-r upper triangular and
00410     // Z = Z(0) * Z(1) ... Z(r-1) is an n-by-n orthogonal matrix.
00411     // We store the data representing Z in R12 and m_zCoeffs.
00412     for (Index k = rank - 1; k >= 0; --k) {
00413       if (k != rank - 1) {
00414         // Given the API for Householder reflectors, it is more convenient if
00415         // we swap the leading parts of columns k and r-1 (zero-based) to form
00416         // the matrix X_k = [X(0:k, k), X(0:k, r:n)]
00417         m_cpqr.m_qr.col(k).head(k + 1).swap(
00418             m_cpqr.m_qr.col(rank - 1).head(k + 1));
00419       }
00420       // Construct Householder reflector Z(k) to zero out the last row of X_k,
00421       // i.e. choose Z(k) such that
00422       // [X(k, k), X(k, r:n)] * Z(k) = [beta, 0, .., 0].
00423       RealScalar beta;
00424       m_cpqr.m_qr.row(k)
00425           .tail(cols - rank + 1)
00426           .makeHouseholderInPlace(m_zCoeffs(k), beta);
00427       m_cpqr.m_qr(k, rank - 1) = beta;
00428       if (k > 0) {
00429         // Apply Z(k) to the first k rows of X_k
00430         m_cpqr.m_qr.topRightCorner(k, cols - rank + 1)
00431             .applyHouseholderOnTheRight(
00432                 m_cpqr.m_qr.row(k).tail(cols - rank).transpose(), m_zCoeffs(k),
00433                 &m_temp(0));
00434       }
00435       if (k != rank - 1) {
00436         // Swap X(0:k,k) back to its proper location.
00437         m_cpqr.m_qr.col(k).head(k + 1).swap(
00438             m_cpqr.m_qr.col(rank - 1).head(k + 1));
00439       }
00440     }
00441   }
00442   return *this;
00443 }
00444 
00445 template <typename MatrixType>
00446 template <typename Rhs>
00447 void CompleteOrthogonalDecomposition<MatrixType>::applyZAdjointOnTheLeftInPlace(
00448     Rhs& rhs) const {
00449   const Index cols = this->cols();
00450   const Index nrhs = rhs.cols();
00451   const Index rank = this->rank();
00452   Matrix<typename MatrixType::Scalar, Dynamic, 1> temp((std::max)(cols, nrhs));
00453   for (Index k = 0; k < rank; ++k) {
00454     if (k != rank - 1) {
00455       rhs.row(k).swap(rhs.row(rank - 1));
00456     }
00457     rhs.middleRows(rank - 1, cols - rank + 1)
00458         .applyHouseholderOnTheLeft(
00459             matrixQTZ().row(k).tail(cols - rank).adjoint(), zCoeffs()(k),
00460             &temp(0));
00461     if (k != rank - 1) {
00462       rhs.row(k).swap(rhs.row(rank - 1));
00463     }
00464   }
00465 }
00466 
00467 #ifndef EIGEN_PARSED_BY_DOXYGEN
00468 template <typename _MatrixType>
00469 template <typename RhsType, typename DstType>
00470 void CompleteOrthogonalDecomposition<_MatrixType>::_solve_impl(
00471     const RhsType& rhs, DstType& dst) const {
00472   eigen_assert(rhs.rows() == this->rows());
00473 
00474   const Index rank = this->rank();
00475   if (rank == 0) {
00476     dst.setZero();
00477     return;
00478   }
00479 
00480   // Compute c = Q^* * rhs
00481   // Note that the matrix Q = H_0^* H_1^*... so its inverse is
00482   // Q^* = (H_0 H_1 ...)^T
00483   typename RhsType::PlainObject c(rhs);
00484   c.applyOnTheLeft(
00485       householderSequence(matrixQTZ(), hCoeffs()).setLength(rank).transpose());
00486 
00487   // Solve T z = c(1:rank, :)
00488   dst.topRows(rank) = matrixT()
00489                           .topLeftCorner(rank, rank)
00490                           .template triangularView<Upper>()
00491                           .solve(c.topRows(rank));
00492 
00493   const Index cols = this->cols();
00494   if (rank < cols) {
00495     // Compute y = Z^* * [ z ]
00496     //                   [ 0 ]
00497     dst.bottomRows(cols - rank).setZero();
00498     applyZAdjointOnTheLeftInPlace(dst);
00499   }
00500 
00501   // Undo permutation to get x = P^{-1} * y.
00502   dst = colsPermutation() * dst;
00503 }
00504 #endif
00505 
00506 namespace internal {
00507 
00508 template<typename DstXprType, typename MatrixType, typename Scalar>
00509 struct Assignment<DstXprType, Inverse<CompleteOrthogonalDecomposition<MatrixType> >, internal::assign_op<Scalar>, Dense2Dense, Scalar>
00510 {
00511   typedef CompleteOrthogonalDecomposition<MatrixType> CodType;
00512   typedef Inverse<CodType> SrcXprType;
00513   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar> &)
00514   {
00515     dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.rows()));
00516   }
00517 };
00518 
00519 } // end namespace internal
00520 
00522 template <typename MatrixType>
00523 typename CompleteOrthogonalDecomposition<MatrixType>::HouseholderSequenceType
00524 CompleteOrthogonalDecomposition<MatrixType>::householderQ() const {
00525   return m_cpqr.householderQ();
00526 }
00527 
00528 #ifndef __CUDACC__
00529 
00533 template <typename Derived>
00534 const CompleteOrthogonalDecomposition<typename MatrixBase<Derived>::PlainObject>
00535 MatrixBase<Derived>::completeOrthogonalDecomposition() const {
00536   return CompleteOrthogonalDecomposition<PlainObject>(eval());
00537 }
00538 #endif  // __CUDACC__
00539 
00540 }  // end namespace Eigen
00541 
00542 #endif  // EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines