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