| // This file is part of Eigen, a lightweight C++ template library |
| // for linear algebra. |
| // |
| // Copyright (C) 2008 Guillaume Saupin <guillaume.saupin@cea.fr> |
| // |
| // This Source Code Form is subject to the terms of the Mozilla |
| // Public License v. 2.0. If a copy of the MPL was not distributed |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| #ifndef EIGEN_SKYLINEINPLACELU_H |
| #define EIGEN_SKYLINEINPLACELU_H |
| |
| namespace Eigen { |
| |
| /** \ingroup Skyline_Module |
| * |
| * \class SkylineInplaceLU |
| * |
| * \brief Inplace LU decomposition of a skyline matrix and associated features |
| * |
| * \param MatrixType the type of the matrix of which we are computing the LU factorization |
| * |
| */ |
| template<typename MatrixType> |
| class SkylineInplaceLU { |
| protected: |
| typedef typename MatrixType::Scalar Scalar; |
| typedef typename MatrixType::Index Index; |
| |
| typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar; |
| |
| public: |
| |
| /** Creates a LU object and compute the respective factorization of \a matrix using |
| * flags \a flags. */ |
| SkylineInplaceLU(MatrixType& matrix, int flags = 0) |
| : /*m_matrix(matrix.rows(), matrix.cols()),*/ m_flags(flags), m_status(0), m_lu(matrix) { |
| m_precision = RealScalar(0.1) * Eigen::dummy_precision<RealScalar > (); |
| m_lu.IsRowMajor ? computeRowMajor() : compute(); |
| } |
| |
| /** Sets the relative threshold value used to prune zero coefficients during the decomposition. |
| * |
| * Setting a value greater than zero speeds up computation, and yields to an imcomplete |
| * factorization with fewer non zero coefficients. Such approximate factors are especially |
| * useful to initialize an iterative solver. |
| * |
| * Note that the exact meaning of this parameter might depends on the actual |
| * backend. Moreover, not all backends support this feature. |
| * |
| * \sa precision() */ |
| void setPrecision(RealScalar v) { |
| m_precision = v; |
| } |
| |
| /** \returns the current precision. |
| * |
| * \sa setPrecision() */ |
| RealScalar precision() const { |
| return m_precision; |
| } |
| |
| /** Sets the flags. Possible values are: |
| * - CompleteFactorization |
| * - IncompleteFactorization |
| * - MemoryEfficient |
| * - one of the ordering methods |
| * - etc... |
| * |
| * \sa flags() */ |
| void setFlags(int f) { |
| m_flags = f; |
| } |
| |
| /** \returns the current flags */ |
| int flags() const { |
| return m_flags; |
| } |
| |
| void setOrderingMethod(int m) { |
| m_flags = m; |
| } |
| |
| int orderingMethod() const { |
| return m_flags; |
| } |
| |
| /** Computes/re-computes the LU factorization */ |
| void compute(); |
| void computeRowMajor(); |
| |
| /** \returns the lower triangular matrix L */ |
| //inline const MatrixType& matrixL() const { return m_matrixL; } |
| |
| /** \returns the upper triangular matrix U */ |
| //inline const MatrixType& matrixU() const { return m_matrixU; } |
| |
| template<typename BDerived, typename XDerived> |
| bool solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x, |
| const int transposed = 0) const; |
| |
| /** \returns true if the factorization succeeded */ |
| inline bool succeeded(void) const { |
| return m_succeeded; |
| } |
| |
| protected: |
| RealScalar m_precision; |
| int m_flags; |
| mutable int m_status; |
| bool m_succeeded; |
| MatrixType& m_lu; |
| }; |
| |
| /** Computes / recomputes the in place LU decomposition of the SkylineInplaceLU. |
| * using the default algorithm. |
| */ |
| template<typename MatrixType> |
| //template<typename _Scalar> |
| void SkylineInplaceLU<MatrixType>::compute() { |
| const size_t rows = m_lu.rows(); |
| const size_t cols = m_lu.cols(); |
| |
| eigen_assert(rows == cols && "We do not (yet) support rectangular LU."); |
| eigen_assert(!m_lu.IsRowMajor && "LU decomposition does not work with rowMajor Storage"); |
| |
| for (Index row = 0; row < rows; row++) { |
| const double pivot = m_lu.coeffDiag(row); |
| |
| //Lower matrix Columns update |
| const Index& col = row; |
| for (typename MatrixType::InnerLowerIterator lIt(m_lu, col); lIt; ++lIt) { |
| lIt.valueRef() /= pivot; |
| } |
| |
| //Upper matrix update -> contiguous memory access |
| typename MatrixType::InnerLowerIterator lIt(m_lu, col); |
| for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) { |
| typename MatrixType::InnerUpperIterator uItPivot(m_lu, row); |
| typename MatrixType::InnerUpperIterator uIt(m_lu, rrow); |
| const double coef = lIt.value(); |
| |
| uItPivot += (rrow - row - 1); |
| |
| //update upper part -> contiguous memory access |
| for (++uItPivot; uIt && uItPivot;) { |
| uIt.valueRef() -= uItPivot.value() * coef; |
| |
| ++uIt; |
| ++uItPivot; |
| } |
| ++lIt; |
| } |
| |
| //Upper matrix update -> non contiguous memory access |
| typename MatrixType::InnerLowerIterator lIt3(m_lu, col); |
| for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) { |
| typename MatrixType::InnerUpperIterator uItPivot(m_lu, row); |
| const double coef = lIt3.value(); |
| |
| //update lower part -> non contiguous memory access |
| for (Index i = 0; i < rrow - row - 1; i++) { |
| m_lu.coeffRefLower(rrow, row + i + 1) -= uItPivot.value() * coef; |
| ++uItPivot; |
| } |
| ++lIt3; |
| } |
| //update diag -> contiguous |
| typename MatrixType::InnerLowerIterator lIt2(m_lu, col); |
| for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) { |
| |
| typename MatrixType::InnerUpperIterator uItPivot(m_lu, row); |
| typename MatrixType::InnerUpperIterator uIt(m_lu, rrow); |
| const double coef = lIt2.value(); |
| |
| uItPivot += (rrow - row - 1); |
| m_lu.coeffRefDiag(rrow) -= uItPivot.value() * coef; |
| ++lIt2; |
| } |
| } |
| } |
| |
| template<typename MatrixType> |
| void SkylineInplaceLU<MatrixType>::computeRowMajor() { |
| const size_t rows = m_lu.rows(); |
| const size_t cols = m_lu.cols(); |
| |
| eigen_assert(rows == cols && "We do not (yet) support rectangular LU."); |
| eigen_assert(m_lu.IsRowMajor && "You're trying to apply rowMajor decomposition on a ColMajor matrix !"); |
| |
| for (Index row = 0; row < rows; row++) { |
| typename MatrixType::InnerLowerIterator llIt(m_lu, row); |
| |
| |
| for (Index col = llIt.col(); col < row; col++) { |
| if (m_lu.coeffExistLower(row, col)) { |
| const double diag = m_lu.coeffDiag(col); |
| |
| typename MatrixType::InnerLowerIterator lIt(m_lu, row); |
| typename MatrixType::InnerUpperIterator uIt(m_lu, col); |
| |
| |
| const Index offset = lIt.col() - uIt.row(); |
| |
| |
| Index stop = offset > 0 ? col - lIt.col() : col - uIt.row(); |
| |
| //#define VECTORIZE |
| #ifdef VECTORIZE |
| Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop); |
| Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop); |
| |
| |
| Scalar newCoeff = m_lu.coeffLower(row, col) - rowVal.dot(colVal); |
| #else |
| if (offset > 0) //Skip zero value of lIt |
| uIt += offset; |
| else //Skip zero values of uIt |
| lIt += -offset; |
| Scalar newCoeff = m_lu.coeffLower(row, col); |
| |
| for (Index k = 0; k < stop; ++k) { |
| const Scalar tmp = newCoeff; |
| newCoeff = tmp - lIt.value() * uIt.value(); |
| ++lIt; |
| ++uIt; |
| } |
| #endif |
| |
| m_lu.coeffRefLower(row, col) = newCoeff / diag; |
| } |
| } |
| |
| //Upper matrix update |
| const Index col = row; |
| typename MatrixType::InnerUpperIterator uuIt(m_lu, col); |
| for (Index rrow = uuIt.row(); rrow < col; rrow++) { |
| |
| typename MatrixType::InnerLowerIterator lIt(m_lu, rrow); |
| typename MatrixType::InnerUpperIterator uIt(m_lu, col); |
| const Index offset = lIt.col() - uIt.row(); |
| |
| Index stop = offset > 0 ? rrow - lIt.col() : rrow - uIt.row(); |
| |
| #ifdef VECTORIZE |
| Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop); |
| Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop); |
| |
| Scalar newCoeff = m_lu.coeffUpper(rrow, col) - rowVal.dot(colVal); |
| #else |
| if (offset > 0) //Skip zero value of lIt |
| uIt += offset; |
| else //Skip zero values of uIt |
| lIt += -offset; |
| Scalar newCoeff = m_lu.coeffUpper(rrow, col); |
| for (Index k = 0; k < stop; ++k) { |
| const Scalar tmp = newCoeff; |
| newCoeff = tmp - lIt.value() * uIt.value(); |
| |
| ++lIt; |
| ++uIt; |
| } |
| #endif |
| m_lu.coeffRefUpper(rrow, col) = newCoeff; |
| } |
| |
| |
| //Diag matrix update |
| typename MatrixType::InnerLowerIterator lIt(m_lu, row); |
| typename MatrixType::InnerUpperIterator uIt(m_lu, row); |
| |
| const Index offset = lIt.col() - uIt.row(); |
| |
| |
| Index stop = offset > 0 ? lIt.size() : uIt.size(); |
| #ifdef VECTORIZE |
| Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop); |
| Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop); |
| Scalar newCoeff = m_lu.coeffDiag(row) - rowVal.dot(colVal); |
| #else |
| if (offset > 0) //Skip zero value of lIt |
| uIt += offset; |
| else //Skip zero values of uIt |
| lIt += -offset; |
| Scalar newCoeff = m_lu.coeffDiag(row); |
| for (Index k = 0; k < stop; ++k) { |
| const Scalar tmp = newCoeff; |
| newCoeff = tmp - lIt.value() * uIt.value(); |
| ++lIt; |
| ++uIt; |
| } |
| #endif |
| m_lu.coeffRefDiag(row) = newCoeff; |
| } |
| } |
| |
| /** Computes *x = U^-1 L^-1 b |
| * |
| * If \a transpose is set to SvTranspose or SvAdjoint, the solution |
| * of the transposed/adjoint system is computed instead. |
| * |
| * Not all backends implement the solution of the transposed or |
| * adjoint system. |
| */ |
| template<typename MatrixType> |
| template<typename BDerived, typename XDerived> |
| bool SkylineInplaceLU<MatrixType>::solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x, const int transposed) const { |
| const size_t rows = m_lu.rows(); |
| const size_t cols = m_lu.cols(); |
| |
| |
| for (Index row = 0; row < rows; row++) { |
| x->coeffRef(row) = b.coeff(row); |
| Scalar newVal = x->coeff(row); |
| typename MatrixType::InnerLowerIterator lIt(m_lu, row); |
| |
| Index col = lIt.col(); |
| while (lIt.col() < row) { |
| |
| newVal -= x->coeff(col++) * lIt.value(); |
| ++lIt; |
| } |
| |
| x->coeffRef(row) = newVal; |
| } |
| |
| |
| for (Index col = rows - 1; col > 0; col--) { |
| x->coeffRef(col) = x->coeff(col) / m_lu.coeffDiag(col); |
| |
| const Scalar x_col = x->coeff(col); |
| |
| typename MatrixType::InnerUpperIterator uIt(m_lu, col); |
| uIt += uIt.size()-1; |
| |
| |
| while (uIt) { |
| x->coeffRef(uIt.row()) -= x_col * uIt.value(); |
| //TODO : introduce --operator |
| uIt += -1; |
| } |
| |
| |
| } |
| x->coeffRef(0) = x->coeff(0) / m_lu.coeffDiag(0); |
| |
| return true; |
| } |
| |
| } // end namespace Eigen |
| |
| #endif // EIGEN_SKYLINELU_H |