11 #ifndef EIGEN_SPARSE_QR_H
12 #define EIGEN_SPARSE_QR_H
16 template<
typename MatrixType,
typename OrderingType>
class SparseQR;
17 template<
typename SparseQRType>
struct SparseQRMatrixQReturnType;
18 template<
typename SparseQRType>
struct SparseQRMatrixQTransposeReturnType;
19 template<
typename SparseQRType,
typename Derived>
struct SparseQR_QProduct;
23 typedef typename SparseQRType::MatrixType ReturnType;
24 typedef typename ReturnType::StorageIndex StorageIndex;
25 typedef typename ReturnType::StorageKind StorageKind;
33 typedef typename SparseQRType::MatrixType ReturnType;
37 typedef typename Derived::PlainObject ReturnType;
83 template<
typename _MatrixType,
typename _OrderingType>
88 using Base::m_isInitialized;
90 using Base::_solve_impl;
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;
102 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
103 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
107 SparseQR () : m_analysisIsok(
false), m_lastError(
""), m_useDefaultThreshold(
true),m_isQSorted(
false),m_isEtreeOk(
false)
116 explicit SparseQR(
const MatrixType& mat) : m_analysisIsok(false), m_lastError(
""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
164 eigen_assert(m_isInitialized &&
"The factorization should be called first, use compute()");
165 return m_nonzeropivots;
194 eigen_assert(m_isInitialized &&
"Decomposition is not initialized.");
195 return m_outputPerm_c;
204 template<
typename Rhs,
typename Dest>
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");
213 typename Dest::PlainObject y, b;
214 y = this->
matrixQ().adjoint() * B;
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();
224 else dest = y.topRows(
cols());
237 m_useDefaultThreshold =
false;
238 m_threshold = threshold;
245 template<
typename Rhs>
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");
252 template<
typename Rhs>
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");
270 eigen_assert(m_isInitialized &&
"Decomposition is not initialized.");
276 inline void _sort_matrix_Q()
278 if(this->m_isQSorted)
return;
282 this->m_isQSorted =
true;
288 bool m_factorizationIsok;
290 std::string m_lastError;
294 ScalarVector m_hcoeffs;
295 PermutationType m_perm_c;
296 PermutationType m_pivotperm;
297 PermutationType m_outputPerm_c;
298 RealScalar m_threshold;
299 bool m_useDefaultThreshold;
300 Index m_nonzeropivots;
302 IndexVector m_firstRowElt;
306 template <
typename,
typename >
friend struct SparseQR_QProduct;
319 template <
typename MatrixType,
typename OrderingType>
322 eigen_assert(mat.isCompressed() &&
"SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR");
327 ord(matCpy, m_perm_c);
328 Index n = mat.cols();
329 Index m = mat.rows();
330 Index diagSize = (std::min)(m,n);
332 if (!m_perm_c.size())
335 m_perm_c.indices().setLinSpaced(n, 0,StorageIndex(n-1));
339 m_outputPerm_c = m_perm_c.inverse();
340 internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
344 m_Q.resize(m, diagSize);
347 m_R.reserve(2*mat.nonZeros());
348 m_Q.reserve(2*mat.nonZeros());
349 m_hcoeffs.resize(diagSize);
350 m_analysisIsok =
true;
360 template <
typename MatrixType,
typename OrderingType>
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);
371 Index nzcolR, nzcolQ;
373 RealScalar pivotThreshold = m_threshold;
380 m_outputPerm_c = m_perm_c.inverse();
381 internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
393 const StorageIndex *originalOuterIndices = mat.outerIndexPtr();
394 if(MatrixType::IsRowMajor)
396 originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(),n+1);
397 originalOuterIndices = originalOuterIndicesCpy.
data();
400 for (
int i = 0; i < n; i++)
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];
412 if(m_useDefaultThreshold)
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);
422 m_pivotperm.setIdentity(n);
424 StorageIndex nonzeroCol = 0;
428 for (StorageIndex col = 0; col < n; ++col)
432 mark(nonzeroCol) = col;
433 Qidx(0) = nonzeroCol;
434 nzcolR = 0; nzcolQ = 1;
435 bool found_diag = nonzeroCol>=m;
442 for (
typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
444 StorageIndex curIdx = nonzeroCol;
445 if(itp) curIdx = StorageIndex(itp.row());
446 if(curIdx == nonzeroCol) found_diag =
true;
449 StorageIndex st = m_firstRowElt(curIdx);
452 m_lastError =
"Empty row found during numerical factorization";
459 for (; mark(st) != col; st = m_etree(st))
467 Index nt = nzcolR-bi;
468 for(
Index i = 0; i < nt/2; i++) std::swap(Ridx(bi+i), Ridx(nzcolR-i-1));
471 if(itp) tval(curIdx) = itp.value();
472 else tval(curIdx) = Scalar(0);
475 if(curIdx > nonzeroCol && mark(curIdx) != col )
477 Qidx(nzcolQ) = curIdx;
484 for (
Index i = nzcolR-1; i >= 0; i--)
486 Index curIdx = Ridx(i);
492 tdot = m_Q.col(curIdx).dot(tval);
494 tdot *= m_hcoeffs(curIdx);
498 for (
typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
499 tval(itq.row()) -= itq.value() * tdot;
502 if(m_etree(Ridx(i)) == nonzeroCol)
504 for (
typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
506 StorageIndex iQ = StorageIndex(itq.row());
516 Scalar tau = RealScalar(0);
519 if(nonzeroCol < diagSize)
523 Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
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))
530 beta = numext::real(c0);
536 beta = sqrt(numext::abs2(c0) + sqrNorm);
537 if(numext::real(c0) >= RealScalar(0))
540 for (
Index itq = 1; itq < nzcolQ; ++itq)
541 tval(Qidx(itq)) /= (c0 - beta);
542 tau = numext::conj((beta-c0) / beta);
548 for (
Index i = nzcolR-1; i >= 0; i--)
550 Index curIdx = Ridx(i);
551 if(curIdx < nonzeroCol)
553 m_R.insertBackByOuterInnerUnordered(col, curIdx) = tval(curIdx);
554 tval(curIdx) = Scalar(0.);
558 if(nonzeroCol < diagSize && abs(beta) >= pivotThreshold)
560 m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
562 m_hcoeffs(nonzeroCol) = tau;
564 for (
Index itq = 0; itq < nzcolQ; ++itq)
566 Index iQ = Qidx(itq);
567 m_Q.insertBackByOuterInnerUnordered(nonzeroCol,iQ) = tval(iQ);
568 tval(iQ) = Scalar(0.);
571 if(nonzeroCol<diagSize)
572 m_Q.startVec(nonzeroCol);
577 for (
Index j = nonzeroCol; j < n-1; j++)
578 std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
581 internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
586 m_hcoeffs.tail(diagSize-nonzeroCol).setZero();
590 m_Q.makeCompressed();
592 m_R.makeCompressed();
595 m_nonzeropivots = nonzeroCol;
601 m_R = tempR * m_pivotperm;
604 m_outputPerm_c = m_outputPerm_c * m_pivotperm;
607 m_isInitialized =
true;
608 m_factorizationIsok =
true;
612 template <
typename SparseQRType,
typename Derived>
615 typedef typename SparseQRType::QRMatrixType MatrixType;
616 typedef typename SparseQRType::Scalar Scalar;
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(); }
624 template<
typename DesType>
625 void evalTo(DesType& res)
const
627 Index m = m_qr.rows();
628 Index n = m_qr.cols();
629 Index diagSize = (std::min)(m,n);
633 eigen_assert(m_qr.m_Q.rows() == m_other.rows() &&
"Non conforming object sizes");
635 for(
Index j = 0; j < res.cols(); j++){
636 for (
Index k = 0; k < diagSize; k++)
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);
648 eigen_assert(m_qr.matrixQ().cols() == m_other.rows() &&
"Non conforming object sizes");
650 res.conservativeResize(rows(), cols());
653 for(
Index j = 0; j < res.cols(); j++)
656 for (
Index k = start_k; k >=0; k--)
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);
668 const SparseQRType& m_qr;
669 const Derived& m_other;
673 template<
typename SparseQRType>
676 typedef typename SparseQRType::Scalar Scalar;
683 template<
typename Derived>
693 inline Index rows()
const {
return m_qr.rows(); }
694 inline Index cols()
const {
return m_qr.rows(); }
700 const SparseQRType& m_qr;
704 template<
typename SparseQRType>
708 template<
typename Derived>
713 const SparseQRType& m_qr;
718 template<
typename SparseQRType>
721 typedef typename SparseQRType::MatrixType MatrixType;
726 template<
typename DstXprType,
typename SparseQRType>
730 typedef typename DstXprType::Scalar Scalar;
731 typedef typename DstXprType::StorageIndex StorageIndex;
734 typename DstXprType::PlainObject idMat(src.rows(), src.cols());
737 const_cast<SparseQRType *
>(&src.m_qr)->_sort_matrix_Q();
742 template<
typename DstXprType,
typename SparseQRType>
746 typedef typename DstXprType::Scalar Scalar;
747 typedef typename DstXprType::StorageIndex StorageIndex;
750 dst = src.m_qr.matrixQ() * DstXprType::Identity(src.m_qr.rows(), src.m_qr.rows());