MOAB
4.9.3pre
|
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