Home | History | Annotate | Download | only in Skyline
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2008 Guillaume Saupin <guillaume.saupin (at) cea.fr>
      5 //
      6 // This Source Code Form is subject to the terms of the Mozilla
      7 // Public License v. 2.0. If a copy of the MPL was not distributed
      8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9 
     10 #ifndef EIGEN_SKYLINEINPLACELU_H
     11 #define EIGEN_SKYLINEINPLACELU_H
     12 
     13 namespace Eigen {
     14 
     15 /** \ingroup Skyline_Module
     16  *
     17  * \class SkylineInplaceLU
     18  *
     19  * \brief Inplace LU decomposition of a skyline matrix and associated features
     20  *
     21  * \param MatrixType the type of the matrix of which we are computing the LU factorization
     22  *
     23  */
     24 template<typename MatrixType>
     25 class SkylineInplaceLU {
     26 protected:
     27     typedef typename MatrixType::Scalar Scalar;
     28     typedef typename MatrixType::Index Index;
     29 
     30     typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
     31 
     32 public:
     33 
     34     /** Creates a LU object and compute the respective factorization of \a matrix using
     35      * flags \a flags. */
     36     SkylineInplaceLU(MatrixType& matrix, int flags = 0)
     37     : /*m_matrix(matrix.rows(), matrix.cols()),*/ m_flags(flags), m_status(0), m_lu(matrix) {
     38         m_precision = RealScalar(0.1) * Eigen::dummy_precision<RealScalar > ();
     39         m_lu.IsRowMajor ? computeRowMajor() : compute();
     40     }
     41 
     42     /** Sets the relative threshold value used to prune zero coefficients during the decomposition.
     43      *
     44      * Setting a value greater than zero speeds up computation, and yields to an imcomplete
     45      * factorization with fewer non zero coefficients. Such approximate factors are especially
     46      * useful to initialize an iterative solver.
     47      *
     48      * Note that the exact meaning of this parameter might depends on the actual
     49      * backend. Moreover, not all backends support this feature.
     50      *
     51      * \sa precision() */
     52     void setPrecision(RealScalar v) {
     53         m_precision = v;
     54     }
     55 
     56     /** \returns the current precision.
     57      *
     58      * \sa setPrecision() */
     59     RealScalar precision() const {
     60         return m_precision;
     61     }
     62 
     63     /** Sets the flags. Possible values are:
     64      *  - CompleteFactorization
     65      *  - IncompleteFactorization
     66      *  - MemoryEfficient
     67      *  - one of the ordering methods
     68      *  - etc...
     69      *
     70      * \sa flags() */
     71     void setFlags(int f) {
     72         m_flags = f;
     73     }
     74 
     75     /** \returns the current flags */
     76     int flags() const {
     77         return m_flags;
     78     }
     79 
     80     void setOrderingMethod(int m) {
     81         m_flags = m;
     82     }
     83 
     84     int orderingMethod() const {
     85         return m_flags;
     86     }
     87 
     88     /** Computes/re-computes the LU factorization */
     89     void compute();
     90     void computeRowMajor();
     91 
     92     /** \returns the lower triangular matrix L */
     93     //inline const MatrixType& matrixL() const { return m_matrixL; }
     94 
     95     /** \returns the upper triangular matrix U */
     96     //inline const MatrixType& matrixU() const { return m_matrixU; }
     97 
     98     template<typename BDerived, typename XDerived>
     99     bool solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x,
    100             const int transposed = 0) const;
    101 
    102     /** \returns true if the factorization succeeded */
    103     inline bool succeeded(void) const {
    104         return m_succeeded;
    105     }
    106 
    107 protected:
    108     RealScalar m_precision;
    109     int m_flags;
    110     mutable int m_status;
    111     bool m_succeeded;
    112     MatrixType& m_lu;
    113 };
    114 
    115 /** Computes / recomputes the in place LU decomposition of the SkylineInplaceLU.
    116  * using the default algorithm.
    117  */
    118 template<typename MatrixType>
    119 //template<typename _Scalar>
    120 void SkylineInplaceLU<MatrixType>::compute() {
    121     const size_t rows = m_lu.rows();
    122     const size_t cols = m_lu.cols();
    123 
    124     eigen_assert(rows == cols && "We do not (yet) support rectangular LU.");
    125     eigen_assert(!m_lu.IsRowMajor && "LU decomposition does not work with rowMajor Storage");
    126 
    127     for (Index row = 0; row < rows; row++) {
    128         const double pivot = m_lu.coeffDiag(row);
    129 
    130         //Lower matrix Columns update
    131         const Index& col = row;
    132         for (typename MatrixType::InnerLowerIterator lIt(m_lu, col); lIt; ++lIt) {
    133             lIt.valueRef() /= pivot;
    134         }
    135 
    136         //Upper matrix update -> contiguous memory access
    137         typename MatrixType::InnerLowerIterator lIt(m_lu, col);
    138         for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) {
    139             typename MatrixType::InnerUpperIterator uItPivot(m_lu, row);
    140             typename MatrixType::InnerUpperIterator uIt(m_lu, rrow);
    141             const double coef = lIt.value();
    142 
    143             uItPivot += (rrow - row - 1);
    144 
    145             //update upper part  -> contiguous memory access
    146             for (++uItPivot; uIt && uItPivot;) {
    147                 uIt.valueRef() -= uItPivot.value() * coef;
    148 
    149                 ++uIt;
    150                 ++uItPivot;
    151             }
    152             ++lIt;
    153         }
    154 
    155         //Upper matrix update -> non contiguous memory access
    156         typename MatrixType::InnerLowerIterator lIt3(m_lu, col);
    157         for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) {
    158             typename MatrixType::InnerUpperIterator uItPivot(m_lu, row);
    159             const double coef = lIt3.value();
    160 
    161             //update lower part ->  non contiguous memory access
    162             for (Index i = 0; i < rrow - row - 1; i++) {
    163                 m_lu.coeffRefLower(rrow, row + i + 1) -= uItPivot.value() * coef;
    164                 ++uItPivot;
    165             }
    166             ++lIt3;
    167         }
    168         //update diag -> contiguous
    169         typename MatrixType::InnerLowerIterator lIt2(m_lu, col);
    170         for (Index rrow = row + 1; rrow < m_lu.rows(); rrow++) {
    171 
    172             typename MatrixType::InnerUpperIterator uItPivot(m_lu, row);
    173             typename MatrixType::InnerUpperIterator uIt(m_lu, rrow);
    174             const double coef = lIt2.value();
    175 
    176             uItPivot += (rrow - row - 1);
    177             m_lu.coeffRefDiag(rrow) -= uItPivot.value() * coef;
    178             ++lIt2;
    179         }
    180     }
    181 }
    182 
    183 template<typename MatrixType>
    184 void SkylineInplaceLU<MatrixType>::computeRowMajor() {
    185     const size_t rows = m_lu.rows();
    186     const size_t cols = m_lu.cols();
    187 
    188     eigen_assert(rows == cols && "We do not (yet) support rectangular LU.");
    189     eigen_assert(m_lu.IsRowMajor && "You're trying to apply rowMajor decomposition on a ColMajor matrix !");
    190 
    191     for (Index row = 0; row < rows; row++) {
    192         typename MatrixType::InnerLowerIterator llIt(m_lu, row);
    193 
    194 
    195         for (Index col = llIt.col(); col < row; col++) {
    196             if (m_lu.coeffExistLower(row, col)) {
    197                 const double diag = m_lu.coeffDiag(col);
    198 
    199                 typename MatrixType::InnerLowerIterator lIt(m_lu, row);
    200                 typename MatrixType::InnerUpperIterator uIt(m_lu, col);
    201 
    202 
    203                 const Index offset = lIt.col() - uIt.row();
    204 
    205 
    206                 Index stop = offset > 0 ? col - lIt.col() : col - uIt.row();
    207 
    208                 //#define VECTORIZE
    209 #ifdef VECTORIZE
    210                 Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop);
    211                 Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop);
    212 
    213 
    214                 Scalar newCoeff = m_lu.coeffLower(row, col) - rowVal.dot(colVal);
    215 #else
    216                 if (offset > 0) //Skip zero value of lIt
    217                     uIt += offset;
    218                 else //Skip zero values of uIt
    219                     lIt += -offset;
    220                 Scalar newCoeff = m_lu.coeffLower(row, col);
    221 
    222                 for (Index k = 0; k < stop; ++k) {
    223                     const Scalar tmp = newCoeff;
    224                     newCoeff = tmp - lIt.value() * uIt.value();
    225                     ++lIt;
    226                     ++uIt;
    227                 }
    228 #endif
    229 
    230                 m_lu.coeffRefLower(row, col) = newCoeff / diag;
    231             }
    232         }
    233 
    234         //Upper matrix update
    235         const Index col = row;
    236         typename MatrixType::InnerUpperIterator uuIt(m_lu, col);
    237         for (Index rrow = uuIt.row(); rrow < col; rrow++) {
    238 
    239             typename MatrixType::InnerLowerIterator lIt(m_lu, rrow);
    240             typename MatrixType::InnerUpperIterator uIt(m_lu, col);
    241             const Index offset = lIt.col() - uIt.row();
    242 
    243             Index stop = offset > 0 ? rrow - lIt.col() : rrow - uIt.row();
    244 
    245 #ifdef VECTORIZE
    246             Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop);
    247             Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop);
    248 
    249             Scalar newCoeff = m_lu.coeffUpper(rrow, col) - rowVal.dot(colVal);
    250 #else
    251             if (offset > 0) //Skip zero value of lIt
    252                 uIt += offset;
    253             else //Skip zero values of uIt
    254                 lIt += -offset;
    255             Scalar newCoeff = m_lu.coeffUpper(rrow, col);
    256             for (Index k = 0; k < stop; ++k) {
    257                 const Scalar tmp = newCoeff;
    258                 newCoeff = tmp - lIt.value() * uIt.value();
    259 
    260                 ++lIt;
    261                 ++uIt;
    262             }
    263 #endif
    264             m_lu.coeffRefUpper(rrow, col) = newCoeff;
    265         }
    266 
    267 
    268         //Diag matrix update
    269         typename MatrixType::InnerLowerIterator lIt(m_lu, row);
    270         typename MatrixType::InnerUpperIterator uIt(m_lu, row);
    271 
    272         const Index offset = lIt.col() - uIt.row();
    273 
    274 
    275         Index stop = offset > 0 ? lIt.size() : uIt.size();
    276 #ifdef VECTORIZE
    277         Map<VectorXd > rowVal(lIt.valuePtr() + (offset > 0 ? 0 : -offset), stop);
    278         Map<VectorXd > colVal(uIt.valuePtr() + (offset > 0 ? offset : 0), stop);
    279         Scalar newCoeff = m_lu.coeffDiag(row) - rowVal.dot(colVal);
    280 #else
    281         if (offset > 0) //Skip zero value of lIt
    282             uIt += offset;
    283         else //Skip zero values of uIt
    284             lIt += -offset;
    285         Scalar newCoeff = m_lu.coeffDiag(row);
    286         for (Index k = 0; k < stop; ++k) {
    287             const Scalar tmp = newCoeff;
    288             newCoeff = tmp - lIt.value() * uIt.value();
    289             ++lIt;
    290             ++uIt;
    291         }
    292 #endif
    293         m_lu.coeffRefDiag(row) = newCoeff;
    294     }
    295 }
    296 
    297 /** Computes *x = U^-1 L^-1 b
    298  *
    299  * If \a transpose is set to SvTranspose or SvAdjoint, the solution
    300  * of the transposed/adjoint system is computed instead.
    301  *
    302  * Not all backends implement the solution of the transposed or
    303  * adjoint system.
    304  */
    305 template<typename MatrixType>
    306 template<typename BDerived, typename XDerived>
    307 bool SkylineInplaceLU<MatrixType>::solve(const MatrixBase<BDerived> &b, MatrixBase<XDerived>* x, const int transposed) const {
    308     const size_t rows = m_lu.rows();
    309     const size_t cols = m_lu.cols();
    310 
    311 
    312     for (Index row = 0; row < rows; row++) {
    313         x->coeffRef(row) = b.coeff(row);
    314         Scalar newVal = x->coeff(row);
    315         typename MatrixType::InnerLowerIterator lIt(m_lu, row);
    316 
    317         Index col = lIt.col();
    318         while (lIt.col() < row) {
    319 
    320             newVal -= x->coeff(col++) * lIt.value();
    321             ++lIt;
    322         }
    323 
    324         x->coeffRef(row) = newVal;
    325     }
    326 
    327 
    328     for (Index col = rows - 1; col > 0; col--) {
    329         x->coeffRef(col) = x->coeff(col) / m_lu.coeffDiag(col);
    330 
    331         const Scalar x_col = x->coeff(col);
    332 
    333         typename MatrixType::InnerUpperIterator uIt(m_lu, col);
    334         uIt += uIt.size()-1;
    335 
    336 
    337         while (uIt) {
    338             x->coeffRef(uIt.row()) -= x_col * uIt.value();
    339             //TODO : introduce --operator
    340             uIt += -1;
    341         }
    342 
    343 
    344     }
    345     x->coeffRef(0) = x->coeff(0) / m_lu.coeffDiag(0);
    346 
    347     return true;
    348 }
    349 
    350 } // end namespace Eigen
    351 
    352 #endif // EIGEN_SKYLINELU_H
    353