Home | History | Annotate | Download | only in SparseQR
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2012-2013 Desire Nuentsa <desire.nuentsa_wakam (at) inria.fr>
      5 // Copyright (C) 2012-2014 Gael Guennebaud <gael.guennebaud (at) inria.fr>
      6 //
      7 // This Source Code Form is subject to the terms of the Mozilla
      8 // Public License v. 2.0. If a copy of the MPL was not distributed
      9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     10 
     11 #ifndef EIGEN_SPARSE_QR_H
     12 #define EIGEN_SPARSE_QR_H
     13 
     14 namespace Eigen {
     15 
     16 template<typename MatrixType, typename OrderingType> class SparseQR;
     17 template<typename SparseQRType> struct SparseQRMatrixQReturnType;
     18 template<typename SparseQRType> struct SparseQRMatrixQTransposeReturnType;
     19 template<typename SparseQRType, typename Derived> struct SparseQR_QProduct;
     20 namespace internal {
     21   template <typename SparseQRType> struct traits<SparseQRMatrixQReturnType<SparseQRType> >
     22   {
     23     typedef typename SparseQRType::MatrixType ReturnType;
     24     typedef typename ReturnType::StorageIndex StorageIndex;
     25     typedef typename ReturnType::StorageKind StorageKind;
     26     enum {
     27       RowsAtCompileTime = Dynamic,
     28       ColsAtCompileTime = Dynamic
     29     };
     30   };
     31   template <typename SparseQRType> struct traits<SparseQRMatrixQTransposeReturnType<SparseQRType> >
     32   {
     33     typedef typename SparseQRType::MatrixType ReturnType;
     34   };
     35   template <typename SparseQRType, typename Derived> struct traits<SparseQR_QProduct<SparseQRType, Derived> >
     36   {
     37     typedef typename Derived::PlainObject ReturnType;
     38   };
     39 } // End namespace internal
     40 
     41 /**
     42   * \ingroup SparseQR_Module
     43   * \class SparseQR
     44   * \brief Sparse left-looking rank-revealing QR factorization
     45   *
     46   * This class implements a left-looking rank-revealing QR decomposition
     47   * of sparse matrices. When a column has a norm less than a given tolerance
     48   * it is implicitly permuted to the end. The QR factorization thus obtained is
     49   * given by A*P = Q*R where R is upper triangular or trapezoidal.
     50   *
     51   * P is the column permutation which is the product of the fill-reducing and the
     52   * rank-revealing permutations. Use colsPermutation() to get it.
     53   *
     54   * Q is the orthogonal matrix represented as products of Householder reflectors.
     55   * Use matrixQ() to get an expression and matrixQ().transpose() to get the transpose.
     56   * You can then apply it to a vector.
     57   *
     58   * R is the sparse triangular or trapezoidal matrix. The later occurs when A is rank-deficient.
     59   * matrixR().topLeftCorner(rank(), rank()) always returns a triangular factor of full rank.
     60   *
     61   * \tparam _MatrixType The type of the sparse matrix A, must be a column-major SparseMatrix<>
     62   * \tparam _OrderingType The fill-reducing ordering method. See the \link OrderingMethods_Module
     63   *  OrderingMethods \endlink module for the list of built-in and external ordering methods.
     64   *
     65   * \implsparsesolverconcept
     66   *
     67   * \warning The input sparse matrix A must be in compressed mode (see SparseMatrix::makeCompressed()).
     68   *
     69   */
     70 template<typename _MatrixType, typename _OrderingType>
     71 class SparseQR : public SparseSolverBase<SparseQR<_MatrixType,_OrderingType> >
     72 {
     73   protected:
     74     typedef SparseSolverBase<SparseQR<_MatrixType,_OrderingType> > Base;
     75     using Base::m_isInitialized;
     76   public:
     77     using Base::_solve_impl;
     78     typedef _MatrixType MatrixType;
     79     typedef _OrderingType OrderingType;
     80     typedef typename MatrixType::Scalar Scalar;
     81     typedef typename MatrixType::RealScalar RealScalar;
     82     typedef typename MatrixType::StorageIndex StorageIndex;
     83     typedef SparseMatrix<Scalar,ColMajor,StorageIndex> QRMatrixType;
     84     typedef Matrix<StorageIndex, Dynamic, 1> IndexVector;
     85     typedef Matrix<Scalar, Dynamic, 1> ScalarVector;
     86     typedef PermutationMatrix<Dynamic, Dynamic, StorageIndex> PermutationType;
     87 
     88     enum {
     89       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
     90       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
     91     };
     92 
     93   public:
     94     SparseQR () :  m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
     95     { }
     96 
     97     /** Construct a QR factorization of the matrix \a mat.
     98       *
     99       * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
    100       *
    101       * \sa compute()
    102       */
    103     explicit SparseQR(const MatrixType& mat) : m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
    104     {
    105       compute(mat);
    106     }
    107 
    108     /** Computes the QR factorization of the sparse matrix \a mat.
    109       *
    110       * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
    111       *
    112       * \sa analyzePattern(), factorize()
    113       */
    114     void compute(const MatrixType& mat)
    115     {
    116       analyzePattern(mat);
    117       factorize(mat);
    118     }
    119     void analyzePattern(const MatrixType& mat);
    120     void factorize(const MatrixType& mat);
    121 
    122     /** \returns the number of rows of the represented matrix.
    123       */
    124     inline Index rows() const { return m_pmat.rows(); }
    125 
    126     /** \returns the number of columns of the represented matrix.
    127       */
    128     inline Index cols() const { return m_pmat.cols();}
    129 
    130     /** \returns a const reference to the \b sparse upper triangular matrix R of the QR factorization.
    131       * \warning The entries of the returned matrix are not sorted. This means that using it in algorithms
    132       *          expecting sorted entries will fail. This include random coefficient accesses (SpaseMatrix::coeff()),
    133       *          and coefficient-wise operations. Matrix products and triangular solves are fine though.
    134       *
    135       * To sort the entries, you can assign it to a row-major matrix, and if a column-major matrix
    136       * is required, you can copy it again:
    137       * \code
    138       * SparseMatrix<double>          R  = qr.matrixR();  // column-major, not sorted!
    139       * SparseMatrix<double,RowMajor> Rr = qr.matrixR();  // row-major, sorted
    140       * SparseMatrix<double>          Rc = Rr;            // column-major, sorted
    141       * \endcode
    142       */
    143     const QRMatrixType& matrixR() const { return m_R; }
    144 
    145     /** \returns the number of non linearly dependent columns as determined by the pivoting threshold.
    146       *
    147       * \sa setPivotThreshold()
    148       */
    149     Index rank() const
    150     {
    151       eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
    152       return m_nonzeropivots;
    153     }
    154 
    155     /** \returns an expression of the matrix Q as products of sparse Householder reflectors.
    156     * The common usage of this function is to apply it to a dense matrix or vector
    157     * \code
    158     * VectorXd B1, B2;
    159     * // Initialize B1
    160     * B2 = matrixQ() * B1;
    161     * \endcode
    162     *
    163     * To get a plain SparseMatrix representation of Q:
    164     * \code
    165     * SparseMatrix<double> Q;
    166     * Q = SparseQR<SparseMatrix<double> >(A).matrixQ();
    167     * \endcode
    168     * Internally, this call simply performs a sparse product between the matrix Q
    169     * and a sparse identity matrix. However, due to the fact that the sparse
    170     * reflectors are stored unsorted, two transpositions are needed to sort
    171     * them before performing the product.
    172     */
    173     SparseQRMatrixQReturnType<SparseQR> matrixQ() const
    174     { return SparseQRMatrixQReturnType<SparseQR>(*this); }
    175 
    176     /** \returns a const reference to the column permutation P that was applied to A such that A*P = Q*R
    177       * It is the combination of the fill-in reducing permutation and numerical column pivoting.
    178       */
    179     const PermutationType& colsPermutation() const
    180     {
    181       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
    182       return m_outputPerm_c;
    183     }
    184 
    185     /** \returns A string describing the type of error.
    186       * This method is provided to ease debugging, not to handle errors.
    187       */
    188     std::string lastErrorMessage() const { return m_lastError; }
    189 
    190     /** \internal */
    191     template<typename Rhs, typename Dest>
    192     bool _solve_impl(const MatrixBase<Rhs> &B, MatrixBase<Dest> &dest) const
    193     {
    194       eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
    195       eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
    196 
    197       Index rank = this->rank();
    198 
    199       // Compute Q^T * b;
    200       typename Dest::PlainObject y, b;
    201       y = this->matrixQ().transpose() * B;
    202       b = y;
    203 
    204       // Solve with the triangular matrix R
    205       y.resize((std::max<Index>)(cols(),y.rows()),y.cols());
    206       y.topRows(rank) = this->matrixR().topLeftCorner(rank, rank).template triangularView<Upper>().solve(b.topRows(rank));
    207       y.bottomRows(y.rows()-rank).setZero();
    208 
    209       // Apply the column permutation
    210       if (m_perm_c.size())  dest = colsPermutation() * y.topRows(cols());
    211       else                  dest = y.topRows(cols());
    212 
    213       m_info = Success;
    214       return true;
    215     }
    216 
    217     /** Sets the threshold that is used to determine linearly dependent columns during the factorization.
    218       *
    219       * In practice, if during the factorization the norm of the column that has to be eliminated is below
    220       * this threshold, then the entire column is treated as zero, and it is moved at the end.
    221       */
    222     void setPivotThreshold(const RealScalar& threshold)
    223     {
    224       m_useDefaultThreshold = false;
    225       m_threshold = threshold;
    226     }
    227 
    228     /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A.
    229       *
    230       * \sa compute()
    231       */
    232     template<typename Rhs>
    233     inline const Solve<SparseQR, Rhs> solve(const MatrixBase<Rhs>& B) const
    234     {
    235       eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
    236       eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
    237       return Solve<SparseQR, Rhs>(*this, B.derived());
    238     }
    239     template<typename Rhs>
    240     inline const Solve<SparseQR, Rhs> solve(const SparseMatrixBase<Rhs>& B) const
    241     {
    242           eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
    243           eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
    244           return Solve<SparseQR, Rhs>(*this, B.derived());
    245     }
    246 
    247     /** \brief Reports whether previous computation was successful.
    248       *
    249       * \returns \c Success if computation was successful,
    250       *          \c NumericalIssue if the QR factorization reports a numerical problem
    251       *          \c InvalidInput if the input matrix is invalid
    252       *
    253       * \sa iparm()
    254       */
    255     ComputationInfo info() const
    256     {
    257       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
    258       return m_info;
    259     }
    260 
    261 
    262     /** \internal */
    263     inline void _sort_matrix_Q()
    264     {
    265       if(this->m_isQSorted) return;
    266       // The matrix Q is sorted during the transposition
    267       SparseMatrix<Scalar, RowMajor, Index> mQrm(this->m_Q);
    268       this->m_Q = mQrm;
    269       this->m_isQSorted = true;
    270     }
    271 
    272 
    273   protected:
    274     bool m_analysisIsok;
    275     bool m_factorizationIsok;
    276     mutable ComputationInfo m_info;
    277     std::string m_lastError;
    278     QRMatrixType m_pmat;            // Temporary matrix
    279     QRMatrixType m_R;               // The triangular factor matrix
    280     QRMatrixType m_Q;               // The orthogonal reflectors
    281     ScalarVector m_hcoeffs;         // The Householder coefficients
    282     PermutationType m_perm_c;       // Fill-reducing  Column  permutation
    283     PermutationType m_pivotperm;    // The permutation for rank revealing
    284     PermutationType m_outputPerm_c; // The final column permutation
    285     RealScalar m_threshold;         // Threshold to determine null Householder reflections
    286     bool m_useDefaultThreshold;     // Use default threshold
    287     Index m_nonzeropivots;          // Number of non zero pivots found
    288     IndexVector m_etree;            // Column elimination tree
    289     IndexVector m_firstRowElt;      // First element in each row
    290     bool m_isQSorted;               // whether Q is sorted or not
    291     bool m_isEtreeOk;               // whether the elimination tree match the initial input matrix
    292 
    293     template <typename, typename > friend struct SparseQR_QProduct;
    294 
    295 };
    296 
    297 /** \brief Preprocessing step of a QR factorization
    298   *
    299   * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
    300   *
    301   * In this step, the fill-reducing permutation is computed and applied to the columns of A
    302   * and the column elimination tree is computed as well. Only the sparsity pattern of \a mat is exploited.
    303   *
    304   * \note In this step it is assumed that there is no empty row in the matrix \a mat.
    305   */
    306 template <typename MatrixType, typename OrderingType>
    307 void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat)
    308 {
    309   eigen_assert(mat.isCompressed() && "SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR");
    310   // Copy to a column major matrix if the input is rowmajor
    311   typename internal::conditional<MatrixType::IsRowMajor,QRMatrixType,const MatrixType&>::type matCpy(mat);
    312   // Compute the column fill reducing ordering
    313   OrderingType ord;
    314   ord(matCpy, m_perm_c);
    315   Index n = mat.cols();
    316   Index m = mat.rows();
    317   Index diagSize = (std::min)(m,n);
    318 
    319   if (!m_perm_c.size())
    320   {
    321     m_perm_c.resize(n);
    322     m_perm_c.indices().setLinSpaced(n, 0,StorageIndex(n-1));
    323   }
    324 
    325   // Compute the column elimination tree of the permuted matrix
    326   m_outputPerm_c = m_perm_c.inverse();
    327   internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
    328   m_isEtreeOk = true;
    329 
    330   m_R.resize(m, n);
    331   m_Q.resize(m, diagSize);
    332 
    333   // Allocate space for nonzero elements : rough estimation
    334   m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree
    335   m_Q.reserve(2*mat.nonZeros());
    336   m_hcoeffs.resize(diagSize);
    337   m_analysisIsok = true;
    338 }
    339 
    340 /** \brief Performs the numerical QR factorization of the input matrix
    341   *
    342   * The function SparseQR::analyzePattern(const MatrixType&) must have been called beforehand with
    343   * a matrix having the same sparsity pattern than \a mat.
    344   *
    345   * \param mat The sparse column-major matrix
    346   */
    347 template <typename MatrixType, typename OrderingType>
    348 void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
    349 {
    350   using std::abs;
    351 
    352   eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step");
    353   StorageIndex m = StorageIndex(mat.rows());
    354   StorageIndex n = StorageIndex(mat.cols());
    355   StorageIndex diagSize = (std::min)(m,n);
    356   IndexVector mark((std::max)(m,n)); mark.setConstant(-1);  // Record the visited nodes
    357   IndexVector Ridx(n), Qidx(m);                             // Store temporarily the row indexes for the current column of R and Q
    358   Index nzcolR, nzcolQ;                                     // Number of nonzero for the current column of R and Q
    359   ScalarVector tval(m);                                     // The dense vector used to compute the current column
    360   RealScalar pivotThreshold = m_threshold;
    361 
    362   m_R.setZero();
    363   m_Q.setZero();
    364   m_pmat = mat;
    365   if(!m_isEtreeOk)
    366   {
    367     m_outputPerm_c = m_perm_c.inverse();
    368     internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
    369     m_isEtreeOk = true;
    370   }
    371 
    372   m_pmat.uncompress(); // To have the innerNonZeroPtr allocated
    373 
    374   // Apply the fill-in reducing permutation lazily:
    375   {
    376     // If the input is row major, copy the original column indices,
    377     // otherwise directly use the input matrix
    378     //
    379     IndexVector originalOuterIndicesCpy;
    380     const StorageIndex *originalOuterIndices = mat.outerIndexPtr();
    381     if(MatrixType::IsRowMajor)
    382     {
    383       originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(),n+1);
    384       originalOuterIndices = originalOuterIndicesCpy.data();
    385     }
    386 
    387     for (int i = 0; i < n; i++)
    388     {
    389       Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
    390       m_pmat.outerIndexPtr()[p] = originalOuterIndices[i];
    391       m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i+1] - originalOuterIndices[i];
    392     }
    393   }
    394 
    395   /* Compute the default threshold as in MatLab, see:
    396    * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
    397    * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3
    398    */
    399   if(m_useDefaultThreshold)
    400   {
    401     RealScalar max2Norm = 0.0;
    402     for (int j = 0; j < n; j++) max2Norm = numext::maxi(max2Norm, m_pmat.col(j).norm());
    403     if(max2Norm==RealScalar(0))
    404       max2Norm = RealScalar(1);
    405     pivotThreshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
    406   }
    407 
    408   // Initialize the numerical permutation
    409   m_pivotperm.setIdentity(n);
    410 
    411   StorageIndex nonzeroCol = 0; // Record the number of valid pivots
    412   m_Q.startVec(0);
    413 
    414   // Left looking rank-revealing QR factorization: compute a column of R and Q at a time
    415   for (StorageIndex col = 0; col < n; ++col)
    416   {
    417     mark.setConstant(-1);
    418     m_R.startVec(col);
    419     mark(nonzeroCol) = col;
    420     Qidx(0) = nonzeroCol;
    421     nzcolR = 0; nzcolQ = 1;
    422     bool found_diag = nonzeroCol>=m;
    423     tval.setZero();
    424 
    425     // Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e.,
    426     // all the nodes (with indexes lower than rank) reachable through the column elimination tree (etree) rooted at node k.
    427     // Note: if the diagonal entry does not exist, then its contribution must be explicitly added,
    428     // thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found.
    429     for (typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
    430     {
    431       StorageIndex curIdx = nonzeroCol;
    432       if(itp) curIdx = StorageIndex(itp.row());
    433       if(curIdx == nonzeroCol) found_diag = true;
    434 
    435       // Get the nonzeros indexes of the current column of R
    436       StorageIndex st = m_firstRowElt(curIdx); // The traversal of the etree starts here
    437       if (st < 0 )
    438       {
    439         m_lastError = "Empty row found during numerical factorization";
    440         m_info = InvalidInput;
    441         return;
    442       }
    443 
    444       // Traverse the etree
    445       Index bi = nzcolR;
    446       for (; mark(st) != col; st = m_etree(st))
    447       {
    448         Ridx(nzcolR) = st;  // Add this row to the list,
    449         mark(st) = col;     // and mark this row as visited
    450         nzcolR++;
    451       }
    452 
    453       // Reverse the list to get the topological ordering
    454       Index nt = nzcolR-bi;
    455       for(Index i = 0; i < nt/2; i++) std::swap(Ridx(bi+i), Ridx(nzcolR-i-1));
    456 
    457       // Copy the current (curIdx,pcol) value of the input matrix
    458       if(itp) tval(curIdx) = itp.value();
    459       else    tval(curIdx) = Scalar(0);
    460 
    461       // Compute the pattern of Q(:,k)
    462       if(curIdx > nonzeroCol && mark(curIdx) != col )
    463       {
    464         Qidx(nzcolQ) = curIdx;  // Add this row to the pattern of Q,
    465         mark(curIdx) = col;     // and mark it as visited
    466         nzcolQ++;
    467       }
    468     }
    469 
    470     // Browse all the indexes of R(:,col) in reverse order
    471     for (Index i = nzcolR-1; i >= 0; i--)
    472     {
    473       Index curIdx = Ridx(i);
    474 
    475       // Apply the curIdx-th householder vector to the current column (temporarily stored into tval)
    476       Scalar tdot(0);
    477 
    478       // First compute q' * tval
    479       tdot = m_Q.col(curIdx).dot(tval);
    480 
    481       tdot *= m_hcoeffs(curIdx);
    482 
    483       // Then update tval = tval - q * tau
    484       // FIXME: tval -= tdot * m_Q.col(curIdx) should amount to the same (need to check/add support for efficient "dense ?= sparse")
    485       for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
    486         tval(itq.row()) -= itq.value() * tdot;
    487 
    488       // Detect fill-in for the current column of Q
    489       if(m_etree(Ridx(i)) == nonzeroCol)
    490       {
    491         for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
    492         {
    493           StorageIndex iQ = StorageIndex(itq.row());
    494           if (mark(iQ) != col)
    495           {
    496             Qidx(nzcolQ++) = iQ;  // Add this row to the pattern of Q,
    497             mark(iQ) = col;       // and mark it as visited
    498           }
    499         }
    500       }
    501     } // End update current column
    502 
    503     Scalar tau = RealScalar(0);
    504     RealScalar beta = 0;
    505 
    506     if(nonzeroCol < diagSize)
    507     {
    508       // Compute the Householder reflection that eliminate the current column
    509       // FIXME this step should call the Householder module.
    510       Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
    511 
    512       // First, the squared norm of Q((col+1):m, col)
    513       RealScalar sqrNorm = 0.;
    514       for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
    515       if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
    516       {
    517         beta = numext::real(c0);
    518         tval(Qidx(0)) = 1;
    519       }
    520       else
    521       {
    522         using std::sqrt;
    523         beta = sqrt(numext::abs2(c0) + sqrNorm);
    524         if(numext::real(c0) >= RealScalar(0))
    525           beta = -beta;
    526         tval(Qidx(0)) = 1;
    527         for (Index itq = 1; itq < nzcolQ; ++itq)
    528           tval(Qidx(itq)) /= (c0 - beta);
    529         tau = numext::conj((beta-c0) / beta);
    530 
    531       }
    532     }
    533 
    534     // Insert values in R
    535     for (Index  i = nzcolR-1; i >= 0; i--)
    536     {
    537       Index curIdx = Ridx(i);
    538       if(curIdx < nonzeroCol)
    539       {
    540         m_R.insertBackByOuterInnerUnordered(col, curIdx) = tval(curIdx);
    541         tval(curIdx) = Scalar(0.);
    542       }
    543     }
    544 
    545     if(nonzeroCol < diagSize && abs(beta) >= pivotThreshold)
    546     {
    547       m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
    548       // The householder coefficient
    549       m_hcoeffs(nonzeroCol) = tau;
    550       // Record the householder reflections
    551       for (Index itq = 0; itq < nzcolQ; ++itq)
    552       {
    553         Index iQ = Qidx(itq);
    554         m_Q.insertBackByOuterInnerUnordered(nonzeroCol,iQ) = tval(iQ);
    555         tval(iQ) = Scalar(0.);
    556       }
    557       nonzeroCol++;
    558       if(nonzeroCol<diagSize)
    559         m_Q.startVec(nonzeroCol);
    560     }
    561     else
    562     {
    563       // Zero pivot found: move implicitly this column to the end
    564       for (Index j = nonzeroCol; j < n-1; j++)
    565         std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
    566 
    567       // Recompute the column elimination tree
    568       internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
    569       m_isEtreeOk = false;
    570     }
    571   }
    572 
    573   m_hcoeffs.tail(diagSize-nonzeroCol).setZero();
    574 
    575   // Finalize the column pointers of the sparse matrices R and Q
    576   m_Q.finalize();
    577   m_Q.makeCompressed();
    578   m_R.finalize();
    579   m_R.makeCompressed();
    580   m_isQSorted = false;
    581 
    582   m_nonzeropivots = nonzeroCol;
    583 
    584   if(nonzeroCol<n)
    585   {
    586     // Permute the triangular factor to put the 'dead' columns to the end
    587     QRMatrixType tempR(m_R);
    588     m_R = tempR * m_pivotperm;
    589 
    590     // Update the column permutation
    591     m_outputPerm_c = m_outputPerm_c * m_pivotperm;
    592   }
    593 
    594   m_isInitialized = true;
    595   m_factorizationIsok = true;
    596   m_info = Success;
    597 }
    598 
    599 template <typename SparseQRType, typename Derived>
    600 struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived> >
    601 {
    602   typedef typename SparseQRType::QRMatrixType MatrixType;
    603   typedef typename SparseQRType::Scalar Scalar;
    604   // Get the references
    605   SparseQR_QProduct(const SparseQRType& qr, const Derived& other, bool transpose) :
    606   m_qr(qr),m_other(other),m_transpose(transpose) {}
    607   inline Index rows() const { return m_transpose ? m_qr.rows() : m_qr.cols(); }
    608   inline Index cols() const { return m_other.cols(); }
    609 
    610   // Assign to a vector
    611   template<typename DesType>
    612   void evalTo(DesType& res) const
    613   {
    614     Index m = m_qr.rows();
    615     Index n = m_qr.cols();
    616     Index diagSize = (std::min)(m,n);
    617     res = m_other;
    618     if (m_transpose)
    619     {
    620       eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
    621       //Compute res = Q' * other column by column
    622       for(Index j = 0; j < res.cols(); j++){
    623         for (Index k = 0; k < diagSize; k++)
    624         {
    625           Scalar tau = Scalar(0);
    626           tau = m_qr.m_Q.col(k).dot(res.col(j));
    627           if(tau==Scalar(0)) continue;
    628           tau = tau * m_qr.m_hcoeffs(k);
    629           res.col(j) -= tau * m_qr.m_Q.col(k);
    630         }
    631       }
    632     }
    633     else
    634     {
    635       eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
    636       // Compute res = Q * other column by column
    637       for(Index j = 0; j < res.cols(); j++)
    638       {
    639         for (Index k = diagSize-1; k >=0; k--)
    640         {
    641           Scalar tau = Scalar(0);
    642           tau = m_qr.m_Q.col(k).dot(res.col(j));
    643           if(tau==Scalar(0)) continue;
    644           tau = tau * m_qr.m_hcoeffs(k);
    645           res.col(j) -= tau * m_qr.m_Q.col(k);
    646         }
    647       }
    648     }
    649   }
    650 
    651   const SparseQRType& m_qr;
    652   const Derived& m_other;
    653   bool m_transpose;
    654 };
    655 
    656 template<typename SparseQRType>
    657 struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<SparseQRType> >
    658 {
    659   typedef typename SparseQRType::Scalar Scalar;
    660   typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
    661   enum {
    662     RowsAtCompileTime = Dynamic,
    663     ColsAtCompileTime = Dynamic
    664   };
    665   explicit SparseQRMatrixQReturnType(const SparseQRType& qr) : m_qr(qr) {}
    666   template<typename Derived>
    667   SparseQR_QProduct<SparseQRType, Derived> operator*(const MatrixBase<Derived>& other)
    668   {
    669     return SparseQR_QProduct<SparseQRType,Derived>(m_qr,other.derived(),false);
    670   }
    671   SparseQRMatrixQTransposeReturnType<SparseQRType> adjoint() const
    672   {
    673     return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
    674   }
    675   inline Index rows() const { return m_qr.rows(); }
    676   inline Index cols() const { return (std::min)(m_qr.rows(),m_qr.cols()); }
    677   // To use for operations with the transpose of Q
    678   SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const
    679   {
    680     return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
    681   }
    682   const SparseQRType& m_qr;
    683 };
    684 
    685 template<typename SparseQRType>
    686 struct SparseQRMatrixQTransposeReturnType
    687 {
    688   explicit SparseQRMatrixQTransposeReturnType(const SparseQRType& qr) : m_qr(qr) {}
    689   template<typename Derived>
    690   SparseQR_QProduct<SparseQRType,Derived> operator*(const MatrixBase<Derived>& other)
    691   {
    692     return SparseQR_QProduct<SparseQRType,Derived>(m_qr,other.derived(), true);
    693   }
    694   const SparseQRType& m_qr;
    695 };
    696 
    697 namespace internal {
    698 
    699 template<typename SparseQRType>
    700 struct evaluator_traits<SparseQRMatrixQReturnType<SparseQRType> >
    701 {
    702   typedef typename SparseQRType::MatrixType MatrixType;
    703   typedef typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind Kind;
    704   typedef SparseShape Shape;
    705 };
    706 
    707 template< typename DstXprType, typename SparseQRType>
    708 struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>, internal::assign_op<typename DstXprType::Scalar,typename DstXprType::Scalar>, Sparse2Sparse>
    709 {
    710   typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
    711   typedef typename DstXprType::Scalar Scalar;
    712   typedef typename DstXprType::StorageIndex StorageIndex;
    713   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &/*func*/)
    714   {
    715     typename DstXprType::PlainObject idMat(src.m_qr.rows(), src.m_qr.rows());
    716     idMat.setIdentity();
    717     // Sort the sparse householder reflectors if needed
    718     const_cast<SparseQRType *>(&src.m_qr)->_sort_matrix_Q();
    719     dst = SparseQR_QProduct<SparseQRType, DstXprType>(src.m_qr, idMat, false);
    720   }
    721 };
    722 
    723 template< typename DstXprType, typename SparseQRType>
    724 struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>, internal::assign_op<typename DstXprType::Scalar,typename DstXprType::Scalar>, Sparse2Dense>
    725 {
    726   typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
    727   typedef typename DstXprType::Scalar Scalar;
    728   typedef typename DstXprType::StorageIndex StorageIndex;
    729   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &/*func*/)
    730   {
    731     dst = src.m_qr.matrixQ() * DstXprType::Identity(src.m_qr.rows(), src.m_qr.rows());
    732   }
    733 };
    734 
    735 } // end namespace internal
    736 
    737 } // end namespace Eigen
    738 
    739 #endif
    740