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