text: // This file is part of Eigen, a lightweight C++ template library
  // for linear algebra.
  //
  // Copyright (C) 2012-2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
  // Copyright (C) 2012-2014 Gael Guennebaud <gael.guennebaud@inria.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_SPARSE_QR_H
  #define EIGEN_SPARSE_QR_H
  
  namespace Eigen {
  
  template<typename MatrixType, typename OrderingType> class SparseQR;
  template<typename SparseQRType> struct SparseQRMatrixQReturnType;
  template<typename SparseQRType> struct SparseQRMatrixQTransposeReturnType;
  template<typename SparseQRType, typename Derived> struct SparseQR_QProduct;
  namespace internal {
    template <typename SparseQRType> struct traits<SparseQRMatrixQReturnType<SparseQRType> >
    {
      typedef typename SparseQRType::MatrixType ReturnType;
      typedef typename ReturnType::StorageIndex StorageIndex;
      typedef typename ReturnType::StorageKind StorageKind;
      enum {
        RowsAtCompileTime = Dynamic,
        ColsAtCompileTime = Dynamic
      };
    };
    template <typename SparseQRType> struct traits<SparseQRMatrixQTransposeReturnType<SparseQRType> >
    {
      typedef typename SparseQRType::MatrixType ReturnType;
    };
    template <typename SparseQRType, typename Derived> struct traits<SparseQR_QProduct<SparseQRType, Derived> >
    {
      typedef typename Derived::PlainObject ReturnType;
    };
  } // End namespace internal
  
  /**
    * \ingroup SparseQR_Module
    * \class SparseQR
    * \brief Sparse left-looking QR factorization with numerical column pivoting
    * 
    * This class implements a left-looking QR decomposition of sparse matrices
    * with numerical column pivoting.
    * When a column has a norm less than a given tolerance
    * it is implicitly permuted to the end. The QR factorization thus obtained is 
    * given by A*P = Q*R where R is upper triangular or trapezoidal. 
    * 
    * P is the column permutation which is the product of the fill-reducing and the
    * numerical permutations. Use colsPermutation() to get it.
    * 
    * Q is the orthogonal matrix represented as products of Householder reflectors. 
    * Use matrixQ() to get an expression and matrixQ().adjoint() to get the adjoint.
    * You can then apply it to a vector.
    * 
    * R is the sparse triangular or trapezoidal matrix. The later occurs when A is rank-deficient.
    * matrixR().topLeftCorner(rank(), rank()) always returns a triangular factor of full rank.
    * 
    * \tparam _MatrixType The type of the sparse matrix A, must be a column-major SparseMatrix<>
    * \tparam _OrderingType The fill-reducing ordering method. See the \link OrderingMethods_Module 
    *  OrderingMethods \endlink module for the list of built-in and external ordering methods.
    * 
    * \implsparsesolverconcept
    *
    * The numerical pivoting strategy and default threshold are the same as in SuiteSparse QR, and
    * detailed in the following paper:
    * <i>
    * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
    * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011.
    * </i>
    * Even though it is qualified as "rank-revealing", this strategy might fail for some 
    * rank deficient problems. When this class is used to solve linear or least-square problems
    * it is thus strongly recommended to check the accuracy of the computed solution. If it
    * failed, it usually helps to increase the threshold with setPivotThreshold.
    * 
    * \warning The input sparse matrix A must be in compressed mode (see SparseMatrix::makeCompressed()).
    * \warning For complex matrices matrixQ().transpose() will actually return the adjoint matrix.
    * 
    */
  template<typename _MatrixType, typename _OrderingType>
  class SparseQR : public SparseSolverBase<SparseQR<_MatrixType,_OrderingType> >
  {
    protected:
      typedef SparseSolverBase<SparseQR<_MatrixType,_OrderingType> > Base;
      using Base::m_isInitialized;
    public:
      using Base::_solve_impl;
      typedef _MatrixType MatrixType;
      typedef _OrderingType OrderingType;
      typedef typename MatrixType::Scalar Scalar;
      typedef typename MatrixType::RealScalar RealScalar;
      typedef typename MatrixType::StorageIndex StorageIndex;
      typedef SparseMatrix<Scalar,ColMajor,StorageIndex> QRMatrixType;
      typedef Matrix<StorageIndex, Dynamic, 1> IndexVector;
      typedef Matrix<Scalar, Dynamic, 1> ScalarVector;
      typedef PermutationMatrix<Dynamic, Dynamic, StorageIndex> PermutationType;
  
      enum {
        ColsAtCompileTime = MatrixType::ColsAtCompileTime,
        MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
      };
      
    public:
      SparseQR () :  m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
      { }
      
      /** Construct a QR factorization of the matrix \a mat.
        * 
        * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
        * 
        * \sa compute()
        */
      explicit SparseQR(const MatrixType& mat) : m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
      {
        compute(mat);
      }
      
      /** Computes the QR factorization of the sparse matrix \a mat.
        * 
        * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
        * 
        * \sa analyzePattern(), factorize()
        */
      void compute(const MatrixType& mat)
      {
        analyzePattern(mat);
        factorize(mat);
      }
      void analyzePattern(const MatrixType& mat);
      void factorize(const MatrixType& mat);
      
      /** \returns the number of rows of the represented matrix. 
        */
      inline Index rows() const { return m_pmat.rows(); }
      
      /** \returns the number of columns of the represented matrix. 
        */
      inline Index cols() const { return m_pmat.cols();}
      
      /** \returns a const reference to the \b sparse upper triangular matrix R of the QR factorization.
        * \warning The entries of the returned matrix are not sorted. This means that using it in algorithms
        *          expecting sorted entries will fail. This include random coefficient accesses (SpaseMatrix::coeff()),
        *          and coefficient-wise operations. Matrix products and triangular solves are fine though.
        *
        * To sort the entries, you can assign it to a row-major matrix, and if a column-major matrix
        * is required, you can copy it again:
        * \code
        * SparseMatrix<double>          R  = qr.matrixR();  // column-major, not sorted!
        * SparseMatrix<double,RowMajor> Rr = qr.matrixR();  // row-major, sorted
        * SparseMatrix<double>          Rc = Rr;            // column-major, sorted
        * \endcode
        */
      const QRMatrixType& matrixR() const { return m_R; }
      
      /** \returns the number of non linearly dependent columns as determined by the pivoting threshold.
        *
        * \sa setPivotThreshold()
        */
      Index rank() const
      {
        eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
        return m_nonzeropivots; 
      }
      
      /** \returns an expression of the matrix Q as products of sparse Householder reflectors.
      * The common usage of this function is to apply it to a dense matrix or vector
      * \code
      * VectorXd B1, B2;
      * // Initialize B1
      * B2 = matrixQ() * B1;
      * \endcode
      *
      * To get a plain SparseMatrix representation of Q:
      * \code
      * SparseMatrix<double> Q;
      * Q = SparseQR<SparseMatrix<double> >(A).matrixQ();
      * \endcode
      * Internally, this call simply performs a sparse product between the matrix Q
      * and a sparse identity matrix. However, due to the fact that the sparse
      * reflectors are stored unsorted, two transpositions are needed to sort
      * them before performing the product.
      */
      SparseQRMatrixQReturnType<SparseQR> matrixQ() const 
      { return SparseQRMatrixQReturnType<SparseQR>(*this); }
      
      /** \returns a const reference to the column permutation P that was applied to A such that A*P = Q*R
        * It is the combination of the fill-in reducing permutation and numerical column pivoting.
        */
      const PermutationType& colsPermutation() const
      { 
        eigen_assert(m_isInitialized && "Decomposition is not initialized.");
        return m_outputPerm_c;
      }
      
      /** \returns A string describing the type of error.
        * This method is provided to ease debugging, not to handle errors.
        */
      std::string lastErrorMessage() const { return m_lastError; }
      
      /** \internal */
      template<typename Rhs, typename Dest>
      bool _solve_impl(const MatrixBase<Rhs> &B, MatrixBase<Dest> &dest) const
      {
        eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
        eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
  
        Index rank = this->rank();
        
        // Compute Q^* * b;
        typename Dest::PlainObject y, b;
        y = this->matrixQ().adjoint() * B;
        b = y;
        
        // Solve with the triangular matrix R
        y.resize((std::max<Index>)(cols(),y.rows()),y.cols());
        y.topRows(rank) = this->matrixR().topLeftCorner(rank, rank).template triangularView<Upper>().solve(b.topRows(rank));
        y.bottomRows(y.rows()-rank).setZero();
        
        // Apply the column permutation
        if (m_perm_c.size())  dest = colsPermutation() * y.topRows(cols());
        else                  dest = y.topRows(cols());
        
        m_info = Success;
        return true;
      }
  
      /** Sets the threshold that is used to determine linearly dependent columns during the factorization.
        *
        * In practice, if during the factorization the norm of the column that has to be eliminated is below
        * this threshold, then the entire column is treated as zero, and it is moved at the end.
        */
      void setPivotThreshold(const RealScalar& threshold)
      {
        m_useDefaultThreshold = false;
        m_threshold = threshold;
      }
      
      /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A.
        *
        * \sa compute()
        */
      template<typename Rhs>
      inline const Solve<SparseQR, Rhs> solve(const MatrixBase<Rhs>& B) const 
      {
        eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
        eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
        return Solve<SparseQR, Rhs>(*this, B.derived());
      }
      template<typename Rhs>
      inline const Solve<SparseQR, Rhs> solve(const SparseMatrixBase<Rhs>& B) const
      {
            eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
            eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
            return Solve<SparseQR, Rhs>(*this, B.derived());
      }
      
      /** \brief Reports whether previous computation was successful.
        *
        * \returns \c Success if computation was successful,
        *          \c NumericalIssue if the QR factorization reports a numerical problem
        *          \c InvalidInput if the input matrix is invalid
        *
        * \sa iparm()          
        */
      ComputationInfo info() const
      {
        eigen_assert(m_isInitialized && "Decomposition is not initialized.");
        return m_info;
      }
  
  
      /** \internal */
      inline void _sort_matrix_Q()
      {
        if(this->m_isQSorted) return;
        // The matrix Q is sorted during the transposition
        SparseMatrix<Scalar, RowMajor, Index> mQrm(this->m_Q);
        this->m_Q = mQrm;
        this->m_isQSorted = true;
      }
  
      
    protected:
      bool m_analysisIsok;
      bool m_factorizationIsok;
      mutable ComputationInfo m_info;
      std::string m_lastError;
      QRMatrixType m_pmat;            // Temporary matrix
      QRMatrixType m_R;               // The triangular factor matrix
      QRMatrixType m_Q;               // The orthogonal reflectors
      ScalarVector m_hcoeffs;         // The Householder coefficients
      PermutationType m_perm_c;       // Fill-reducing  Column  permutation
      PermutationType m_pivotperm;    // The permutation for rank revealing
      PermutationType m_outputPerm_c; // The final column permutation
      RealScalar m_threshold;         // Threshold to determine null Householder reflections
      bool m_useDefaultThreshold;     // Use default threshold
      Index m_nonzeropivots;          // Number of non zero pivots found
      IndexVector m_etree;            // Column elimination tree
      IndexVector m_firstRowElt;      // First element in each row
      bool m_isQSorted;               // whether Q is sorted or not
      bool m_isEtreeOk;               // whether the elimination tree match the initial input matrix
      
      template <typename, typename > friend struct SparseQR_QProduct;
      
  };
  
  /** \brief Preprocessing step of a QR factorization 
    * 
    * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
    * 
    * In this step, the fill-reducing permutation is computed and applied to the columns of A
    * and the column elimination tree is computed as well. Only the sparsity pattern of \a mat is exploited.
    * 
    * \note In this step it is assumed that there is no empty row in the matrix \a mat.
    */
  template <typename MatrixType, typename OrderingType>
  void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat)
  {
    eigen_assert(mat.isCompressed() && "SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR");
    // Copy to a column major matrix if the input is rowmajor
    typename internal::conditional<MatrixType::IsRowMajor,QRMatrixType,const MatrixType&>::type matCpy(mat);
    // Compute the column fill reducing ordering
    OrderingType ord; 
    ord(matCpy, m_perm_c); 
    Index n = mat.cols();
    Index m = mat.rows();
    Index diagSize = (std::min)(m,n);
    
    if (!m_perm_c.size())
    {
      m_perm_c.resize(n);
      m_perm_c.indices().setLinSpaced(n, 0,StorageIndex(n-1));
    }
    
    // Compute the column elimination tree of the permuted matrix
    m_outputPerm_c = m_perm_c.inverse();
    internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
    m_isEtreeOk = true;
    
    m_R.resize(m, n);
    m_Q.resize(m, diagSize);
    
    // Allocate space for nonzero elements: rough estimation
    m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree
    m_Q.reserve(2*mat.nonZeros());
    m_hcoeffs.resize(diagSize);
    m_analysisIsok = true;
  }
  
  /** \brief Performs the numerical QR factorization of the input matrix
    * 
    * The function SparseQR::analyzePattern(const MatrixType&) must have been called beforehand with
    * a matrix having the same sparsity pattern than \a mat.
    * 
    * \param mat The sparse column-major matrix
    */
  template <typename MatrixType, typename OrderingType>
  void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
  {
    using std::abs;
    
    eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step");
    StorageIndex m = StorageIndex(mat.rows());
    StorageIndex n = StorageIndex(mat.cols());
    StorageIndex diagSize = (std::min)(m,n);
    IndexVector mark((std::max)(m,n)); mark.setConstant(-1);  // Record the visited nodes
    IndexVector Ridx(n), Qidx(m);                             // Store temporarily the row indexes for the current column of R and Q
    Index nzcolR, nzcolQ;                                     // Number of nonzero for the current column of R and Q
    ScalarVector tval(m);                                     // The dense vector used to compute the current column
    RealScalar pivotThreshold = m_threshold;
    
    m_R.setZero();
    m_Q.setZero();
    m_pmat = mat;
    if(!m_isEtreeOk)
    {
      m_outputPerm_c = m_perm_c.inverse();
      internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
      m_isEtreeOk = true;
    }
  
    m_pmat.uncompress(); // To have the innerNonZeroPtr allocated
    
    // Apply the fill-in reducing permutation lazily:
    {
      // If the input is row major, copy the original column indices,
      // otherwise directly use the input matrix
      // 
      IndexVector originalOuterIndicesCpy;
      const StorageIndex *originalOuterIndices = mat.outerIndexPtr();
      if(MatrixType::IsRowMajor)
      {
        originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(),n+1);
        originalOuterIndices = originalOuterIndicesCpy.data();
      }
      
      for (int i = 0; i < n; i++)
      {
        Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
        m_pmat.outerIndexPtr()[p] = originalOuterIndices[i]; 
        m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i+1] - originalOuterIndices[i]; 
      }
    }
    
    /* Compute the default threshold as in MatLab, see:
     * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
     * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3 
     */
    if(m_useDefaultThreshold) 
    {
      RealScalar max2Norm = 0.0;
      for (int j = 0; j < n; j++) max2Norm = numext::maxi(max2Norm, m_pmat.col(j).norm());
      if(max2Norm==RealScalar(0))
        max2Norm = RealScalar(1);
      pivotThreshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
    }
    
    // Initialize the numerical permutation
    m_pivotperm.setIdentity(n);
    
    StorageIndex nonzeroCol = 0; // Record the number of valid pivots
    m_Q.startVec(0);
  
    // Left looking rank-revealing QR factorization: compute a column of R and Q at a time
    for (StorageIndex col = 0; col < n; ++col)
    {
      mark.setConstant(-1);
      m_R.startVec(col);
      mark(nonzeroCol) = col;
      Qidx(0) = nonzeroCol;
      nzcolR = 0; nzcolQ = 1;
      bool found_diag = nonzeroCol>=m;
      tval.setZero(); 
      
      // Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e.,
      // all the nodes (with indexes lower than rank) reachable through the column elimination tree (etree) rooted at node k.
      // Note: if the diagonal entry does not exist, then its contribution must be explicitly added,
      // thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found.
      for (typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
      {
        StorageIndex curIdx = nonzeroCol;
        if(itp) curIdx = StorageIndex(itp.row());
        if(curIdx == nonzeroCol) found_diag = true;
        
        // Get the nonzeros indexes of the current column of R
        StorageIndex st = m_firstRowElt(curIdx); // The traversal of the etree starts here
        if (st < 0 )
        {
          m_lastError = "Empty row found during numerical factorization";
          m_info = InvalidInput;
          return;
        }
  
        // Traverse the etree 
        Index bi = nzcolR;
        for (; mark(st) != col; st = m_etree(st))
        {
          Ridx(nzcolR) = st;  // Add this row to the list,
          mark(st) = col;     // and mark this row as visited
          nzcolR++;
        }
  
        // Reverse the list to get the topological ordering
        Index nt = nzcolR-bi;
        for(Index i = 0; i < nt/2; i++) std::swap(Ridx(bi+i), Ridx(nzcolR-i-1));
         
        // Copy the current (curIdx,pcol) value of the input matrix
        if(itp) tval(curIdx) = itp.value();
        else    tval(curIdx) = Scalar(0);
        
        // Compute the pattern of Q(:,k)
        if(curIdx > nonzeroCol && mark(curIdx) != col ) 
        {
          Qidx(nzcolQ) = curIdx;  // Add this row to the pattern of Q,
          mark(curIdx) = col;     // and mark it as visited
          nzcolQ++;
        }
      }
  
      // Browse all the indexes of R(:,col) in reverse order
      for (Index i = nzcolR-1; i >= 0; i--)
      {
        Index curIdx = Ridx(i);
        
        // Apply the curIdx-th householder vector to the current column (temporarily stored into tval)
        Scalar tdot(0);
        
        // First compute q' * tval
        tdot = m_Q.col(curIdx).dot(tval);
  
        tdot *= m_hcoeffs(curIdx);
        
        // Then update tval = tval - q * tau
        // FIXME: tval -= tdot * m_Q.col(curIdx) should amount to the same (need to check/add support for efficient "dense ?= sparse")
        for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
          tval(itq.row()) -= itq.value() * tdot;
  
        // Detect fill-in for the current column of Q
        if(m_etree(Ridx(i)) == nonzeroCol)
        {
          for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
          {
            StorageIndex iQ = StorageIndex(itq.row());
            if (mark(iQ) != col)
            {
              Qidx(nzcolQ++) = iQ;  // Add this row to the pattern of Q,
              mark(iQ) = col;       // and mark it as visited
            }
          }
        }
      } // End update current column
      
      Scalar tau = RealScalar(0);
      RealScalar beta = 0;
      
      if(nonzeroCol < diagSize)
      {
        // Compute the Householder reflection that eliminate the current column
        // FIXME this step should call the Householder module.
        Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
        
        // First, the squared norm of Q((col+1):m, col)
        RealScalar sqrNorm = 0.;
        for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
        if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
        {
          beta = numext::real(c0);
          tval(Qidx(0)) = 1;
        }
        else
        {
          using std::sqrt;
          beta = sqrt(numext::abs2(c0) + sqrNorm);
          if(numext::real(c0) >= RealScalar(0))
            beta = -beta;
          tval(Qidx(0)) = 1;
          for (Index itq = 1; itq < nzcolQ; ++itq)
            tval(Qidx(itq)) /= (c0 - beta);
          tau = numext::conj((beta-c0) / beta);
            
        }
      }
  
      // Insert values in R
      for (Index  i = nzcolR-1; i >= 0; i--)
      {
        Index curIdx = Ridx(i);
        if(curIdx < nonzeroCol) 
        {
          m_R.insertBackByOuterInnerUnordered(col, curIdx) = tval(curIdx);
          tval(curIdx) = Scalar(0.);
        }
      }
  
      if(nonzeroCol < diagSize && abs(beta) >= pivotThreshold)
      {
        m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
        // The householder coefficient
        m_hcoeffs(nonzeroCol) = tau;
        // Record the householder reflections
        for (Index itq = 0; itq < nzcolQ; ++itq)
        {
          Index iQ = Qidx(itq);
          m_Q.insertBackByOuterInnerUnordered(nonzeroCol,iQ) = tval(iQ);
          tval(iQ) = Scalar(0.);
        }
        nonzeroCol++;
        if(nonzeroCol<diagSize)
          m_Q.startVec(nonzeroCol);
      }
      else
      {
        // Zero pivot found: move implicitly this column to the end
        for (Index j = nonzeroCol; j < n-1; j++) 
          std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
        
        // Recompute the column elimination tree
        internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
        m_isEtreeOk = false;
      }
    }
    
    m_hcoeffs.tail(diagSize-nonzeroCol).setZero();
    
    // Finalize the column pointers of the sparse matrices R and Q
    m_Q.finalize();
    m_Q.makeCompressed();
    m_R.finalize();
    m_R.makeCompressed();
    m_isQSorted = false;
  
    m_nonzeropivots = nonzeroCol;
    
    if(nonzeroCol<n)
    {
      // Permute the triangular factor to put the 'dead' columns to the end
      QRMatrixType tempR(m_R);
      m_R = tempR * m_pivotperm;
      
      // Update the column permutation
      m_outputPerm_c = m_outputPerm_c * m_pivotperm;
    }
    
    m_isInitialized = true; 
    m_factorizationIsok = true;
    m_info = Success;
  }
  
  template <typename SparseQRType, typename Derived>
  struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived> >
  {
    typedef typename SparseQRType::QRMatrixType MatrixType;
    typedef typename SparseQRType::Scalar Scalar;
    // Get the references 
    SparseQR_QProduct(const SparseQRType& qr, const Derived& other, bool transpose) : 
    m_qr(qr),m_other(other),m_transpose(transpose) {}
    inline Index rows() const { return m_qr.matrixQ().rows(); }
    inline Index cols() const { return m_other.cols(); }
    
    // Assign to a vector
    template<typename DesType>
    void evalTo(DesType& res) const
    {
      Index m = m_qr.rows();
      Index n = m_qr.cols();
      Index diagSize = (std::min)(m,n);
      res = m_other;
      if (m_transpose)
      {
        eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
        //Compute res = Q' * other column by column
        for(Index j = 0; j < res.cols(); j++){
          for (Index k = 0; k < diagSize; k++)
          {
            Scalar tau = Scalar(0);
            tau = m_qr.m_Q.col(k).dot(res.col(j));
            if(tau==Scalar(0)) continue;
            tau = tau * m_qr.m_hcoeffs(k);
            res.col(j) -= tau * m_qr.m_Q.col(k);
          }
        }
      }
      else
      {
        eigen_assert(m_qr.matrixQ().cols() == m_other.rows() && "Non conforming object sizes");
  
        res.conservativeResize(rows(), cols());
  
        // Compute res = Q * other column by column
        for(Index j = 0; j < res.cols(); j++)
        {
          Index start_k = internal::is_identity<Derived>::value ? numext::mini(j,diagSize-1) : diagSize-1;
          for (Index k = start_k; k >=0; k--)
          {
            Scalar tau = Scalar(0);
            tau = m_qr.m_Q.col(k).dot(res.col(j));
            if(tau==Scalar(0)) continue;
            tau = tau * numext::conj(m_qr.m_hcoeffs(k));
            res.col(j) -= tau * m_qr.m_Q.col(k);
          }
        }
      }
    }
    
    const SparseQRType& m_qr;
    const Derived& m_other;
    bool m_transpose; // TODO this actually means adjoint
  };
  
  template<typename SparseQRType>
  struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<SparseQRType> >
  {  
    typedef typename SparseQRType::Scalar Scalar;
    typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
    enum {
      RowsAtCompileTime = Dynamic,
      ColsAtCompileTime = Dynamic
    };
    explicit SparseQRMatrixQReturnType(const SparseQRType& qr) : m_qr(qr) {}
    template<typename Derived>
    SparseQR_QProduct<SparseQRType, Derived> operator*(const MatrixBase<Derived>& other)
    {
      return SparseQR_QProduct<SparseQRType,Derived>(m_qr,other.derived(),false);
    }
    // To use for operations with the adjoint of Q
    SparseQRMatrixQTransposeReturnType<SparseQRType> adjoint() const
    {
      return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
    }
    inline Index rows() const { return m_qr.rows(); }
    inline Index cols() const { return m_qr.rows(); }
    // To use for operations with the transpose of Q FIXME this is the same as adjoint at the moment
    SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const
    {
      return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
    }
    const SparseQRType& m_qr;
  };
  
  // TODO this actually represents the adjoint of Q
  template<typename SparseQRType>
  struct SparseQRMatrixQTransposeReturnType
  {
    explicit SparseQRMatrixQTransposeReturnType(const SparseQRType& qr) : m_qr(qr) {}
    template<typename Derived>
    SparseQR_QProduct<SparseQRType,Derived> operator*(const MatrixBase<Derived>& other)
    {
      return SparseQR_QProduct<SparseQRType,Derived>(m_qr,other.derived(), true);
    }
    const SparseQRType& m_qr;
  };
  
  namespace internal {
    
  template<typename SparseQRType>
  struct evaluator_traits<SparseQRMatrixQReturnType<SparseQRType> >
  {
    typedef typename SparseQRType::MatrixType MatrixType;
    typedef typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind Kind;
    typedef SparseShape Shape;
  };
  
  template< typename DstXprType, typename SparseQRType>
  struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>, internal::assign_op<typename DstXprType::Scalar,typename DstXprType::Scalar>, Sparse2Sparse>
  {
    typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
    typedef typename DstXprType::Scalar Scalar;
    typedef typename DstXprType::StorageIndex StorageIndex;
    static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &/*func*/)
    {
      typename DstXprType::PlainObject idMat(src.rows(), src.cols());
      idMat.setIdentity();
      // Sort the sparse householder reflectors if needed
      const_cast<SparseQRType *>(&src.m_qr)->_sort_matrix_Q();
      dst = SparseQR_QProduct<SparseQRType, DstXprType>(src.m_qr, idMat, false);
    }
  };
  
  template< typename DstXprType, typename SparseQRType>
  struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>, internal::assign_op<typename DstXprType::Scalar,typename DstXprType::Scalar>, Sparse2Dense>
  {
    typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
    typedef typename DstXprType::Scalar Scalar;
    typedef typename DstXprType::StorageIndex StorageIndex;
    static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &/*func*/)
    {
      dst = src.m_qr.matrixQ() * DstXprType::Identity(src.m_qr.rows(), src.m_qr.rows());
    }
  };
  
  } // end namespace internal
  
  } // end namespace Eigen
  
  #endif
  