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_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