MOAB  4.9.3pre
FullPivLU.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) 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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines