Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:06:44

0001 // This file is part of Eigen, a lightweight C++ template library
0002 // for linear algebra.
0003 //
0004 // Copyright (C) 2012-2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
0005 // Copyright (C) 2012-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
0006 //
0007 // This Source Code Form is subject to the terms of the Mozilla
0008 // Public License v. 2.0. If a copy of the MPL was not distributed
0009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
0010 
0011 #ifndef EIGEN_SPARSE_QR_H
0012 #define EIGEN_SPARSE_QR_H
0013 
0014 namespace RivetEigen {
0015 
0016 template<typename MatrixType, typename OrderingType> class SparseQR;
0017 template<typename SparseQRType> struct SparseQRMatrixQReturnType;
0018 template<typename SparseQRType> struct SparseQRMatrixQTransposeReturnType;
0019 template<typename SparseQRType, typename Derived> struct SparseQR_QProduct;
0020 namespace internal {
0021   template <typename SparseQRType> struct traits<SparseQRMatrixQReturnType<SparseQRType> >
0022   {
0023     typedef typename SparseQRType::MatrixType ReturnType;
0024     typedef typename ReturnType::StorageIndex StorageIndex;
0025     typedef typename ReturnType::StorageKind StorageKind;
0026     enum {
0027       RowsAtCompileTime = Dynamic,
0028       ColsAtCompileTime = Dynamic
0029     };
0030   };
0031   template <typename SparseQRType> struct traits<SparseQRMatrixQTransposeReturnType<SparseQRType> >
0032   {
0033     typedef typename SparseQRType::MatrixType ReturnType;
0034   };
0035   template <typename SparseQRType, typename Derived> struct traits<SparseQR_QProduct<SparseQRType, Derived> >
0036   {
0037     typedef typename Derived::PlainObject ReturnType;
0038   };
0039 } // End namespace internal
0040 
0041 /**
0042   * \ingroup SparseQR_Module
0043   * \class SparseQR
0044   * \brief Sparse left-looking QR factorization with numerical column pivoting
0045   * 
0046   * This class implements a left-looking QR decomposition of sparse matrices
0047   * with numerical column pivoting.
0048   * When a column has a norm less than a given tolerance
0049   * it is implicitly permuted to the end. The QR factorization thus obtained is 
0050   * given by A*P = Q*R where R is upper triangular or trapezoidal. 
0051   * 
0052   * P is the column permutation which is the product of the fill-reducing and the
0053   * numerical permutations. Use colsPermutation() to get it.
0054   * 
0055   * Q is the orthogonal matrix represented as products of Householder reflectors. 
0056   * Use matrixQ() to get an expression and matrixQ().adjoint() to get the adjoint.
0057   * You can then apply it to a vector.
0058   * 
0059   * R is the sparse triangular or trapezoidal matrix. The later occurs when A is rank-deficient.
0060   * matrixR().topLeftCorner(rank(), rank()) always returns a triangular factor of full rank.
0061   * 
0062   * \tparam _MatrixType The type of the sparse matrix A, must be a column-major SparseMatrix<>
0063   * \tparam _OrderingType The fill-reducing ordering method. See the \link OrderingMethods_Module 
0064   *  OrderingMethods \endlink module for the list of built-in and external ordering methods.
0065   * 
0066   * \implsparsesolverconcept
0067   *
0068   * The numerical pivoting strategy and default threshold are the same as in SuiteSparse QR, and
0069   * detailed in the following paper:
0070   * <i>
0071   * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
0072   * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011.
0073   * </i>
0074   * Even though it is qualified as "rank-revealing", this strategy might fail for some 
0075   * rank deficient problems. When this class is used to solve linear or least-square problems
0076   * it is thus strongly recommended to check the accuracy of the computed solution. If it
0077   * failed, it usually helps to increase the threshold with setPivotThreshold.
0078   * 
0079   * \warning The input sparse matrix A must be in compressed mode (see SparseMatrix::makeCompressed()).
0080   * \warning For complex matrices matrixQ().transpose() will actually return the adjoint matrix.
0081   * 
0082   */
0083 template<typename _MatrixType, typename _OrderingType>
0084 class SparseQR : public SparseSolverBase<SparseQR<_MatrixType,_OrderingType> >
0085 {
0086   protected:
0087     typedef SparseSolverBase<SparseQR<_MatrixType,_OrderingType> > Base;
0088     using Base::m_isInitialized;
0089   public:
0090     using Base::_solve_impl;
0091     typedef _MatrixType MatrixType;
0092     typedef _OrderingType OrderingType;
0093     typedef typename MatrixType::Scalar Scalar;
0094     typedef typename MatrixType::RealScalar RealScalar;
0095     typedef typename MatrixType::StorageIndex StorageIndex;
0096     typedef SparseMatrix<Scalar,ColMajor,StorageIndex> QRMatrixType;
0097     typedef Matrix<StorageIndex, Dynamic, 1> IndexVector;
0098     typedef Matrix<Scalar, Dynamic, 1> ScalarVector;
0099     typedef PermutationMatrix<Dynamic, Dynamic, StorageIndex> PermutationType;
0100 
0101     enum {
0102       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
0103       MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
0104     };
0105     
0106   public:
0107     SparseQR () :  m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
0108     { }
0109     
0110     /** Construct a QR factorization of the matrix \a mat.
0111       * 
0112       * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
0113       * 
0114       * \sa compute()
0115       */
0116     explicit SparseQR(const MatrixType& mat) : m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
0117     {
0118       compute(mat);
0119     }
0120     
0121     /** Computes the QR factorization of the sparse matrix \a mat.
0122       * 
0123       * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
0124       * 
0125       * \sa analyzePattern(), factorize()
0126       */
0127     void compute(const MatrixType& mat)
0128     {
0129       analyzePattern(mat);
0130       factorize(mat);
0131     }
0132     void analyzePattern(const MatrixType& mat);
0133     void factorize(const MatrixType& mat);
0134     
0135     /** \returns the number of rows of the represented matrix. 
0136       */
0137     inline Index rows() const { return m_pmat.rows(); }
0138     
0139     /** \returns the number of columns of the represented matrix. 
0140       */
0141     inline Index cols() const { return m_pmat.cols();}
0142     
0143     /** \returns a const reference to the \b sparse upper triangular matrix R of the QR factorization.
0144       * \warning The entries of the returned matrix are not sorted. This means that using it in algorithms
0145       *          expecting sorted entries will fail. This include random coefficient accesses (SpaseMatrix::coeff()),
0146       *          and coefficient-wise operations. Matrix products and triangular solves are fine though.
0147       *
0148       * To sort the entries, you can assign it to a row-major matrix, and if a column-major matrix
0149       * is required, you can copy it again:
0150       * \code
0151       * SparseMatrix<double>          R  = qr.matrixR();  // column-major, not sorted!
0152       * SparseMatrix<double,RowMajor> Rr = qr.matrixR();  // row-major, sorted
0153       * SparseMatrix<double>          Rc = Rr;            // column-major, sorted
0154       * \endcode
0155       */
0156     const QRMatrixType& matrixR() const { return m_R; }
0157     
0158     /** \returns the number of non linearly dependent columns as determined by the pivoting threshold.
0159       *
0160       * \sa setPivotThreshold()
0161       */
0162     Index rank() const
0163     {
0164       eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
0165       return m_nonzeropivots; 
0166     }
0167     
0168     /** \returns an expression of the matrix Q as products of sparse Householder reflectors.
0169     * The common usage of this function is to apply it to a dense matrix or vector
0170     * \code
0171     * VectorXd B1, B2;
0172     * // Initialize B1
0173     * B2 = matrixQ() * B1;
0174     * \endcode
0175     *
0176     * To get a plain SparseMatrix representation of Q:
0177     * \code
0178     * SparseMatrix<double> Q;
0179     * Q = SparseQR<SparseMatrix<double> >(A).matrixQ();
0180     * \endcode
0181     * Internally, this call simply performs a sparse product between the matrix Q
0182     * and a sparse identity matrix. However, due to the fact that the sparse
0183     * reflectors are stored unsorted, two transpositions are needed to sort
0184     * them before performing the product.
0185     */
0186     SparseQRMatrixQReturnType<SparseQR> matrixQ() const 
0187     { return SparseQRMatrixQReturnType<SparseQR>(*this); }
0188     
0189     /** \returns a const reference to the column permutation P that was applied to A such that A*P = Q*R
0190       * It is the combination of the fill-in reducing permutation and numerical column pivoting.
0191       */
0192     const PermutationType& colsPermutation() const
0193     { 
0194       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
0195       return m_outputPerm_c;
0196     }
0197     
0198     /** \returns A string describing the type of error.
0199       * This method is provided to ease debugging, not to handle errors.
0200       */
0201     std::string lastErrorMessage() const { return m_lastError; }
0202     
0203     /** \internal */
0204     template<typename Rhs, typename Dest>
0205     bool _solve_impl(const MatrixBase<Rhs> &B, MatrixBase<Dest> &dest) const
0206     {
0207       eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
0208       eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
0209 
0210       Index rank = this->rank();
0211       
0212       // Compute Q^* * b;
0213       typename Dest::PlainObject y, b;
0214       y = this->matrixQ().adjoint() * B;
0215       b = y;
0216       
0217       // Solve with the triangular matrix R
0218       y.resize((std::max<Index>)(cols(),y.rows()),y.cols());
0219       y.topRows(rank) = this->matrixR().topLeftCorner(rank, rank).template triangularView<Upper>().solve(b.topRows(rank));
0220       y.bottomRows(y.rows()-rank).setZero();
0221       
0222       // Apply the column permutation
0223       if (m_perm_c.size())  dest = colsPermutation() * y.topRows(cols());
0224       else                  dest = y.topRows(cols());
0225       
0226       m_info = Success;
0227       return true;
0228     }
0229 
0230     /** Sets the threshold that is used to determine linearly dependent columns during the factorization.
0231       *
0232       * In practice, if during the factorization the norm of the column that has to be eliminated is below
0233       * this threshold, then the entire column is treated as zero, and it is moved at the end.
0234       */
0235     void setPivotThreshold(const RealScalar& threshold)
0236     {
0237       m_useDefaultThreshold = false;
0238       m_threshold = threshold;
0239     }
0240     
0241     /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A.
0242       *
0243       * \sa compute()
0244       */
0245     template<typename Rhs>
0246     inline const Solve<SparseQR, Rhs> solve(const MatrixBase<Rhs>& B) const 
0247     {
0248       eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
0249       eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
0250       return Solve<SparseQR, Rhs>(*this, B.derived());
0251     }
0252     template<typename Rhs>
0253     inline const Solve<SparseQR, Rhs> solve(const SparseMatrixBase<Rhs>& B) const
0254     {
0255           eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
0256           eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
0257           return Solve<SparseQR, Rhs>(*this, B.derived());
0258     }
0259     
0260     /** \brief Reports whether previous computation was successful.
0261       *
0262       * \returns \c Success if computation was successful,
0263       *          \c NumericalIssue if the QR factorization reports a numerical problem
0264       *          \c InvalidInput if the input matrix is invalid
0265       *
0266       * \sa iparm()          
0267       */
0268     ComputationInfo info() const
0269     {
0270       eigen_assert(m_isInitialized && "Decomposition is not initialized.");
0271       return m_info;
0272     }
0273 
0274 
0275     /** \internal */
0276     inline void _sort_matrix_Q()
0277     {
0278       if(this->m_isQSorted) return;
0279       // The matrix Q is sorted during the transposition
0280       SparseMatrix<Scalar, RowMajor, Index> mQrm(this->m_Q);
0281       this->m_Q = mQrm;
0282       this->m_isQSorted = true;
0283     }
0284 
0285     
0286   protected:
0287     bool m_analysisIsok;
0288     bool m_factorizationIsok;
0289     mutable ComputationInfo m_info;
0290     std::string m_lastError;
0291     QRMatrixType m_pmat;            // Temporary matrix
0292     QRMatrixType m_R;               // The triangular factor matrix
0293     QRMatrixType m_Q;               // The orthogonal reflectors
0294     ScalarVector m_hcoeffs;         // The Householder coefficients
0295     PermutationType m_perm_c;       // Fill-reducing  Column  permutation
0296     PermutationType m_pivotperm;    // The permutation for rank revealing
0297     PermutationType m_outputPerm_c; // The final column permutation
0298     RealScalar m_threshold;         // Threshold to determine null Householder reflections
0299     bool m_useDefaultThreshold;     // Use default threshold
0300     Index m_nonzeropivots;          // Number of non zero pivots found
0301     IndexVector m_etree;            // Column elimination tree
0302     IndexVector m_firstRowElt;      // First element in each row
0303     bool m_isQSorted;               // whether Q is sorted or not
0304     bool m_isEtreeOk;               // whether the elimination tree match the initial input matrix
0305     
0306     template <typename, typename > friend struct SparseQR_QProduct;
0307     
0308 };
0309 
0310 /** \brief Preprocessing step of a QR factorization 
0311   * 
0312   * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
0313   * 
0314   * In this step, the fill-reducing permutation is computed and applied to the columns of A
0315   * and the column elimination tree is computed as well. Only the sparsity pattern of \a mat is exploited.
0316   * 
0317   * \note In this step it is assumed that there is no empty row in the matrix \a mat.
0318   */
0319 template <typename MatrixType, typename OrderingType>
0320 void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat)
0321 {
0322   eigen_assert(mat.isCompressed() && "SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR");
0323   // Copy to a column major matrix if the input is rowmajor
0324   typename internal::conditional<MatrixType::IsRowMajor,QRMatrixType,const MatrixType&>::type matCpy(mat);
0325   // Compute the column fill reducing ordering
0326   OrderingType ord; 
0327   ord(matCpy, m_perm_c); 
0328   Index n = mat.cols();
0329   Index m = mat.rows();
0330   Index diagSize = (std::min)(m,n);
0331   
0332   if (!m_perm_c.size())
0333   {
0334     m_perm_c.resize(n);
0335     m_perm_c.indices().setLinSpaced(n, 0,StorageIndex(n-1));
0336   }
0337   
0338   // Compute the column elimination tree of the permuted matrix
0339   m_outputPerm_c = m_perm_c.inverse();
0340   internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
0341   m_isEtreeOk = true;
0342   
0343   m_R.resize(m, n);
0344   m_Q.resize(m, diagSize);
0345   
0346   // Allocate space for nonzero elements: rough estimation
0347   m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree
0348   m_Q.reserve(2*mat.nonZeros());
0349   m_hcoeffs.resize(diagSize);
0350   m_analysisIsok = true;
0351 }
0352 
0353 /** \brief Performs the numerical QR factorization of the input matrix
0354   * 
0355   * The function SparseQR::analyzePattern(const MatrixType&) must have been called beforehand with
0356   * a matrix having the same sparsity pattern than \a mat.
0357   * 
0358   * \param mat The sparse column-major matrix
0359   */
0360 template <typename MatrixType, typename OrderingType>
0361 void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
0362 {
0363   using std::abs;
0364   
0365   eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step");
0366   StorageIndex m = StorageIndex(mat.rows());
0367   StorageIndex n = StorageIndex(mat.cols());
0368   StorageIndex diagSize = (std::min)(m,n);
0369   IndexVector mark((std::max)(m,n)); mark.setConstant(-1);  // Record the visited nodes
0370   IndexVector Ridx(n), Qidx(m);                             // Store temporarily the row indexes for the current column of R and Q
0371   Index nzcolR, nzcolQ;                                     // Number of nonzero for the current column of R and Q
0372   ScalarVector tval(m);                                     // The dense vector used to compute the current column
0373   RealScalar pivotThreshold = m_threshold;
0374   
0375   m_R.setZero();
0376   m_Q.setZero();
0377   m_pmat = mat;
0378   if(!m_isEtreeOk)
0379   {
0380     m_outputPerm_c = m_perm_c.inverse();
0381     internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
0382     m_isEtreeOk = true;
0383   }
0384 
0385   m_pmat.uncompress(); // To have the innerNonZeroPtr allocated
0386   
0387   // Apply the fill-in reducing permutation lazily:
0388   {
0389     // If the input is row major, copy the original column indices,
0390     // otherwise directly use the input matrix
0391     // 
0392     IndexVector originalOuterIndicesCpy;
0393     const StorageIndex *originalOuterIndices = mat.outerIndexPtr();
0394     if(MatrixType::IsRowMajor)
0395     {
0396       originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(),n+1);
0397       originalOuterIndices = originalOuterIndicesCpy.data();
0398     }
0399     
0400     for (int i = 0; i < n; i++)
0401     {
0402       Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
0403       m_pmat.outerIndexPtr()[p] = originalOuterIndices[i]; 
0404       m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i+1] - originalOuterIndices[i]; 
0405     }
0406   }
0407   
0408   /* Compute the default threshold as in MatLab, see:
0409    * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
0410    * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3 
0411    */
0412   if(m_useDefaultThreshold) 
0413   {
0414     RealScalar max2Norm = 0.0;
0415     for (int j = 0; j < n; j++) max2Norm = numext::maxi(max2Norm, m_pmat.col(j).norm());
0416     if(max2Norm==RealScalar(0))
0417       max2Norm = RealScalar(1);
0418     pivotThreshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
0419   }
0420   
0421   // Initialize the numerical permutation
0422   m_pivotperm.setIdentity(n);
0423   
0424   StorageIndex nonzeroCol = 0; // Record the number of valid pivots
0425   m_Q.startVec(0);
0426 
0427   // Left looking rank-revealing QR factorization: compute a column of R and Q at a time
0428   for (StorageIndex col = 0; col < n; ++col)
0429   {
0430     mark.setConstant(-1);
0431     m_R.startVec(col);
0432     mark(nonzeroCol) = col;
0433     Qidx(0) = nonzeroCol;
0434     nzcolR = 0; nzcolQ = 1;
0435     bool found_diag = nonzeroCol>=m;
0436     tval.setZero(); 
0437     
0438     // Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e.,
0439     // all the nodes (with indexes lower than rank) reachable through the column elimination tree (etree) rooted at node k.
0440     // Note: if the diagonal entry does not exist, then its contribution must be explicitly added,
0441     // thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found.
0442     for (typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
0443     {
0444       StorageIndex curIdx = nonzeroCol;
0445       if(itp) curIdx = StorageIndex(itp.row());
0446       if(curIdx == nonzeroCol) found_diag = true;
0447       
0448       // Get the nonzeros indexes of the current column of R
0449       StorageIndex st = m_firstRowElt(curIdx); // The traversal of the etree starts here
0450       if (st < 0 )
0451       {
0452         m_lastError = "Empty row found during numerical factorization";
0453         m_info = InvalidInput;
0454         return;
0455       }
0456 
0457       // Traverse the etree 
0458       Index bi = nzcolR;
0459       for (; mark(st) != col; st = m_etree(st))
0460       {
0461         Ridx(nzcolR) = st;  // Add this row to the list,
0462         mark(st) = col;     // and mark this row as visited
0463         nzcolR++;
0464       }
0465 
0466       // Reverse the list to get the topological ordering
0467       Index nt = nzcolR-bi;
0468       for(Index i = 0; i < nt/2; i++) std::swap(Ridx(bi+i), Ridx(nzcolR-i-1));
0469        
0470       // Copy the current (curIdx,pcol) value of the input matrix
0471       if(itp) tval(curIdx) = itp.value();
0472       else    tval(curIdx) = Scalar(0);
0473       
0474       // Compute the pattern of Q(:,k)
0475       if(curIdx > nonzeroCol && mark(curIdx) != col ) 
0476       {
0477         Qidx(nzcolQ) = curIdx;  // Add this row to the pattern of Q,
0478         mark(curIdx) = col;     // and mark it as visited
0479         nzcolQ++;
0480       }
0481     }
0482 
0483     // Browse all the indexes of R(:,col) in reverse order
0484     for (Index i = nzcolR-1; i >= 0; i--)
0485     {
0486       Index curIdx = Ridx(i);
0487       
0488       // Apply the curIdx-th householder vector to the current column (temporarily stored into tval)
0489       Scalar tdot(0);
0490       
0491       // First compute q' * tval
0492       tdot = m_Q.col(curIdx).dot(tval);
0493 
0494       tdot *= m_hcoeffs(curIdx);
0495       
0496       // Then update tval = tval - q * tau
0497       // FIXME: tval -= tdot * m_Q.col(curIdx) should amount to the same (need to check/add support for efficient "dense ?= sparse")
0498       for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
0499         tval(itq.row()) -= itq.value() * tdot;
0500 
0501       // Detect fill-in for the current column of Q
0502       if(m_etree(Ridx(i)) == nonzeroCol)
0503       {
0504         for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
0505         {
0506           StorageIndex iQ = StorageIndex(itq.row());
0507           if (mark(iQ) != col)
0508           {
0509             Qidx(nzcolQ++) = iQ;  // Add this row to the pattern of Q,
0510             mark(iQ) = col;       // and mark it as visited
0511           }
0512         }
0513       }
0514     } // End update current column
0515     
0516     Scalar tau = RealScalar(0);
0517     RealScalar beta = 0;
0518     
0519     if(nonzeroCol < diagSize)
0520     {
0521       // Compute the Householder reflection that eliminate the current column
0522       // FIXME this step should call the Householder module.
0523       Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
0524       
0525       // First, the squared norm of Q((col+1):m, col)
0526       RealScalar sqrNorm = 0.;
0527       for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
0528       if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
0529       {
0530         beta = numext::real(c0);
0531         tval(Qidx(0)) = 1;
0532       }
0533       else
0534       {
0535         using std::sqrt;
0536         beta = sqrt(numext::abs2(c0) + sqrNorm);
0537         if(numext::real(c0) >= RealScalar(0))
0538           beta = -beta;
0539         tval(Qidx(0)) = 1;
0540         for (Index itq = 1; itq < nzcolQ; ++itq)
0541           tval(Qidx(itq)) /= (c0 - beta);
0542         tau = numext::conj((beta-c0) / beta);
0543           
0544       }
0545     }
0546 
0547     // Insert values in R
0548     for (Index  i = nzcolR-1; i >= 0; i--)
0549     {
0550       Index curIdx = Ridx(i);
0551       if(curIdx < nonzeroCol) 
0552       {
0553         m_R.insertBackByOuterInnerUnordered(col, curIdx) = tval(curIdx);
0554         tval(curIdx) = Scalar(0.);
0555       }
0556     }
0557 
0558     if(nonzeroCol < diagSize && abs(beta) >= pivotThreshold)
0559     {
0560       m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
0561       // The householder coefficient
0562       m_hcoeffs(nonzeroCol) = tau;
0563       // Record the householder reflections
0564       for (Index itq = 0; itq < nzcolQ; ++itq)
0565       {
0566         Index iQ = Qidx(itq);
0567         m_Q.insertBackByOuterInnerUnordered(nonzeroCol,iQ) = tval(iQ);
0568         tval(iQ) = Scalar(0.);
0569       }
0570       nonzeroCol++;
0571       if(nonzeroCol<diagSize)
0572         m_Q.startVec(nonzeroCol);
0573     }
0574     else
0575     {
0576       // Zero pivot found: move implicitly this column to the end
0577       for (Index j = nonzeroCol; j < n-1; j++) 
0578         std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
0579       
0580       // Recompute the column elimination tree
0581       internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
0582       m_isEtreeOk = false;
0583     }
0584   }
0585   
0586   m_hcoeffs.tail(diagSize-nonzeroCol).setZero();
0587   
0588   // Finalize the column pointers of the sparse matrices R and Q
0589   m_Q.finalize();
0590   m_Q.makeCompressed();
0591   m_R.finalize();
0592   m_R.makeCompressed();
0593   m_isQSorted = false;
0594 
0595   m_nonzeropivots = nonzeroCol;
0596   
0597   if(nonzeroCol<n)
0598   {
0599     // Permute the triangular factor to put the 'dead' columns to the end
0600     QRMatrixType tempR(m_R);
0601     m_R = tempR * m_pivotperm;
0602     
0603     // Update the column permutation
0604     m_outputPerm_c = m_outputPerm_c * m_pivotperm;
0605   }
0606   
0607   m_isInitialized = true; 
0608   m_factorizationIsok = true;
0609   m_info = Success;
0610 }
0611 
0612 template <typename SparseQRType, typename Derived>
0613 struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived> >
0614 {
0615   typedef typename SparseQRType::QRMatrixType MatrixType;
0616   typedef typename SparseQRType::Scalar Scalar;
0617   // Get the references 
0618   SparseQR_QProduct(const SparseQRType& qr, const Derived& other, bool transpose) : 
0619   m_qr(qr),m_other(other),m_transpose(transpose) {}
0620   inline Index rows() const { return m_qr.matrixQ().rows(); }
0621   inline Index cols() const { return m_other.cols(); }
0622   
0623   // Assign to a vector
0624   template<typename DesType>
0625   void evalTo(DesType& res) const
0626   {
0627     Index m = m_qr.rows();
0628     Index n = m_qr.cols();
0629     Index diagSize = (std::min)(m,n);
0630     res = m_other;
0631     if (m_transpose)
0632     {
0633       eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
0634       //Compute res = Q' * other column by column
0635       for(Index j = 0; j < res.cols(); j++){
0636         for (Index k = 0; k < diagSize; k++)
0637         {
0638           Scalar tau = Scalar(0);
0639           tau = m_qr.m_Q.col(k).dot(res.col(j));
0640           if(tau==Scalar(0)) continue;
0641           tau = tau * m_qr.m_hcoeffs(k);
0642           res.col(j) -= tau * m_qr.m_Q.col(k);
0643         }
0644       }
0645     }
0646     else
0647     {
0648       eigen_assert(m_qr.matrixQ().cols() == m_other.rows() && "Non conforming object sizes");
0649 
0650       res.conservativeResize(rows(), cols());
0651 
0652       // Compute res = Q * other column by column
0653       for(Index j = 0; j < res.cols(); j++)
0654       {
0655         Index start_k = internal::is_identity<Derived>::value ? numext::mini(j,diagSize-1) : diagSize-1;
0656         for (Index k = start_k; k >=0; k--)
0657         {
0658           Scalar tau = Scalar(0);
0659           tau = m_qr.m_Q.col(k).dot(res.col(j));
0660           if(tau==Scalar(0)) continue;
0661           tau = tau * numext::conj(m_qr.m_hcoeffs(k));
0662           res.col(j) -= tau * m_qr.m_Q.col(k);
0663         }
0664       }
0665     }
0666   }
0667   
0668   const SparseQRType& m_qr;
0669   const Derived& m_other;
0670   bool m_transpose; // TODO this actually means adjoint
0671 };
0672 
0673 template<typename SparseQRType>
0674 struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<SparseQRType> >
0675 {  
0676   typedef typename SparseQRType::Scalar Scalar;
0677   typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
0678   enum {
0679     RowsAtCompileTime = Dynamic,
0680     ColsAtCompileTime = Dynamic
0681   };
0682   explicit SparseQRMatrixQReturnType(const SparseQRType& qr) : m_qr(qr) {}
0683   template<typename Derived>
0684   SparseQR_QProduct<SparseQRType, Derived> operator*(const MatrixBase<Derived>& other)
0685   {
0686     return SparseQR_QProduct<SparseQRType,Derived>(m_qr,other.derived(),false);
0687   }
0688   // To use for operations with the adjoint of Q
0689   SparseQRMatrixQTransposeReturnType<SparseQRType> adjoint() const
0690   {
0691     return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
0692   }
0693   inline Index rows() const { return m_qr.rows(); }
0694   inline Index cols() const { return m_qr.rows(); }
0695   // To use for operations with the transpose of Q FIXME this is the same as adjoint at the moment
0696   SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const
0697   {
0698     return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
0699   }
0700   const SparseQRType& m_qr;
0701 };
0702 
0703 // TODO this actually represents the adjoint of Q
0704 template<typename SparseQRType>
0705 struct SparseQRMatrixQTransposeReturnType
0706 {
0707   explicit SparseQRMatrixQTransposeReturnType(const SparseQRType& qr) : m_qr(qr) {}
0708   template<typename Derived>
0709   SparseQR_QProduct<SparseQRType,Derived> operator*(const MatrixBase<Derived>& other)
0710   {
0711     return SparseQR_QProduct<SparseQRType,Derived>(m_qr,other.derived(), true);
0712   }
0713   const SparseQRType& m_qr;
0714 };
0715 
0716 namespace internal {
0717   
0718 template<typename SparseQRType>
0719 struct evaluator_traits<SparseQRMatrixQReturnType<SparseQRType> >
0720 {
0721   typedef typename SparseQRType::MatrixType MatrixType;
0722   typedef typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind Kind;
0723   typedef SparseShape Shape;
0724 };
0725 
0726 template< typename DstXprType, typename SparseQRType>
0727 struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>, internal::assign_op<typename DstXprType::Scalar,typename DstXprType::Scalar>, Sparse2Sparse>
0728 {
0729   typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
0730   typedef typename DstXprType::Scalar Scalar;
0731   typedef typename DstXprType::StorageIndex StorageIndex;
0732   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &/*func*/)
0733   {
0734     typename DstXprType::PlainObject idMat(src.rows(), src.cols());
0735     idMat.setIdentity();
0736     // Sort the sparse householder reflectors if needed
0737     const_cast<SparseQRType *>(&src.m_qr)->_sort_matrix_Q();
0738     dst = SparseQR_QProduct<SparseQRType, DstXprType>(src.m_qr, idMat, false);
0739   }
0740 };
0741 
0742 template< typename DstXprType, typename SparseQRType>
0743 struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>, internal::assign_op<typename DstXprType::Scalar,typename DstXprType::Scalar>, Sparse2Dense>
0744 {
0745   typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
0746   typedef typename DstXprType::Scalar Scalar;
0747   typedef typename DstXprType::StorageIndex StorageIndex;
0748   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &/*func*/)
0749   {
0750     dst = src.m_qr.matrixQ() * DstXprType::Identity(src.m_qr.rows(), src.m_qr.rows());
0751   }
0752 };
0753 
0754 } // end namespace internal
0755 
0756 } // end namespace RivetEigen
0757 
0758 #endif