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