11#ifndef EIGEN_SPARSE_QR_H
12#define EIGEN_SPARSE_QR_H
15#include "./InternalHeaderCheck.h"
19template <
typename MatrixType,
typename OrderingType>
21template <
typename SparseQRType>
22struct SparseQRMatrixQReturnType;
23template <
typename SparseQRType>
24struct SparseQRMatrixQTransposeReturnType;
25template <
typename SparseQRType,
typename Derived>
26struct SparseQR_QProduct;
28template <
typename SparseQRType>
29struct traits<SparseQRMatrixQReturnType<SparseQRType> > {
30 typedef typename SparseQRType::MatrixType ReturnType;
31 typedef typename ReturnType::StorageIndex StorageIndex;
32 typedef typename ReturnType::StorageKind StorageKind;
35template <
typename SparseQRType>
36struct traits<SparseQRMatrixQTransposeReturnType<SparseQRType> > {
37 typedef typename SparseQRType::MatrixType ReturnType;
39template <
typename SparseQRType,
typename Derived>
40struct traits<SparseQR_QProduct<SparseQRType, Derived> > {
41 typedef typename Derived::PlainObject ReturnType;
87template <
typename MatrixType_,
typename OrderingType_>
91 using Base::m_isInitialized;
94 using Base::_solve_impl;
95 typedef MatrixType_ MatrixType;
96 typedef OrderingType_ OrderingType;
97 typedef typename MatrixType::Scalar Scalar;
98 typedef typename MatrixType::RealScalar RealScalar;
99 typedef typename MatrixType::StorageIndex StorageIndex;
105 enum { ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime };
109 : m_analysisIsok(
false), m_lastError(
""), m_useDefaultThreshold(
true), m_isQSorted(
false), m_isEtreeOk(
false) {}
118 : m_analysisIsok(false), m_lastError(
""), m_useDefaultThreshold(true), m_isQSorted(false), m_isEtreeOk(false) {
156 const QRMatrixType&
matrixR()
const {
return m_R; }
163 eigen_assert(m_isInitialized &&
"The factorization should be called first, use compute()");
164 return m_nonzeropivots;
185 SparseQRMatrixQReturnType<SparseQR>
matrixQ()
const {
return SparseQRMatrixQReturnType<SparseQR>(*
this); }
191 eigen_assert(m_isInitialized &&
"Decomposition is not initialized.");
192 return m_outputPerm_c;
201 template <
typename Rhs,
typename Dest>
203 eigen_assert(m_isInitialized &&
"The factorization should be called first, use compute()");
204 eigen_assert(this->
rows() == B.rows() &&
205 "SparseQR::solve() : invalid number of rows in the right hand side matrix");
210 typename Dest::PlainObject y, b;
211 y = this->
matrixQ().adjoint() * B;
215 y.resize((std::max<Index>)(
cols(), y.rows()), y.cols());
217 y.bottomRows(y.rows() -
rank).setZero();
223 dest = y.topRows(
cols());
235 m_useDefaultThreshold =
false;
236 m_threshold = threshold;
243 template <
typename Rhs>
245 eigen_assert(m_isInitialized &&
"The factorization should be called first, use compute()");
246 eigen_assert(this->
rows() == B.rows() &&
247 "SparseQR::solve() : invalid number of rows in the right hand side matrix");
250 template <
typename Rhs>
252 eigen_assert(m_isInitialized &&
"The factorization should be called first, use compute()");
253 eigen_assert(this->
rows() == B.
rows() &&
254 "SparseQR::solve() : invalid number of rows in the right hand side matrix");
267 eigen_assert(m_isInitialized &&
"Decomposition is not initialized.");
272 inline void _sort_matrix_Q() {
273 if (this->m_isQSorted)
return;
277 this->m_isQSorted =
true;
282 bool m_factorizationIsok;
283 mutable ComputationInfo m_info;
284 std::string m_lastError;
288 ScalarVector m_hcoeffs;
289 PermutationType m_perm_c;
290 PermutationType m_pivotperm;
291 PermutationType m_outputPerm_c;
292 RealScalar m_threshold;
293 bool m_useDefaultThreshold;
294 Index m_nonzeropivots;
296 IndexVector m_firstRowElt;
300 template <
typename,
typename>
301 friend struct SparseQR_QProduct;
313template <
typename MatrixType,
typename OrderingType>
316 mat.isCompressed() &&
317 "SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR");
319 std::conditional_t<MatrixType::IsRowMajor, QRMatrixType, const MatrixType&> matCpy(mat);
322 ord(matCpy, m_perm_c);
323 Index n = mat.cols();
324 Index m = mat.rows();
325 Index diagSize = (std::min)(m, n);
327 if (!m_perm_c.size()) {
329 m_perm_c.indices().setLinSpaced(n, 0, StorageIndex(n - 1));
333 m_outputPerm_c = m_perm_c.inverse();
334 internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
338 m_Q.resize(m, diagSize);
341 m_R.reserve(2 * mat.nonZeros());
343 m_Q.reserve(2 * mat.nonZeros());
344 m_hcoeffs.resize(diagSize);
345 m_analysisIsok =
true;
355template <
typename MatrixType,
typename OrderingType>
359 eigen_assert(m_analysisIsok &&
"analyzePattern() should be called before this step");
360 StorageIndex m = StorageIndex(mat.rows());
361 StorageIndex n = StorageIndex(mat.cols());
362 StorageIndex diagSize = (std::min)(m, n);
363 IndexVector mark((std::max)(m, n));
365 IndexVector Ridx(n), Qidx(m);
366 Index nzcolR, nzcolQ;
367 ScalarVector tval(m);
373 m_outputPerm_c = m_perm_c.inverse();
374 internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
385 IndexVector originalOuterIndicesCpy;
386 const StorageIndex* originalOuterIndices = mat.outerIndexPtr();
387 if (MatrixType::IsRowMajor) {
388 originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(), n + 1);
389 originalOuterIndices = originalOuterIndicesCpy.
data();
392 for (
int i = 0; i < n; i++) {
393 Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
394 m_pmat.outerIndexPtr()[p] = originalOuterIndices[i];
395 m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i + 1] - originalOuterIndices[i];
403 RealScalar pivotThreshold;
404 if (m_useDefaultThreshold) {
405 RealScalar max2Norm = 0.0;
406 for (
int j = 0; j < n; j++) max2Norm = numext::maxi(max2Norm, m_pmat.col(j).norm());
407 if (max2Norm == RealScalar(0)) max2Norm = RealScalar(1);
408 pivotThreshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
410 pivotThreshold = m_threshold;
414 m_pivotperm.setIdentity(n);
416 StorageIndex nonzeroCol = 0;
420 for (StorageIndex col = 0; col < n; ++col) {
423 mark(nonzeroCol) = col;
424 Qidx(0) = nonzeroCol;
427 bool found_diag = nonzeroCol >= m;
434 for (
typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp) {
435 StorageIndex curIdx = nonzeroCol;
436 if (itp) curIdx = StorageIndex(itp.row());
437 if (curIdx == nonzeroCol) found_diag =
true;
440 StorageIndex st = m_firstRowElt(curIdx);
442 m_lastError =
"Empty row found during numerical factorization";
449 for (; mark(st) != col; st = m_etree(st)) {
456 Index nt = nzcolR - bi;
457 for (
Index i = 0; i < nt / 2; i++) std::swap(Ridx(bi + i), Ridx(nzcolR - i - 1));
461 tval(curIdx) = itp.value();
463 tval(curIdx) = Scalar(0);
466 if (curIdx > nonzeroCol && mark(curIdx) != col) {
467 Qidx(nzcolQ) = curIdx;
474 for (
Index i = nzcolR - 1; i >= 0; i--) {
475 Index curIdx = Ridx(i);
481 tdot = m_Q.col(curIdx).dot(tval);
483 tdot *= m_hcoeffs(curIdx);
486 tval -= tdot * m_Q.col(curIdx);
489 if (m_etree(Ridx(i)) == nonzeroCol) {
490 for (
typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq) {
491 StorageIndex iQ = StorageIndex(itq.row());
492 if (mark(iQ) != col) {
500 Scalar tau = RealScalar(0);
503 if (nonzeroCol < diagSize) {
506 Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
509 RealScalar sqrNorm = 0.;
510 for (
Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
511 if (sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0)) {
512 beta = numext::real(c0);
516 beta =
sqrt(numext::abs2(c0) + sqrNorm);
517 if (numext::real(c0) >= RealScalar(0)) beta = -beta;
519 for (
Index itq = 1; itq < nzcolQ; ++itq) tval(Qidx(itq)) /= (c0 - beta);
520 tau = numext::conj((beta - c0) / beta);
525 for (
Index i = nzcolR - 1; i >= 0; i--) {
526 Index curIdx = Ridx(i);
527 if (curIdx < nonzeroCol) {
528 m_R.insertBackByOuterInnerUnordered(col, curIdx) = tval(curIdx);
529 tval(curIdx) = Scalar(0.);
533 if (nonzeroCol < diagSize &&
abs(beta) >= pivotThreshold) {
534 m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
536 m_hcoeffs(nonzeroCol) = tau;
538 for (
Index itq = 0; itq < nzcolQ; ++itq) {
539 Index iQ = Qidx(itq);
540 m_Q.insertBackByOuterInnerUnordered(nonzeroCol, iQ) = tval(iQ);
541 tval(iQ) = Scalar(0.);
544 if (nonzeroCol < diagSize) m_Q.startVec(nonzeroCol);
547 for (
Index j = nonzeroCol; j < n - 1; j++) std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j + 1]);
550 internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
555 m_hcoeffs.tail(diagSize - nonzeroCol).setZero();
559 m_Q.makeCompressed();
561 m_R.makeCompressed();
564 m_nonzeropivots = nonzeroCol;
566 if (nonzeroCol < n) {
568 QRMatrixType tempR(m_R);
569 m_R = tempR * m_pivotperm;
572 m_outputPerm_c = m_outputPerm_c * m_pivotperm;
575 m_isInitialized =
true;
576 m_factorizationIsok =
true;
580template <
typename SparseQRType,
typename Derived>
581struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived> > {
582 typedef typename SparseQRType::QRMatrixType
MatrixType;
583 typedef typename SparseQRType::Scalar
Scalar;
585 SparseQR_QProduct(
const SparseQRType& qr,
const Derived& other,
bool transpose)
586 : m_qr(qr), m_other(other), m_transpose(transpose) {}
587 inline Index rows()
const {
return m_qr.matrixQ().rows(); }
588 inline Index cols()
const {
return m_other.cols(); }
591 template <
typename DesType>
592 void evalTo(DesType& res)
const {
593 Index m = m_qr.rows();
594 Index n = m_qr.cols();
595 Index diagSize = (std::min)(m, n);
598 eigen_assert(m_qr.m_Q.rows() == m_other.rows() &&
"Non conforming object sizes");
600 for (
Index j = 0; j < res.cols(); j++) {
601 for (
Index k = 0; k < diagSize; k++) {
602 Scalar tau = Scalar(0);
603 tau = m_qr.m_Q.col(k).dot(res.col(j));
604 if (tau == Scalar(0))
continue;
605 tau = tau * m_qr.m_hcoeffs(k);
606 res.col(j) -= tau * m_qr.m_Q.col(k);
610 eigen_assert(m_qr.matrixQ().cols() == m_other.rows() &&
"Non conforming object sizes");
612 res.conservativeResize(rows(), cols());
615 for (
Index j = 0; j < res.cols(); j++) {
616 Index start_k = internal::is_identity<Derived>::value ? numext::mini(j, diagSize - 1) : diagSize - 1;
617 for (
Index k = start_k; k >= 0; k--) {
618 Scalar tau = Scalar(0);
619 tau = m_qr.m_Q.col(k).dot(res.col(j));
620 if (tau == Scalar(0))
continue;
621 tau = tau * numext::conj(m_qr.m_hcoeffs(k));
622 res.col(j) -= tau * m_qr.m_Q.col(k);
628 const SparseQRType& m_qr;
629 const Derived& m_other;
633template <
typename SparseQRType>
634struct SparseQRMatrixQReturnType :
public EigenBase<SparseQRMatrixQReturnType<SparseQRType> > {
635 typedef typename SparseQRType::Scalar Scalar;
636 typedef Matrix<Scalar, Dynamic, Dynamic> DenseMatrix;
637 enum { RowsAtCompileTime =
Dynamic, ColsAtCompileTime =
Dynamic };
638 explicit SparseQRMatrixQReturnType(
const SparseQRType& qr) : m_qr(qr) {}
639 template <
typename Derived>
640 SparseQR_QProduct<SparseQRType, Derived> operator*(
const MatrixBase<Derived>& other) {
641 return SparseQR_QProduct<SparseQRType, Derived>(m_qr, other.derived(),
false);
644 SparseQRMatrixQTransposeReturnType<SparseQRType> adjoint()
const {
645 return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
647 inline Index rows()
const {
return m_qr.rows(); }
648 inline Index cols()
const {
return m_qr.rows(); }
650 SparseQRMatrixQTransposeReturnType<SparseQRType> transpose()
const {
651 return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
653 const SparseQRType& m_qr;
657template <
typename SparseQRType>
658struct SparseQRMatrixQTransposeReturnType {
659 explicit SparseQRMatrixQTransposeReturnType(
const SparseQRType& qr) : m_qr(qr) {}
660 template <
typename Derived>
661 SparseQR_QProduct<SparseQRType, Derived> operator*(
const MatrixBase<Derived>& other) {
662 return SparseQR_QProduct<SparseQRType, Derived>(m_qr, other.derived(),
true);
664 const SparseQRType& m_qr;
669template <
typename SparseQRType>
670struct evaluator_traits<SparseQRMatrixQReturnType<SparseQRType> > {
671 typedef typename SparseQRType::MatrixType MatrixType;
672 typedef typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind Kind;
673 typedef SparseShape Shape;
676template <
typename DstXprType,
typename SparseQRType>
677struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>,
678 internal::assign_op<typename DstXprType::Scalar, typename DstXprType::Scalar>, Sparse2Sparse> {
679 typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
680 typedef typename DstXprType::Scalar Scalar;
681 typedef typename DstXprType::StorageIndex StorageIndex;
682 static void run(DstXprType& dst,
const SrcXprType& src,
const internal::assign_op<Scalar, Scalar>& ) {
683 typename DstXprType::PlainObject idMat(src.rows(), src.cols());
686 const_cast<SparseQRType*
>(&src.m_qr)->_sort_matrix_Q();
687 dst = SparseQR_QProduct<SparseQRType, DstXprType>(src.m_qr, idMat,
false);
691template <
typename DstXprType,
typename SparseQRType>
692struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>,
693 internal::assign_op<typename DstXprType::Scalar, typename DstXprType::Scalar>, Sparse2Dense> {
694 typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
695 typedef typename DstXprType::Scalar Scalar;
696 typedef typename DstXprType::StorageIndex StorageIndex;
697 static void run(DstXprType& dst,
const SrcXprType& src,
const internal::assign_op<Scalar, Scalar>& ) {
698 dst = src.m_qr.matrixQ() * DstXprType::Identity(src.m_qr.rows(), src.m_qr.rows());
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:52
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:186
Index size() const
Definition PermutationMatrix.h:96
Permutation matrix.
Definition PermutationMatrix.h:283
Derived & setConstant(Index size, const Scalar &val)
Definition CwiseNullaryOp.h:363
constexpr const Scalar * data() const
Definition PlainObjectBase.h:247
Derived & setZero(Index size)
Definition CwiseNullaryOp.h:567
Pseudo expression representing a solving operation.
Definition Solve.h:62
Base class of any sparse matrices or sparse expressions.
Definition SparseMatrixBase.h:30
Index rows() const
Definition SparseMatrixBase.h:182
FixedBlockXpr<...,... >::Type topLeftCorner(NRowsType cRows, NColsType cCols)
Definition SparseMatrixBase.h:285
A versatible sparse matrix representation.
Definition SparseMatrix.h:121
Sparse left-looking QR factorization with numerical column pivoting.
Definition SparseQR.h:88
const PermutationType & colsPermutation() const
Definition SparseQR.h:190
void setPivotThreshold(const RealScalar &threshold)
Definition SparseQR.h:234
void analyzePattern(const MatrixType &mat)
Preprocessing step of a QR factorization.
Definition SparseQR.h:314
void factorize(const MatrixType &mat)
Performs the numerical QR factorization of the input matrix.
Definition SparseQR.h:356
SparseQR(const MatrixType &mat)
Definition SparseQR.h:117
Index cols() const
Definition SparseQR.h:141
const QRMatrixType & matrixR() const
Definition SparseQR.h:156
SparseQRMatrixQReturnType< SparseQR > matrixQ() const
Definition SparseQR.h:185
const Solve< SparseQR, Rhs > solve(const MatrixBase< Rhs > &B) const
Definition SparseQR.h:244
Index rows() const
Definition SparseQR.h:137
std::string lastErrorMessage() const
Definition SparseQR.h:198
void compute(const MatrixType &mat)
Definition SparseQR.h:128
ComputationInfo info() const
Reports whether previous computation was successful.
Definition SparseQR.h:266
Index rank() const
Definition SparseQR.h:162
SparseSolverBase()
Definition SparseSolverBase.h:70
ComputationInfo
Definition Constants.h:438
@ InvalidInput
Definition Constants.h:447
@ Success
Definition Constants.h:440
Namespace containing all symbols from the Eigen library.
Definition B01_Experimental.dox:1
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition Meta.h:82
const int Dynamic
Definition Constants.h:25
Definition EigenBase.h:33
constexpr Derived & derived()
Definition EigenBase.h:49
Eigen::Index Index
Definition EigenBase.h:43