Shapeworks Studio  2.1
Shape analysis software suite
List of all members | Public Types | Public Member Functions | Protected Member Functions | Protected Attributes | Friends
Eigen::SparseQR< _MatrixType, _OrderingType > Class Template Reference

Sparse left-looking rank-revealing QR factorization. More...

#include <SparseQR.h>

+ Collaboration diagram for Eigen::SparseQR< _MatrixType, _OrderingType >:

Public Types

typedef _MatrixType MatrixType
 
typedef _OrderingType OrderingType
 
typedef MatrixType::Scalar Scalar
 
typedef MatrixType::RealScalar RealScalar
 
typedef MatrixType::Index Index
 
typedef SparseMatrix< Scalar, ColMajor, Index > QRMatrixType
 
typedef Matrix< Index, Dynamic, 1 > IndexVector
 
typedef Matrix< Scalar, Dynamic, 1 > ScalarVector
 
typedef PermutationMatrix< Dynamic, Dynamic, Index > PermutationType
 

Public Member Functions

 SparseQR (const MatrixType &mat)
 
void compute (const MatrixType &mat)
 
void analyzePattern (const MatrixType &mat)
 Preprocessing step of a QR factorization. More...
 
void factorize (const MatrixType &mat)
 Performs the numerical QR factorization of the input matrix. More...
 
Index rows () const
 
Index cols () const
 
const QRMatrixTypematrixR () const
 
Index rank () const
 
SparseQRMatrixQReturnType< SparseQRmatrixQ () const
 
const PermutationTypecolsPermutation () const
 
std::string lastErrorMessage () const
 
template<typename Rhs , typename Dest >
bool _solve (const MatrixBase< Rhs > &B, MatrixBase< Dest > &dest) const
 
void setPivotThreshold (const RealScalar &threshold)
 
template<typename Rhs >
const internal::solve_retval< SparseQR, Rhs > solve (const MatrixBase< Rhs > &B) const
 
template<typename Rhs >
const internal::sparse_solve_retval< SparseQR, Rhs > solve (const SparseMatrixBase< Rhs > &B) const
 
ComputationInfo info () const
 Reports whether previous computation was successful. More...
 

Protected Member Functions

void sort_matrix_Q ()
 

Protected Attributes

bool m_isInitialized
 
bool m_analysisIsok
 
bool m_factorizationIsok
 
ComputationInfo m_info
 
std::string m_lastError
 
QRMatrixType m_pmat
 
QRMatrixType m_R
 
QRMatrixType m_Q
 
ScalarVector m_hcoeffs
 
PermutationType m_perm_c
 
PermutationType m_pivotperm
 
PermutationType m_outputPerm_c
 
RealScalar m_threshold
 
bool m_useDefaultThreshold
 
Index m_nonzeropivots
 
IndexVector m_etree
 
IndexVector m_firstRowElt
 
bool m_isQSorted
 

Friends

template<typename , typename >
struct SparseQR_QProduct
 
template<typename >
struct SparseQRMatrixQReturnType
 

Detailed Description

template<typename _MatrixType, typename _OrderingType>
class Eigen::SparseQR< _MatrixType, _OrderingType >

Sparse left-looking rank-revealing QR factorization.

This class implements a left-looking rank-revealing QR decomposition of sparse matrices. When a column has a norm less than a given tolerance it is implicitly permuted to the end. The QR factorization thus obtained is given by A*P = Q*R where R is upper triangular or trapezoidal.

P is the column permutation which is the product of the fill-reducing and the rank-revealing permutations. Use colsPermutation() to get it.

Q is the orthogonal matrix represented as products of Householder reflectors. Use matrixQ() to get an expression and matrixQ().transpose() to get the transpose. You can then apply it to a vector.

R is the sparse triangular or trapezoidal matrix. The later occurs when A is rank-deficient. matrixR().topLeftCorner(rank(), rank()) always returns a triangular factor of full rank.

Template Parameters
_MatrixTypeThe type of the sparse matrix A, must be a column-major SparseMatrix<>
_OrderingTypeThe fill-reducing ordering method. See the OrderingMethods module for the list of built-in and external ordering methods.

Definition at line 16 of file SparseQR.h.

Member Function Documentation

template<typename MatrixType , typename OrderingType >
void Eigen::SparseQR< MatrixType, OrderingType >::analyzePattern ( const MatrixType &  mat)

Preprocessing step of a QR factorization.

In this step, the fill-reducing permutation is computed and applied to the columns of A and the column elimination tree is computed as well. Only the sparcity pattern of mat is exploited.

Note
In this step it is assumed that there is no empty row in the matrix mat.

Definition at line 264 of file SparseQR.h.

265 {
266  // Compute the column fill reducing ordering
267  OrderingType ord;
268  ord(mat, m_perm_c);
269  Index n = mat.cols();
270  Index m = mat.rows();
271 
272  if (!m_perm_c.size())
273  {
274  m_perm_c.resize(n);
275  m_perm_c.indices().setLinSpaced(n, 0,n-1);
276  }
277 
278  // Compute the column elimination tree of the permuted matrix
279  m_outputPerm_c = m_perm_c.inverse();
280  internal::coletree(mat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
281 
282  m_R.resize(n, n);
283  m_Q.resize(m, n);
284 
285  // Allocate space for nonzero elements : rough estimation
286  m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree
287  m_Q.reserve(2*mat.nonZeros());
288  m_hcoeffs.resize(n);
289  m_analysisIsok = true;
290 }
void resize(Index newSize)
EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols)
void reserve(Index reserveSize)
Definition: SparseMatrix.h:256
const IndicesType & indices() const
Transpose< PermutationBase > inverse() const
void resize(Index rows, Index cols)
Definition: SparseMatrix.h:596
int coletree(const MatrixType &mat, IndexVector &parent, IndexVector &firstRowElt, typename MatrixType::Index *perm=0)
template<typename _MatrixType , typename _OrderingType >
Index Eigen::SparseQR< _MatrixType, _OrderingType >::cols ( void  ) const
inline
Returns
the number of columns of the represented matrix.

Definition at line 98 of file SparseQR.h.

98 { return m_pmat.cols();}
Index cols() const
Definition: SparseMatrix.h:121
template<typename _MatrixType , typename _OrderingType >
const PermutationType& Eigen::SparseQR< _MatrixType, _OrderingType >::colsPermutation ( ) const
inline
Returns
a const reference to the column permutation P that was applied to A such that A*P = Q*R It is the combination of the fill-in reducing permutation and numerical column pivoting.

Definition at line 138 of file SparseQR.h.

139  {
140  eigen_assert(m_isInitialized && "Decomposition is not initialized.");
141  return m_outputPerm_c;
142  }
template<typename MatrixType , typename OrderingType >
void Eigen::SparseQR< MatrixType, OrderingType >::factorize ( const MatrixType &  mat)

Performs the numerical QR factorization of the input matrix.

The function SparseQR::analyzePattern(const MatrixType&) must have been called beforehand with a matrix having the same sparcity pattern than mat.

Parameters
matThe sparse column-major matrix

Definition at line 300 of file SparseQR.h.

301 {
302  using std::abs;
303  using std::max;
304 
305  eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step");
306  Index m = mat.rows();
307  Index n = mat.cols();
308  IndexVector mark(m); mark.setConstant(-1); // Record the visited nodes
309  IndexVector Ridx(n), Qidx(m); // Store temporarily the row indexes for the current column of R and Q
310  Index nzcolR, nzcolQ; // Number of nonzero for the current column of R and Q
311  ScalarVector tval(m); // The dense vector used to compute the current column
312  bool found_diag;
313 
314  m_pmat = mat;
315  m_pmat.uncompress(); // To have the innerNonZeroPtr allocated
316  // Apply the fill-in reducing permutation lazily:
317  for (int i = 0; i < n; i++)
318  {
319  Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
320  m_pmat.outerIndexPtr()[p] = mat.outerIndexPtr()[i];
321  m_pmat.innerNonZeroPtr()[p] = mat.outerIndexPtr()[i+1] - mat.outerIndexPtr()[i];
322  }
323 
324  /* Compute the default threshold, see :
325  * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
326  * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3
327  */
328  if(m_useDefaultThreshold)
329  {
330  RealScalar max2Norm = 0.0;
331  for (int j = 0; j < n; j++) max2Norm = (max)(max2Norm, m_pmat.col(j).norm());
332  m_threshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
333  }
334 
335  // Initialize the numerical permutation
336  m_pivotperm.setIdentity(n);
337 
338  Index nonzeroCol = 0; // Record the number of valid pivots
339 
340  // Left looking rank-revealing QR factorization: compute a column of R and Q at a time
341  for (Index col = 0; col < n; ++col)
342  {
343  mark.setConstant(-1);
344  m_R.startVec(col);
345  m_Q.startVec(col);
346  mark(nonzeroCol) = col;
347  Qidx(0) = nonzeroCol;
348  nzcolR = 0; nzcolQ = 1;
349  found_diag = false;
350  tval.setZero();
351 
352  // Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e.,
353  // all the nodes (with indexes lower than rank) reachable through the column elimination tree (etree) rooted at node k.
354  // Note: if the diagonal entry does not exist, then its contribution must be explicitly added,
355  // thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found.
356  for (typename MatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
357  {
358  Index curIdx = nonzeroCol ;
359  if(itp) curIdx = itp.row();
360  if(curIdx == nonzeroCol) found_diag = true;
361 
362  // Get the nonzeros indexes of the current column of R
363  Index st = m_firstRowElt(curIdx); // The traversal of the etree starts here
364  if (st < 0 )
365  {
366  m_lastError = "Empty row found during numerical factorization";
367  m_info = InvalidInput;
368  return;
369  }
370 
371  // Traverse the etree
372  Index bi = nzcolR;
373  for (; mark(st) != col; st = m_etree(st))
374  {
375  Ridx(nzcolR) = st; // Add this row to the list,
376  mark(st) = col; // and mark this row as visited
377  nzcolR++;
378  }
379 
380  // Reverse the list to get the topological ordering
381  Index nt = nzcolR-bi;
382  for(Index i = 0; i < nt/2; i++) std::swap(Ridx(bi+i), Ridx(nzcolR-i-1));
383 
384  // Copy the current (curIdx,pcol) value of the input matrix
385  if(itp) tval(curIdx) = itp.value();
386  else tval(curIdx) = Scalar(0);
387 
388  // Compute the pattern of Q(:,k)
389  if(curIdx > nonzeroCol && mark(curIdx) != col )
390  {
391  Qidx(nzcolQ) = curIdx; // Add this row to the pattern of Q,
392  mark(curIdx) = col; // and mark it as visited
393  nzcolQ++;
394  }
395  }
396 
397  // Browse all the indexes of R(:,col) in reverse order
398  for (Index i = nzcolR-1; i >= 0; i--)
399  {
400  Index curIdx = m_pivotperm.indices()(Ridx(i));
401 
402  // Apply the curIdx-th householder vector to the current column (temporarily stored into tval)
403  Scalar tdot(0);
404 
405  // First compute q' * tval
406  tdot = m_Q.col(curIdx).dot(tval);
407 
408  tdot *= m_hcoeffs(curIdx);
409 
410  // Then update tval = tval - q * tau
411  // FIXME: tval -= tdot * m_Q.col(curIdx) should amount to the same (need to check/add support for efficient "dense ?= sparse")
412  for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
413  tval(itq.row()) -= itq.value() * tdot;
414 
415  // Detect fill-in for the current column of Q
416  if(m_etree(Ridx(i)) == nonzeroCol)
417  {
418  for (typename QRMatrixType::InnerIterator itq(m_Q, curIdx); itq; ++itq)
419  {
420  Index iQ = itq.row();
421  if (mark(iQ) != col)
422  {
423  Qidx(nzcolQ++) = iQ; // Add this row to the pattern of Q,
424  mark(iQ) = col; // and mark it as visited
425  }
426  }
427  }
428  } // End update current column
429 
430  // Compute the Householder reflection that eliminate the current column
431  // FIXME this step should call the Householder module.
432  Scalar tau;
433  RealScalar beta;
434  Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
435 
436  // First, the squared norm of Q((col+1):m, col)
437  RealScalar sqrNorm = 0.;
438  for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
439 
440  if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
441  {
442  tau = RealScalar(0);
443  beta = numext::real(c0);
444  tval(Qidx(0)) = 1;
445  }
446  else
447  {
448  beta = std::sqrt(numext::abs2(c0) + sqrNorm);
449  if(numext::real(c0) >= RealScalar(0))
450  beta = -beta;
451  tval(Qidx(0)) = 1;
452  for (Index itq = 1; itq < nzcolQ; ++itq)
453  tval(Qidx(itq)) /= (c0 - beta);
454  tau = numext::conj((beta-c0) / beta);
455 
456  }
457 
458  // Insert values in R
459  for (Index i = nzcolR-1; i >= 0; i--)
460  {
461  Index curIdx = Ridx(i);
462  if(curIdx < nonzeroCol)
463  {
464  m_R.insertBackByOuterInnerUnordered(col, curIdx) = tval(curIdx);
465  tval(curIdx) = Scalar(0.);
466  }
467  }
468 
469  if(abs(beta) >= m_threshold)
470  {
471  m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
472  nonzeroCol++;
473  // The householder coefficient
474  m_hcoeffs(col) = tau;
475  // Record the householder reflections
476  for (Index itq = 0; itq < nzcolQ; ++itq)
477  {
478  Index iQ = Qidx(itq);
479  m_Q.insertBackByOuterInnerUnordered(col,iQ) = tval(iQ);
480  tval(iQ) = Scalar(0.);
481  }
482  }
483  else
484  {
485  // Zero pivot found: move implicitly this column to the end
486  m_hcoeffs(col) = Scalar(0);
487  for (Index j = nonzeroCol; j < n-1; j++)
488  std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
489 
490  // Recompute the column elimination tree
491  internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
492  }
493  }
494 
495  // Finalize the column pointers of the sparse matrices R and Q
496  m_Q.finalize();
497  m_Q.makeCompressed();
498  m_R.finalize();
499  m_R.makeCompressed();
500  m_isQSorted = false;
501 
502  m_nonzeropivots = nonzeroCol;
503 
504  if(nonzeroCol<n)
505  {
506  // Permute the triangular factor to put the 'dead' columns to the end
507  MatrixType tempR(m_R);
508  m_R = tempR * m_pivotperm;
509 
510  // Update the column permutation
511  m_outputPerm_c = m_outputPerm_c * m_pivotperm;
512  }
513 
514  m_isInitialized = true;
515  m_factorizationIsok = true;
516  m_info = Success;
517 }
const Index * innerNonZeroPtr() const
Definition: SparseMatrix.h:158
const IndicesType & indices() const
const Index * outerIndexPtr() const
Definition: SparseMatrix.h:149
int coletree(const MatrixType &mat, IndexVector &parent, IndexVector &firstRowElt, typename MatrixType::Index *perm=0)
template<typename _MatrixType , typename _OrderingType >
ComputationInfo Eigen::SparseQR< _MatrixType, _OrderingType >::info ( ) const
inline

Reports whether previous computation was successful.

Returns
Success if computation was succesful, NumericalIssue if the QR factorization reports a numerical problem InvalidInput if the input matrix is invalid
See also
iparm()

Definition at line 214 of file SparseQR.h.

215  {
216  eigen_assert(m_isInitialized && "Decomposition is not initialized.");
217  return m_info;
218  }
template<typename _MatrixType , typename _OrderingType >
std::string Eigen::SparseQR< _MatrixType, _OrderingType >::lastErrorMessage ( ) const
inline
Returns
A string describing the type of error. This method is provided to ease debugging, not to handle errors.

Definition at line 147 of file SparseQR.h.

147 { return m_lastError; }
template<typename _MatrixType , typename _OrderingType >
SparseQRMatrixQReturnType<SparseQR> Eigen::SparseQR< _MatrixType, _OrderingType >::matrixQ ( void  ) const
inline
Returns
an expression of the matrix Q as products of sparse Householder reflectors. The common usage of this function is to apply it to a dense matrix or vector
VectorXd B1, B2;
// Initialize B1
B2 = matrixQ() * B1;

To get a plain SparseMatrix representation of Q:

SparseMatrix<double> Q;
Q = SparseQR<SparseMatrix<double> >(A).matrixQ();

Internally, this call simply performs a sparse product between the matrix Q and a sparse identity matrix. However, due to the fact that the sparse reflectors are stored unsorted, two transpositions are needed to sort them before performing the product.

Definition at line 132 of file SparseQR.h.

133  { return SparseQRMatrixQReturnType<SparseQR>(*this); }
template<typename _MatrixType , typename _OrderingType >
const QRMatrixType& Eigen::SparseQR< _MatrixType, _OrderingType >::matrixR ( void  ) const
inline
Returns
a const reference to the sparse upper triangular matrix R of the QR factorization.

Definition at line 102 of file SparseQR.h.

102 { return m_R; }
template<typename _MatrixType , typename _OrderingType >
Index Eigen::SparseQR< _MatrixType, _OrderingType >::rank ( ) const
inline
Returns
the number of non linearly dependent columns as determined by the pivoting threshold.
See also
setPivotThreshold()

Definition at line 108 of file SparseQR.h.

109  {
110  eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
111  return m_nonzeropivots;
112  }
template<typename _MatrixType , typename _OrderingType >
Index Eigen::SparseQR< _MatrixType, _OrderingType >::rows ( void  ) const
inline
Returns
the number of rows of the represented matrix.

Definition at line 94 of file SparseQR.h.

94 { return m_pmat.rows(); }
Index rows() const
Definition: SparseMatrix.h:119
template<typename _MatrixType , typename _OrderingType >
void Eigen::SparseQR< _MatrixType, _OrderingType >::setPivotThreshold ( const RealScalar &  threshold)
inline

Sets the threshold that is used to determine linearly dependent columns during the factorization.

In practice, if during the factorization the norm of the column that has to be eliminated is below this threshold, then the entire column is treated as zero, and it is moved at the end.

Definition at line 181 of file SparseQR.h.

182  {
183  m_useDefaultThreshold = false;
184  m_threshold = threshold;
185  }
template<typename _MatrixType , typename _OrderingType >
template<typename Rhs >
const internal::solve_retval<SparseQR, Rhs> Eigen::SparseQR< _MatrixType, _OrderingType >::solve ( const MatrixBase< Rhs > &  B) const
inline
Returns
the solution X of $ A X = B $ using the current decomposition of A.
See also
compute()

Definition at line 192 of file SparseQR.h.

193  {
194  eigen_assert(m_isInitialized && "The factorization should be called first, use compute()");
195  eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix");
196  return internal::solve_retval<SparseQR, Rhs>(*this, B.derived());
197  }
Index rows() const
Definition: SparseQR.h:94

The documentation for this class was generated from the following file: