MOAB
4.9.3pre
|
00001 // This file is part of Eigen, a lightweight C++ template library 00002 // for linear algebra. 00003 // 00004 // Copyright (C) 2006-2009 Benoit Jacob <[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_LU_H 00011 #define EIGEN_LU_H 00012 00013 namespace Eigen { 00014 00015 namespace internal { 00016 template<typename _MatrixType> struct traits<FullPivLU<_MatrixType> > 00017 : traits<_MatrixType> 00018 { 00019 typedef MatrixXpr XprKind; 00020 typedef SolverStorage StorageKind; 00021 enum { Flags = 0 }; 00022 }; 00023 00024 } // end namespace internal 00025 00057 template<typename _MatrixType> class FullPivLU 00058 : public SolverBase<FullPivLU<_MatrixType> > 00059 { 00060 public: 00061 typedef _MatrixType MatrixType; 00062 typedef SolverBase<FullPivLU> Base; 00063 00064 EIGEN_GENERIC_PUBLIC_INTERFACE(FullPivLU) 00065 // FIXME StorageIndex defined in EIGEN_GENERIC_PUBLIC_INTERFACE should be int 00066 enum { 00067 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, 00068 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime 00069 }; 00070 typedef typename internal::plain_row_type<MatrixType, StorageIndex>::type IntRowVectorType; 00071 typedef typename internal::plain_col_type<MatrixType, StorageIndex>::type IntColVectorType; 00072 typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationQType; 00073 typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationPType; 00074 typedef typename MatrixType::PlainObject PlainObject; 00075 00082 FullPivLU(); 00083 00090 FullPivLU(Index rows, Index cols); 00091 00097 template<typename InputType> 00098 explicit FullPivLU(const EigenBase<InputType>& matrix); 00099 00107 template<typename InputType> 00108 FullPivLU& compute(const EigenBase<InputType>& matrix); 00109 00116 inline const MatrixType& matrixLU() const 00117 { 00118 eigen_assert(m_isInitialized && "LU is not initialized."); 00119 return m_lu; 00120 } 00121 00129 inline Index nonzeroPivots() const 00130 { 00131 eigen_assert(m_isInitialized && "LU is not initialized."); 00132 return m_nonzero_pivots; 00133 } 00134 00138 RealScalar maxPivot() const { return m_maxpivot; } 00139 00144 inline const PermutationPType& permutationP() const 00145 { 00146 eigen_assert(m_isInitialized && "LU is not initialized."); 00147 return m_p; 00148 } 00149 00154 inline const PermutationQType& permutationQ() const 00155 { 00156 eigen_assert(m_isInitialized && "LU is not initialized."); 00157 return m_q; 00158 } 00159 00174 inline const internal::kernel_retval<FullPivLU> kernel() const 00175 { 00176 eigen_assert(m_isInitialized && "LU is not initialized."); 00177 return internal::kernel_retval<FullPivLU>(*this); 00178 } 00179 00199 inline const internal::image_retval<FullPivLU> 00200 image(const MatrixType& originalMatrix) const 00201 { 00202 eigen_assert(m_isInitialized && "LU is not initialized."); 00203 return internal::image_retval<FullPivLU>(*this, originalMatrix); 00204 } 00205 00225 // FIXME this is a copy-paste of the base-class member to add the isInitialized assertion. 00226 template<typename Rhs> 00227 inline const Solve<FullPivLU, Rhs> 00228 solve(const MatrixBase<Rhs>& b) const 00229 { 00230 eigen_assert(m_isInitialized && "LU is not initialized."); 00231 return Solve<FullPivLU, Rhs>(*this, b.derived()); 00232 } 00233 00249 typename internal::traits<MatrixType>::Scalar determinant() const; 00250 00268 FullPivLU& setThreshold(const RealScalar& threshold) 00269 { 00270 m_usePrescribedThreshold = true; 00271 m_prescribedThreshold = threshold; 00272 return *this; 00273 } 00274 00283 FullPivLU& setThreshold(Default_t) 00284 { 00285 m_usePrescribedThreshold = false; 00286 return *this; 00287 } 00288 00293 RealScalar threshold() const 00294 { 00295 eigen_assert(m_isInitialized || m_usePrescribedThreshold); 00296 return m_usePrescribedThreshold ? m_prescribedThreshold 00297 // this formula comes from experimenting (see "LU precision tuning" thread on the list) 00298 // and turns out to be identical to Higham's formula used already in LDLt. 00299 : NumTraits<Scalar>::epsilon() * m_lu.diagonalSize(); 00300 } 00301 00308 inline Index rank() const 00309 { 00310 using std::abs; 00311 eigen_assert(m_isInitialized && "LU is not initialized."); 00312 RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold(); 00313 Index result = 0; 00314 for(Index i = 0; i < m_nonzero_pivots; ++i) 00315 result += (abs(m_lu.coeff(i,i)) > premultiplied_threshold); 00316 return result; 00317 } 00318 00325 inline Index dimensionOfKernel() const 00326 { 00327 eigen_assert(m_isInitialized && "LU is not initialized."); 00328 return cols() - rank(); 00329 } 00330 00338 inline bool isInjective() const 00339 { 00340 eigen_assert(m_isInitialized && "LU is not initialized."); 00341 return rank() == cols(); 00342 } 00343 00351 inline bool isSurjective() const 00352 { 00353 eigen_assert(m_isInitialized && "LU is not initialized."); 00354 return rank() == rows(); 00355 } 00356 00363 inline bool isInvertible() const 00364 { 00365 eigen_assert(m_isInitialized && "LU is not initialized."); 00366 return isInjective() && (m_lu.rows() == m_lu.cols()); 00367 } 00368 00376 inline const Inverse<FullPivLU> inverse() const 00377 { 00378 eigen_assert(m_isInitialized && "LU is not initialized."); 00379 eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!"); 00380 return Inverse<FullPivLU>(*this); 00381 } 00382 00383 MatrixType reconstructedMatrix() const; 00384 00385 inline Index rows() const { return m_lu.rows(); } 00386 inline Index cols() const { return m_lu.cols(); } 00387 00388 #ifndef EIGEN_PARSED_BY_DOXYGEN 00389 template<typename RhsType, typename DstType> 00390 EIGEN_DEVICE_FUNC 00391 void _solve_impl(const RhsType &rhs, DstType &dst) const; 00392 00393 template<bool Conjugate, typename RhsType, typename DstType> 00394 EIGEN_DEVICE_FUNC 00395 void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const; 00396 #endif 00397 00398 protected: 00399 00400 static void check_template_parameters() 00401 { 00402 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); 00403 } 00404 00405 void computeInPlace(); 00406 00407 MatrixType m_lu; 00408 PermutationPType m_p; 00409 PermutationQType m_q; 00410 IntColVectorType m_rowsTranspositions; 00411 IntRowVectorType m_colsTranspositions; 00412 Index m_det_pq, m_nonzero_pivots; 00413 RealScalar m_maxpivot, m_prescribedThreshold; 00414 bool m_isInitialized, m_usePrescribedThreshold; 00415 }; 00416 00417 template<typename MatrixType> 00418 FullPivLU<MatrixType>::FullPivLU() 00419 : m_isInitialized(false), m_usePrescribedThreshold(false) 00420 { 00421 } 00422 00423 template<typename MatrixType> 00424 FullPivLU<MatrixType>::FullPivLU(Index rows, Index cols) 00425 : m_lu(rows, cols), 00426 m_p(rows), 00427 m_q(cols), 00428 m_rowsTranspositions(rows), 00429 m_colsTranspositions(cols), 00430 m_isInitialized(false), 00431 m_usePrescribedThreshold(false) 00432 { 00433 } 00434 00435 template<typename MatrixType> 00436 template<typename InputType> 00437 FullPivLU<MatrixType>::FullPivLU(const EigenBase<InputType>& matrix) 00438 : m_lu(matrix.rows(), matrix.cols()), 00439 m_p(matrix.rows()), 00440 m_q(matrix.cols()), 00441 m_rowsTranspositions(matrix.rows()), 00442 m_colsTranspositions(matrix.cols()), 00443 m_isInitialized(false), 00444 m_usePrescribedThreshold(false) 00445 { 00446 compute(matrix.derived()); 00447 } 00448 00449 template<typename MatrixType> 00450 template<typename InputType> 00451 FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const EigenBase<InputType>& matrix) 00452 { 00453 check_template_parameters(); 00454 00455 // the permutations are stored as int indices, so just to be sure: 00456 eigen_assert(matrix.rows()<=NumTraits<int>::highest() && matrix.cols()<=NumTraits<int>::highest()); 00457 00458 m_isInitialized = true; 00459 m_lu = matrix.derived(); 00460 00461 computeInPlace(); 00462 00463 return *this; 00464 } 00465 00466 template<typename MatrixType> 00467 void FullPivLU<MatrixType>::computeInPlace() 00468 { 00469 const Index size = m_lu.diagonalSize(); 00470 const Index rows = m_lu.rows(); 00471 const Index cols = m_lu.cols(); 00472 00473 // will store the transpositions, before we accumulate them at the end. 00474 // can't accumulate on-the-fly because that will be done in reverse order for the rows. 00475 m_rowsTranspositions.resize(m_lu.rows()); 00476 m_colsTranspositions.resize(m_lu.cols()); 00477 Index number_of_transpositions = 0; // number of NONTRIVIAL transpositions, i.e. m_rowsTranspositions[i]!=i 00478 00479 m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case) 00480 m_maxpivot = RealScalar(0); 00481 00482 for(Index k = 0; k < size; ++k) 00483 { 00484 // First, we need to find the pivot. 00485 00486 // biggest coefficient in the remaining bottom-right corner (starting at row k, col k) 00487 Index row_of_biggest_in_corner, col_of_biggest_in_corner; 00488 typedef internal::scalar_score_coeff_op<Scalar> Scoring; 00489 typedef typename Scoring::result_type Score; 00490 Score biggest_in_corner; 00491 biggest_in_corner = m_lu.bottomRightCorner(rows-k, cols-k) 00492 .unaryExpr(Scoring()) 00493 .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner); 00494 row_of_biggest_in_corner += k; // correct the values! since they were computed in the corner, 00495 col_of_biggest_in_corner += k; // need to add k to them. 00496 00497 if(biggest_in_corner==Score(0)) 00498 { 00499 // before exiting, make sure to initialize the still uninitialized transpositions 00500 // in a sane state without destroying what we already have. 00501 m_nonzero_pivots = k; 00502 for(Index i = k; i < size; ++i) 00503 { 00504 m_rowsTranspositions.coeffRef(i) = i; 00505 m_colsTranspositions.coeffRef(i) = i; 00506 } 00507 break; 00508 } 00509 00510 RealScalar abs_pivot = internal::abs_knowing_score<Scalar>()(m_lu(row_of_biggest_in_corner, col_of_biggest_in_corner), biggest_in_corner); 00511 if(abs_pivot > m_maxpivot) m_maxpivot = abs_pivot; 00512 00513 // Now that we've found the pivot, we need to apply the row/col swaps to 00514 // bring it to the location (k,k). 00515 00516 m_rowsTranspositions.coeffRef(k) = row_of_biggest_in_corner; 00517 m_colsTranspositions.coeffRef(k) = col_of_biggest_in_corner; 00518 if(k != row_of_biggest_in_corner) { 00519 m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner)); 00520 ++number_of_transpositions; 00521 } 00522 if(k != col_of_biggest_in_corner) { 00523 m_lu.col(k).swap(m_lu.col(col_of_biggest_in_corner)); 00524 ++number_of_transpositions; 00525 } 00526 00527 // Now that the pivot is at the right location, we update the remaining 00528 // bottom-right corner by Gaussian elimination. 00529 00530 if(k<rows-1) 00531 m_lu.col(k).tail(rows-k-1) /= m_lu.coeff(k,k); 00532 if(k<size-1) 00533 m_lu.block(k+1,k+1,rows-k-1,cols-k-1).noalias() -= m_lu.col(k).tail(rows-k-1) * m_lu.row(k).tail(cols-k-1); 00534 } 00535 00536 // the main loop is over, we still have to accumulate the transpositions to find the 00537 // permutations P and Q 00538 00539 m_p.setIdentity(rows); 00540 for(Index k = size-1; k >= 0; --k) 00541 m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k)); 00542 00543 m_q.setIdentity(cols); 00544 for(Index k = 0; k < size; ++k) 00545 m_q.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k)); 00546 00547 m_det_pq = (number_of_transpositions%2) ? -1 : 1; 00548 } 00549 00550 template<typename MatrixType> 00551 typename internal::traits<MatrixType>::Scalar FullPivLU<MatrixType>::determinant() const 00552 { 00553 eigen_assert(m_isInitialized && "LU is not initialized."); 00554 eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); 00555 return Scalar(m_det_pq) * Scalar(m_lu.diagonal().prod()); 00556 } 00557 00561 template<typename MatrixType> 00562 MatrixType FullPivLU<MatrixType>::reconstructedMatrix() const 00563 { 00564 eigen_assert(m_isInitialized && "LU is not initialized."); 00565 const Index smalldim = (std::min)(m_lu.rows(), m_lu.cols()); 00566 // LU 00567 MatrixType res(m_lu.rows(),m_lu.cols()); 00568 // FIXME the .toDenseMatrix() should not be needed... 00569 res = m_lu.leftCols(smalldim) 00570 .template triangularView<UnitLower>().toDenseMatrix() 00571 * m_lu.topRows(smalldim) 00572 .template triangularView<Upper>().toDenseMatrix(); 00573 00574 // P^{-1}(LU) 00575 res = m_p.inverse() * res; 00576 00577 // (P^{-1}LU)Q^{-1} 00578 res = res * m_q.inverse(); 00579 00580 return res; 00581 } 00582 00583 /********* Implementation of kernel() **************************************************/ 00584 00585 namespace internal { 00586 template<typename _MatrixType> 00587 struct kernel_retval<FullPivLU<_MatrixType> > 00588 : kernel_retval_base<FullPivLU<_MatrixType> > 00589 { 00590 EIGEN_MAKE_KERNEL_HELPERS(FullPivLU<_MatrixType>) 00591 00592 enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED( 00593 MatrixType::MaxColsAtCompileTime, 00594 MatrixType::MaxRowsAtCompileTime) 00595 }; 00596 00597 template<typename Dest> void evalTo(Dest& dst) const 00598 { 00599 using std::abs; 00600 const Index l_cols = dec().matrixLU().cols(), dimker = l_cols - rank(); 00601 if(dimker == 0) 00602 { 00603 // The Kernel is just {0}, so it doesn't have a basis properly speaking, but let's 00604 // avoid crashing/asserting as that depends on floating point calculations. Let's 00605 // just return a single column vector filled with zeros. 00606 dst.setZero(); 00607 return; 00608 } 00609 00610 /* Let us use the following lemma: 00611 * 00612 * Lemma: If the matrix A has the LU decomposition PAQ = LU, 00613 * then Ker A = Q(Ker U). 00614 * 00615 * Proof: trivial: just keep in mind that P, Q, L are invertible. 00616 */ 00617 00618 /* Thus, all we need to do is to compute Ker U, and then apply Q. 00619 * 00620 * U is upper triangular, with eigenvalues sorted so that any zeros appear at the end. 00621 * Thus, the diagonal of U ends with exactly 00622 * dimKer zero's. Let us use that to construct dimKer linearly 00623 * independent vectors in Ker U. 00624 */ 00625 00626 Matrix<Index, Dynamic, 1, 0, MaxSmallDimAtCompileTime, 1> pivots(rank()); 00627 RealScalar premultiplied_threshold = dec().maxPivot() * dec().threshold(); 00628 Index p = 0; 00629 for(Index i = 0; i < dec().nonzeroPivots(); ++i) 00630 if(abs(dec().matrixLU().coeff(i,i)) > premultiplied_threshold) 00631 pivots.coeffRef(p++) = i; 00632 eigen_internal_assert(p == rank()); 00633 00634 // we construct a temporaty trapezoid matrix m, by taking the U matrix and 00635 // permuting the rows and cols to bring the nonnegligible pivots to the top of 00636 // the main diagonal. We need that to be able to apply our triangular solvers. 00637 // FIXME when we get triangularView-for-rectangular-matrices, this can be simplified 00638 Matrix<typename MatrixType::Scalar, Dynamic, Dynamic, MatrixType::Options, 00639 MaxSmallDimAtCompileTime, MatrixType::MaxColsAtCompileTime> 00640 m(dec().matrixLU().block(0, 0, rank(), l_cols)); 00641 for(Index i = 0; i < rank(); ++i) 00642 { 00643 if(i) m.row(i).head(i).setZero(); 00644 m.row(i).tail(l_cols-i) = dec().matrixLU().row(pivots.coeff(i)).tail(l_cols-i); 00645 } 00646 m.block(0, 0, rank(), rank()); 00647 m.block(0, 0, rank(), rank()).template triangularView<StrictlyLower>().setZero(); 00648 for(Index i = 0; i < rank(); ++i) 00649 m.col(i).swap(m.col(pivots.coeff(i))); 00650 00651 // ok, we have our trapezoid matrix, we can apply the triangular solver. 00652 // notice that the math behind this suggests that we should apply this to the 00653 // negative of the RHS, but for performance we just put the negative sign elsewhere, see below. 00654 m.topLeftCorner(rank(), rank()) 00655 .template triangularView<Upper>().solveInPlace( 00656 m.topRightCorner(rank(), dimker) 00657 ); 00658 00659 // now we must undo the column permutation that we had applied! 00660 for(Index i = rank()-1; i >= 0; --i) 00661 m.col(i).swap(m.col(pivots.coeff(i))); 00662 00663 // see the negative sign in the next line, that's what we were talking about above. 00664 for(Index i = 0; i < rank(); ++i) dst.row(dec().permutationQ().indices().coeff(i)) = -m.row(i).tail(dimker); 00665 for(Index i = rank(); i < l_cols; ++i) dst.row(dec().permutationQ().indices().coeff(i)).setZero(); 00666 for(Index k = 0; k < dimker; ++k) dst.coeffRef(dec().permutationQ().indices().coeff(rank()+k), k) = Scalar(1); 00667 } 00668 }; 00669 00670 /***** Implementation of image() *****************************************************/ 00671 00672 template<typename _MatrixType> 00673 struct image_retval<FullPivLU<_MatrixType> > 00674 : image_retval_base<FullPivLU<_MatrixType> > 00675 { 00676 EIGEN_MAKE_IMAGE_HELPERS(FullPivLU<_MatrixType>) 00677 00678 enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED( 00679 MatrixType::MaxColsAtCompileTime, 00680 MatrixType::MaxRowsAtCompileTime) 00681 }; 00682 00683 template<typename Dest> void evalTo(Dest& dst) const 00684 { 00685 using std::abs; 00686 if(rank() == 0) 00687 { 00688 // The Image is just {0}, so it doesn't have a basis properly speaking, but let's 00689 // avoid crashing/asserting as that depends on floating point calculations. Let's 00690 // just return a single column vector filled with zeros. 00691 dst.setZero(); 00692 return; 00693 } 00694 00695 Matrix<Index, Dynamic, 1, 0, MaxSmallDimAtCompileTime, 1> pivots(rank()); 00696 RealScalar premultiplied_threshold = dec().maxPivot() * dec().threshold(); 00697 Index p = 0; 00698 for(Index i = 0; i < dec().nonzeroPivots(); ++i) 00699 if(abs(dec().matrixLU().coeff(i,i)) > premultiplied_threshold) 00700 pivots.coeffRef(p++) = i; 00701 eigen_internal_assert(p == rank()); 00702 00703 for(Index i = 0; i < rank(); ++i) 00704 dst.col(i) = originalMatrix().col(dec().permutationQ().indices().coeff(pivots.coeff(i))); 00705 } 00706 }; 00707 00708 /***** Implementation of solve() *****************************************************/ 00709 00710 } // end namespace internal 00711 00712 #ifndef EIGEN_PARSED_BY_DOXYGEN 00713 template<typename _MatrixType> 00714 template<typename RhsType, typename DstType> 00715 void FullPivLU<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const 00716 { 00717 /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}. 00718 * So we proceed as follows: 00719 * Step 1: compute c = P * rhs. 00720 * Step 2: replace c by the solution x to Lx = c. Exists because L is invertible. 00721 * Step 3: replace c by the solution x to Ux = c. May or may not exist. 00722 * Step 4: result = Q * c; 00723 */ 00724 00725 const Index rows = this->rows(), 00726 cols = this->cols(), 00727 nonzero_pivots = this->rank(); 00728 eigen_assert(rhs.rows() == rows); 00729 const Index smalldim = (std::min)(rows, cols); 00730 00731 if(nonzero_pivots == 0) 00732 { 00733 dst.setZero(); 00734 return; 00735 } 00736 00737 typename RhsType::PlainObject c(rhs.rows(), rhs.cols()); 00738 00739 // Step 1 00740 c = permutationP() * rhs; 00741 00742 // Step 2 00743 m_lu.topLeftCorner(smalldim,smalldim) 00744 .template triangularView<UnitLower>() 00745 .solveInPlace(c.topRows(smalldim)); 00746 if(rows>cols) 00747 c.bottomRows(rows-cols) -= m_lu.bottomRows(rows-cols) * c.topRows(cols); 00748 00749 // Step 3 00750 m_lu.topLeftCorner(nonzero_pivots, nonzero_pivots) 00751 .template triangularView<Upper>() 00752 .solveInPlace(c.topRows(nonzero_pivots)); 00753 00754 // Step 4 00755 for(Index i = 0; i < nonzero_pivots; ++i) 00756 dst.row(permutationQ().indices().coeff(i)) = c.row(i); 00757 for(Index i = nonzero_pivots; i < m_lu.cols(); ++i) 00758 dst.row(permutationQ().indices().coeff(i)).setZero(); 00759 } 00760 00761 template<typename _MatrixType> 00762 template<bool Conjugate, typename RhsType, typename DstType> 00763 void FullPivLU<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const 00764 { 00765 /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}, 00766 * and since permutations are real and unitary, we can write this 00767 * as A^T = Q U^T L^T P, 00768 * So we proceed as follows: 00769 * Step 1: compute c = Q^T rhs. 00770 * Step 2: replace c by the solution x to U^T x = c. May or may not exist. 00771 * Step 3: replace c by the solution x to L^T x = c. 00772 * Step 4: result = P^T c. 00773 * If Conjugate is true, replace "^T" by "^*" above. 00774 */ 00775 00776 const Index rows = this->rows(), cols = this->cols(), 00777 nonzero_pivots = this->rank(); 00778 eigen_assert(rhs.rows() == cols); 00779 const Index smalldim = (std::min)(rows, cols); 00780 00781 if(nonzero_pivots == 0) 00782 { 00783 dst.setZero(); 00784 return; 00785 } 00786 00787 typename RhsType::PlainObject c(rhs.rows(), rhs.cols()); 00788 00789 // Step 1 00790 c = permutationQ().inverse() * rhs; 00791 00792 if (Conjugate) { 00793 // Step 2 00794 m_lu.topLeftCorner(nonzero_pivots, nonzero_pivots) 00795 .template triangularView<Upper>() 00796 .adjoint() 00797 .solveInPlace(c.topRows(nonzero_pivots)); 00798 // Step 3 00799 m_lu.topLeftCorner(smalldim, smalldim) 00800 .template triangularView<UnitLower>() 00801 .adjoint() 00802 .solveInPlace(c.topRows(smalldim)); 00803 } else { 00804 // Step 2 00805 m_lu.topLeftCorner(nonzero_pivots, nonzero_pivots) 00806 .template triangularView<Upper>() 00807 .transpose() 00808 .solveInPlace(c.topRows(nonzero_pivots)); 00809 // Step 3 00810 m_lu.topLeftCorner(smalldim, smalldim) 00811 .template triangularView<UnitLower>() 00812 .transpose() 00813 .solveInPlace(c.topRows(smalldim)); 00814 } 00815 00816 // Step 4 00817 PermutationPType invp = permutationP().inverse().eval(); 00818 for(Index i = 0; i < smalldim; ++i) 00819 dst.row(invp.indices().coeff(i)) = c.row(i); 00820 for(Index i = smalldim; i < rows; ++i) 00821 dst.row(invp.indices().coeff(i)).setZero(); 00822 } 00823 00824 #endif 00825 00826 namespace internal { 00827 00828 00829 /***** Implementation of inverse() *****************************************************/ 00830 template<typename DstXprType, typename MatrixType, typename Scalar> 00831 struct Assignment<DstXprType, Inverse<FullPivLU<MatrixType> >, internal::assign_op<Scalar>, Dense2Dense, Scalar> 00832 { 00833 typedef FullPivLU<MatrixType> LuType; 00834 typedef Inverse<LuType> SrcXprType; 00835 static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar> &) 00836 { 00837 dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); 00838 } 00839 }; 00840 } // end namespace internal 00841 00842 /******* MatrixBase methods *****************************************************************/ 00843 00850 #ifndef __CUDACC__ 00851 template<typename Derived> 00852 inline const FullPivLU<typename MatrixBase<Derived>::PlainObject> 00853 MatrixBase<Derived>::fullPivLu() const 00854 { 00855 return FullPivLU<PlainObject>(eval()); 00856 } 00857 #endif 00858 00859 } // end namespace Eigen 00860 00861 #endif // EIGEN_LU_H