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) {
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());
216 y.topRows(
rank) = this->
matrixR().topLeftCorner(rank,
rank).template triangularView<Upper>().solve(b.topRows(
rank));
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);
366 Index nzcolR, nzcolQ;
368 RealScalar pivotThreshold = m_threshold;
374 m_outputPerm_c = m_perm_c.inverse();
375 internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
387 const StorageIndex* originalOuterIndices = mat.outerIndexPtr();
388 if (MatrixType::IsRowMajor) {
389 originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(), n + 1);
390 originalOuterIndices = originalOuterIndicesCpy.
data();
393 for (
int i = 0; i < n; i++) {
394 Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
395 m_pmat.outerIndexPtr()[p] = originalOuterIndices[i];
396 m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i + 1] - originalOuterIndices[i];
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);
412 m_pivotperm.setIdentity(n);
414 StorageIndex nonzeroCol = 0;
418 for (StorageIndex col = 0; col < n; ++col) {
421 mark(nonzeroCol) = col;
422 Qidx(0) = nonzeroCol;
425 bool found_diag = nonzeroCol >= m;
432 for (
typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp) {
433 StorageIndex curIdx = nonzeroCol;
434 if (itp) curIdx = StorageIndex(itp.row());
435 if (curIdx == nonzeroCol) found_diag =
true;
438 StorageIndex st = m_firstRowElt(curIdx);
440 m_lastError =
"Empty row found during numerical factorization";
447 for (; mark(st) != col; st = m_etree(st)) {
454 Index nt = nzcolR - bi;
455 for (
Index i = 0; i < nt / 2; i++) std::swap(Ridx(bi + i), Ridx(nzcolR - i - 1));
459 tval(curIdx) = itp.value();
461 tval(curIdx) = Scalar(0);
464 if (curIdx > nonzeroCol && mark(curIdx) != col) {
465 Qidx(nzcolQ) = curIdx;
472 for (
Index i = nzcolR - 1; i >= 0; i--) {
473 Index curIdx = Ridx(i);
479 tdot = m_Q.col(curIdx).dot(tval);
481 tdot *= m_hcoeffs(curIdx);
484 tval -= tdot * m_Q.col(curIdx);
487 if (m_etree(Ridx(i)) == nonzeroCol) {
488 for (
typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq) {
489 StorageIndex iQ = StorageIndex(itq.row());
490 if (mark(iQ) != col) {
498 Scalar tau = RealScalar(0);
501 if (nonzeroCol < diagSize) {
504 Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
507 RealScalar sqrNorm = 0.;
508 for (
Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
509 if (sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0)) {
510 beta = numext::real(c0);
514 beta = sqrt(numext::abs2(c0) + sqrNorm);
515 if (numext::real(c0) >= RealScalar(0)) beta = -beta;
517 for (
Index itq = 1; itq < nzcolQ; ++itq) tval(Qidx(itq)) /= (c0 - beta);
518 tau = numext::conj((beta - c0) / beta);
523 for (
Index i = nzcolR - 1; i >= 0; i--) {
524 Index curIdx = Ridx(i);
525 if (curIdx < nonzeroCol) {
526 m_R.insertBackByOuterInnerUnordered(col, curIdx) = tval(curIdx);
527 tval(curIdx) = Scalar(0.);
531 if (nonzeroCol < diagSize && abs(beta) >= pivotThreshold) {
532 m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
534 m_hcoeffs(nonzeroCol) = tau;
536 for (
Index itq = 0; itq < nzcolQ; ++itq) {
537 Index iQ = Qidx(itq);
538 m_Q.insertBackByOuterInnerUnordered(nonzeroCol, iQ) = tval(iQ);
539 tval(iQ) = Scalar(0.);
542 if (nonzeroCol < diagSize) m_Q.startVec(nonzeroCol);
545 for (
Index j = nonzeroCol; j < n - 1; j++) std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j + 1]);
548 internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
553 m_hcoeffs.tail(diagSize - nonzeroCol).setZero();
557 m_Q.makeCompressed();
559 m_R.makeCompressed();
562 m_nonzeropivots = nonzeroCol;
564 if (nonzeroCol < n) {
567 m_R = tempR * m_pivotperm;
570 m_outputPerm_c = m_outputPerm_c * m_pivotperm;
573 m_isInitialized =
true;
574 m_factorizationIsok =
true;
578template <
typename SparseQRType,
typename Derived>
579struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived> > {
580 typedef typename SparseQRType::QRMatrixType MatrixType;
581 typedef typename SparseQRType::Scalar Scalar;
583 SparseQR_QProduct(
const SparseQRType& qr,
const Derived& other,
bool transpose)
584 : m_qr(qr), m_other(other), m_transpose(transpose) {}
585 inline Index rows()
const {
return m_qr.matrixQ().rows(); }
586 inline Index cols()
const {
return m_other.cols(); }
589 template <
typename DesType>
590 void evalTo(DesType& res)
const {
591 Index m = m_qr.rows();
592 Index n = m_qr.cols();
593 Index diagSize = (std::min)(m, n);
596 eigen_assert(m_qr.m_Q.rows() == m_other.rows() &&
"Non conforming object sizes");
598 for (Index j = 0; j < res.cols(); j++) {
599 for (Index k = 0; k < diagSize; k++) {
600 Scalar tau = Scalar(0);
601 tau = m_qr.m_Q.col(k).dot(res.col(j));
602 if (tau == Scalar(0))
continue;
603 tau = tau * m_qr.m_hcoeffs(k);
604 res.col(j) -= tau * m_qr.m_Q.col(k);
608 eigen_assert(m_qr.matrixQ().cols() == m_other.rows() &&
"Non conforming object sizes");
610 res.conservativeResize(rows(), cols());
613 for (Index j = 0; j < res.cols(); j++) {
614 Index start_k = internal::is_identity<Derived>::value ? numext::mini(j, diagSize - 1) : diagSize - 1;
615 for (Index k = start_k; k >= 0; k--) {
616 Scalar tau = Scalar(0);
617 tau = m_qr.m_Q.col(k).dot(res.col(j));
618 if (tau == Scalar(0))
continue;
619 tau = tau * numext::conj(m_qr.m_hcoeffs(k));
620 res.col(j) -= tau * m_qr.m_Q.col(k);
626 const SparseQRType& m_qr;
627 const Derived& m_other;
631template <
typename SparseQRType>
632struct SparseQRMatrixQReturnType :
public EigenBase<SparseQRMatrixQReturnType<SparseQRType> > {
633 typedef typename SparseQRType::Scalar Scalar;
634 typedef Matrix<Scalar, Dynamic, Dynamic> DenseMatrix;
635 enum { RowsAtCompileTime =
Dynamic, ColsAtCompileTime =
Dynamic };
636 explicit SparseQRMatrixQReturnType(
const SparseQRType& qr) : m_qr(qr) {}
637 template <
typename Derived>
638 SparseQR_QProduct<SparseQRType, Derived> operator*(
const MatrixBase<Derived>& other) {
639 return SparseQR_QProduct<SparseQRType, Derived>(m_qr, other.derived(),
false);
642 SparseQRMatrixQTransposeReturnType<SparseQRType> adjoint()
const {
643 return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
645 inline Index rows()
const {
return m_qr.rows(); }
646 inline Index cols()
const {
return m_qr.rows(); }
648 SparseQRMatrixQTransposeReturnType<SparseQRType> transpose()
const {
649 return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
651 const SparseQRType& m_qr;
655template <
typename SparseQRType>
656struct SparseQRMatrixQTransposeReturnType {
657 explicit SparseQRMatrixQTransposeReturnType(
const SparseQRType& qr) : m_qr(qr) {}
658 template <
typename Derived>
659 SparseQR_QProduct<SparseQRType, Derived> operator*(
const MatrixBase<Derived>& other) {
660 return SparseQR_QProduct<SparseQRType, Derived>(m_qr, other.derived(),
true);
662 const SparseQRType& m_qr;
667template <
typename SparseQRType>
668struct evaluator_traits<SparseQRMatrixQReturnType<SparseQRType> > {
669 typedef typename SparseQRType::MatrixType MatrixType;
670 typedef typename storage_kind_to_evaluator_kind<typename MatrixType::StorageKind>::Kind Kind;
671 typedef SparseShape Shape;
674template <
typename DstXprType,
typename SparseQRType>
675struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>,
676 internal::assign_op<typename DstXprType::Scalar, typename DstXprType::Scalar>, Sparse2Sparse> {
677 typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
678 typedef typename DstXprType::Scalar Scalar;
679 typedef typename DstXprType::StorageIndex StorageIndex;
680 static void run(DstXprType& dst,
const SrcXprType& src,
const internal::assign_op<Scalar, Scalar>& ) {
681 typename DstXprType::PlainObject idMat(src.rows(), src.cols());
684 const_cast<SparseQRType*
>(&src.m_qr)->_sort_matrix_Q();
685 dst = SparseQR_QProduct<SparseQRType, DstXprType>(src.m_qr, idMat,
false);
689template <
typename DstXprType,
typename SparseQRType>
690struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>,
691 internal::assign_op<typename DstXprType::Scalar, typename DstXprType::Scalar>, Sparse2Dense> {
692 typedef SparseQRMatrixQReturnType<SparseQRType> SrcXprType;
693 typedef typename DstXprType::Scalar Scalar;
694 typedef typename DstXprType::StorageIndex StorageIndex;
695 static void run(DstXprType& dst,
const SrcXprType& src,
const internal::assign_op<Scalar, Scalar>& ) {
696 dst = src.m_qr.matrixQ() * DstXprType::Identity(src.m_qr.rows(), src.m_qr.rows());
Derived & derived()
Definition EigenBase.h:49
EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT
Definition EigenBase.h:59
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:280
Derived & setConstant(Index size, const Scalar &val)
Definition CwiseNullaryOp.h:360
Derived & setZero(Index size)
Definition CwiseNullaryOp.h:563
const Scalar * data() const
Definition PlainObjectBase.h:273
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
A versatible sparse matrix representation.
Definition SparseUtil.h:47
Index cols() const
Definition SparseMatrix.h:161
Index rows() const
Definition SparseMatrix.h:159
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
A base class for sparse solvers.
Definition SparseSolverBase.h:67
ComputationInfo
Definition Constants.h:438
@ InvalidInput
Definition Constants.h:447
@ Success
Definition Constants.h:440
Namespace containing all symbols from the Eigen library.
Definition Core:137
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition Meta.h:83
const int Dynamic
Definition Constants.h:25
Derived & derived()
Definition EigenBase.h:49
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition Meta.h:523