ColPivHouseholderQR.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) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
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_COLPIVOTINGHOUSEHOLDERQR_H
12 #define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
13 
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 namespace internal {
19 template<typename MatrixType_, typename PermutationIndex_> struct traits<ColPivHouseholderQR<MatrixType_, PermutationIndex_> >
20  : traits<MatrixType_>
21 {
22  typedef MatrixXpr XprKind;
23  typedef SolverStorage StorageKind;
24  typedef PermutationIndex_ PermutationIndex;
25  enum { Flags = 0 };
26 };
27 
28 } // end namespace internal
29 
53 template<typename MatrixType_, typename PermutationIndex_> class ColPivHouseholderQR
54  : public SolverBase<ColPivHouseholderQR<MatrixType_, PermutationIndex_> >
55 {
56  public:
57 
58  typedef MatrixType_ MatrixType;
60  friend class SolverBase<ColPivHouseholderQR>;
61  typedef PermutationIndex_ PermutationIndex;
63 
64  enum {
65  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
66  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
67  };
68  typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
70  typedef typename internal::plain_row_type<MatrixType, PermutationIndex>::type IntRowVectorType;
71  typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
72  typedef typename internal::plain_row_type<MatrixType, RealScalar>::type RealRowVectorType;
75 
76 private:
78  Index diag = numext::mini(rows, cols);
79  m_hCoeffs.resize(diag);
81  m_colsTranspositions.resize(cols);
82  m_temp.resize(cols);
83  m_colNormsUpdated.resize(cols);
84  m_colNormsDirect.resize(cols);
85  m_isInitialized = false;
87  }
88 
89  public:
90 
98  : m_qr(),
99  m_hCoeffs(),
102  m_temp(),
105  m_isInitialized(false),
106  m_usePrescribedThreshold(false) {}
107 
115 
128  template <typename InputType>
129  explicit ColPivHouseholderQR(const EigenBase<InputType>& matrix) : m_qr(matrix.rows(), matrix.cols()) {
130  init(matrix.rows(), matrix.cols());
131  compute(matrix.derived());
132  }
133 
140  template <typename InputType>
141  explicit ColPivHouseholderQR(EigenBase<InputType>& matrix) : m_qr(matrix.derived()) {
142  init(matrix.rows(), matrix.cols());
143  computeInPlace();
144  }
145 
146  #ifdef EIGEN_PARSED_BY_DOXYGEN
161  template<typename Rhs>
163  solve(const MatrixBase<Rhs>& b) const;
164  #endif
165 
168  {
169  return householderQ();
170  }
171 
174  const MatrixType& matrixQR() const
175  {
176  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
177  return m_qr;
178  }
179 
189  const MatrixType& matrixR() const
190  {
191  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
192  return m_qr;
193  }
194 
195  template<typename InputType>
197 
200  {
201  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
202  return m_colsPermutation;
203  }
204 
218  typename MatrixType::Scalar determinant() const;
219 
234 
248 
255  inline Index rank() const
256  {
257  using std::abs;
258  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
259  RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
260  Index result = 0;
261  for(Index i = 0; i < m_nonzero_pivots; ++i)
262  result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
263  return result;
264  }
265 
272  inline Index dimensionOfKernel() const
273  {
274  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
275  return cols() - rank();
276  }
277 
285  inline bool isInjective() const
286  {
287  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
288  return rank() == cols();
289  }
290 
298  inline bool isSurjective() const
299  {
300  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
301  return rank() == rows();
302  }
303 
310  inline bool isInvertible() const
311  {
312  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
313  return isInjective() && isSurjective();
314  }
315 
322  {
323  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
324  return Inverse<ColPivHouseholderQR>(*this);
325  }
326 
327  inline Index rows() const { return m_qr.rows(); }
328  inline Index cols() const { return m_qr.cols(); }
329 
334  const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
335 
354  {
357  return *this;
358  }
359 
369  {
370  m_usePrescribedThreshold = false;
371  return *this;
372  }
373 
378  RealScalar threshold() const
379  {
382  // this formula comes from experimenting (see "LU precision tuning" thread on the list)
383  // and turns out to be identical to Higham's formula used already in LDLt.
384  : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
385  }
386 
394  inline Index nonzeroPivots() const
395  {
396  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
397  return m_nonzero_pivots;
398  }
399 
403  RealScalar maxPivot() const { return m_maxpivot; }
404 
412  {
413  eigen_assert(m_isInitialized && "Decomposition is not initialized.");
414  return Success;
415  }
416 
417  #ifndef EIGEN_PARSED_BY_DOXYGEN
418  template<typename RhsType, typename DstType>
419  void _solve_impl(const RhsType &rhs, DstType &dst) const;
420 
421  template<bool Conjugate, typename RhsType, typename DstType>
422  void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
423  #endif
424 
425  protected:
426 
428 
430 
432 
444 };
445 
446 template<typename MatrixType, typename PermutationIndex>
448 {
449  eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
450  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
451  Scalar detQ;
452  internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ);
453  return m_qr.diagonal().prod() * detQ * Scalar(m_det_p);
454 }
455 
456 template<typename MatrixType, typename PermutationIndex>
458 {
459  using std::abs;
460  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
461  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
462  return abs(m_qr.diagonal().prod());
463 }
464 
465 template<typename MatrixType, typename PermutationIndex>
467 {
468  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
469  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
470  return m_qr.diagonal().cwiseAbs().array().log().sum();
471 }
472 
479 template<typename MatrixType, typename PermutationIndex>
480 template<typename InputType>
482 {
483  m_qr = matrix.derived();
484  computeInPlace();
485  return *this;
486 }
487 
488 template<typename MatrixType, typename PermutationIndex>
490 {
491 
493 
494  using std::abs;
495 
496  Index rows = m_qr.rows();
497  Index cols = m_qr.cols();
498  Index size = m_qr.diagonalSize();
499 
500  m_hCoeffs.resize(size);
501 
502  m_temp.resize(cols);
503 
504  m_colsTranspositions.resize(m_qr.cols());
505  Index number_of_transpositions = 0;
506 
507  m_colNormsUpdated.resize(cols);
508  m_colNormsDirect.resize(cols);
509  for (Index k = 0; k < cols; ++k) {
510  // colNormsDirect(k) caches the most recent directly computed norm of
511  // column k.
512  m_colNormsDirect.coeffRef(k) = m_qr.col(k).norm();
513  m_colNormsUpdated.coeffRef(k) = m_colNormsDirect.coeffRef(k);
514  }
515 
516  RealScalar threshold_helper = numext::abs2<RealScalar>(m_colNormsUpdated.maxCoeff() * NumTraits<RealScalar>::epsilon()) / RealScalar(rows);
517  RealScalar norm_downdate_threshold = numext::sqrt(NumTraits<RealScalar>::epsilon());
518 
519  m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
520  m_maxpivot = RealScalar(0);
521 
522  for(Index k = 0; k < size; ++k)
523  {
524  // first, we look up in our table m_colNormsUpdated which column has the biggest norm
525  Index biggest_col_index;
526  RealScalar biggest_col_sq_norm = numext::abs2(m_colNormsUpdated.tail(cols-k).maxCoeff(&biggest_col_index));
527  biggest_col_index += k;
528 
529  // Track the number of meaningful pivots but do not stop the decomposition to make
530  // sure that the initial matrix is properly reproduced. See bug 941.
531  if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
532  m_nonzero_pivots = k;
533 
534  // apply the transposition to the columns
535  m_colsTranspositions.coeffRef(k) = static_cast<PermutationIndex>(biggest_col_index);
536  if(k != biggest_col_index) {
537  m_qr.col(k).swap(m_qr.col(biggest_col_index));
538  std::swap(m_colNormsUpdated.coeffRef(k), m_colNormsUpdated.coeffRef(biggest_col_index));
539  std::swap(m_colNormsDirect.coeffRef(k), m_colNormsDirect.coeffRef(biggest_col_index));
540  ++number_of_transpositions;
541  }
542 
543  // generate the householder vector, store it below the diagonal
544  RealScalar beta;
545  m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
546 
547  // apply the householder transformation to the diagonal coefficient
548  m_qr.coeffRef(k,k) = beta;
549 
550  // remember the maximum absolute value of diagonal coefficients
551  if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
552 
553  // apply the householder transformation
554  m_qr.bottomRightCorner(rows-k, cols-k-1)
555  .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
556 
557  // update our table of norms of the columns
558  for (Index j = k + 1; j < cols; ++j) {
559  // The following implements the stable norm downgrade step discussed in
560  // http://www.netlib.org/lapack/lawnspdf/lawn176.pdf
561  // and used in LAPACK routines xGEQPF and xGEQP3.
562  // See lines 278-297 in http://www.netlib.org/lapack/explore-html/dc/df4/sgeqpf_8f_source.html
563  if (!numext::is_exactly_zero(m_colNormsUpdated.coeffRef(j))) {
564  RealScalar temp = abs(m_qr.coeffRef(k, j)) / m_colNormsUpdated.coeffRef(j);
565  temp = (RealScalar(1) + temp) * (RealScalar(1) - temp);
566  temp = temp < RealScalar(0) ? RealScalar(0) : temp;
567  RealScalar temp2 = temp * numext::abs2<RealScalar>(m_colNormsUpdated.coeffRef(j) /
568  m_colNormsDirect.coeffRef(j));
569  if (temp2 <= norm_downdate_threshold) {
570  // The updated norm has become too inaccurate so re-compute the column
571  // norm directly.
572  m_colNormsDirect.coeffRef(j) = m_qr.col(j).tail(rows - k - 1).norm();
573  m_colNormsUpdated.coeffRef(j) = m_colNormsDirect.coeffRef(j);
574  } else {
575  m_colNormsUpdated.coeffRef(j) *= numext::sqrt(temp);
576  }
577  }
578  }
579  }
580 
582  for(Index k = 0; k < size/*m_nonzero_pivots*/; ++k)
584 
585  m_det_p = (number_of_transpositions%2) ? -1 : 1;
586  m_isInitialized = true;
587 }
588 
589 #ifndef EIGEN_PARSED_BY_DOXYGEN
590 template<typename MatrixType_, typename PermutationIndex_>
591 template<typename RhsType, typename DstType>
592 void ColPivHouseholderQR<MatrixType_, PermutationIndex_>::_solve_impl(const RhsType &rhs, DstType &dst) const
593 {
594  const Index nonzero_pivots = nonzeroPivots();
595 
596  if(nonzero_pivots == 0)
597  {
598  dst.setZero();
599  return;
600  }
601 
602  typename RhsType::PlainObject c(rhs);
603 
604  c.applyOnTheLeft(householderQ().setLength(nonzero_pivots).adjoint() );
605 
606  m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
607  .template triangularView<Upper>()
608  .solveInPlace(c.topRows(nonzero_pivots));
609 
610  for(Index i = 0; i < nonzero_pivots; ++i) dst.row(m_colsPermutation.indices().coeff(i)) = c.row(i);
611  for(Index i = nonzero_pivots; i < cols(); ++i) dst.row(m_colsPermutation.indices().coeff(i)).setZero();
612 }
613 
614 template<typename MatrixType_, typename PermutationIndex_>
615 template<bool Conjugate, typename RhsType, typename DstType>
616 void ColPivHouseholderQR<MatrixType_, PermutationIndex_>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
617 {
618  const Index nonzero_pivots = nonzeroPivots();
619 
620  if(nonzero_pivots == 0)
621  {
622  dst.setZero();
623  return;
624  }
625 
626  typename RhsType::PlainObject c(m_colsPermutation.transpose()*rhs);
627 
628  m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
629  .template triangularView<Upper>()
630  .transpose().template conjugateIf<Conjugate>()
631  .solveInPlace(c.topRows(nonzero_pivots));
632 
633  dst.topRows(nonzero_pivots) = c.topRows(nonzero_pivots);
634  dst.bottomRows(rows()-nonzero_pivots).setZero();
635 
636  dst.applyOnTheLeft(householderQ().setLength(nonzero_pivots).template conjugateIf<!Conjugate>() );
637 }
638 #endif
639 
640 namespace internal {
641 
642 template<typename DstXprType, typename MatrixType, typename PermutationIndex>
643 struct Assignment<DstXprType, Inverse<ColPivHouseholderQR<MatrixType, PermutationIndex> >, internal::assign_op<typename DstXprType::Scalar,typename ColPivHouseholderQR<MatrixType, PermutationIndex>::Scalar>, Dense2Dense>
644 {
645  typedef ColPivHouseholderQR<MatrixType, PermutationIndex> QrType;
646  typedef Inverse<QrType> SrcXprType;
647  static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename QrType::Scalar> &)
648  {
649  dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
650  }
651 };
652 
653 } // end namespace internal
654 
658 template<typename MatrixType, typename PermutationIndex>
661 {
662  eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
663  return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
664 }
665 
670 template<typename Derived>
671 template<typename PermutationIndexType>
674 {
676 }
677 
678 } // end namespace Eigen
679 
680 #endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
const AbsReturnType abs() const
Array< int, 3, 1 > b
Array33i c
#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived)
Definition: Macros.h:1149
#define eigen_assert(x)
Definition: Macros.h:902
v setZero(3)
#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE)
Definition: StaticAssert.h:81
Matrix< float, 1, Dynamic > MatrixType
Householder rank-revealing QR decomposition of a matrix with column-pivoting.
internal::plain_row_type< MatrixType >::type RowVectorType
MatrixType::PlainObject PlainObject
const Inverse< ColPivHouseholderQR > inverse() const
internal::plain_diag_type< MatrixType >::type HCoeffsType
RealRowVectorType m_colNormsUpdated
MatrixType::RealScalar absDeterminant() const
internal::plain_row_type< MatrixType, RealScalar >::type RealRowVectorType
RealRowVectorType m_colNormsDirect
ColPivHouseholderQR(EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
ColPivHouseholderQR & setThreshold(const RealScalar &threshold)
PermutationIndex_ PermutationIndex
internal::plain_row_type< MatrixType, PermutationIndex >::type IntRowVectorType
const HCoeffsType & hCoeffs() const
PermutationMatrix< ColsAtCompileTime, MaxColsAtCompileTime, PermutationIndex > PermutationType
HouseholderSequenceType matrixQ() const
SolverBase< ColPivHouseholderQR > Base
ComputationInfo info() const
Reports whether the QR factorization was successful.
const PermutationType & colsPermutation() const
ColPivHouseholderQR()
Default Constructor.
HouseholderSequenceType householderQ() const
const MatrixType & matrixR() const
const Solve< ColPivHouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
ColPivHouseholderQR & compute(const EigenBase< InputType > &matrix)
MatrixType::Scalar determinant() const
void init(Index rows, Index cols)
MatrixType::RealScalar logAbsDeterminant() const
ColPivHouseholderQR & setThreshold(Default_t)
ColPivHouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
ColPivHouseholderQR(const EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
HouseholderSequence< MatrixType, internal::remove_all_t< typename HCoeffsType::ConjugateReturnType > > HouseholderSequenceType
const MatrixType & matrixQR() const
IntRowVectorType m_colsTranspositions
Complete orthogonal decomposition (COD) of a matrix.
NumTraits< Scalar >::Real RealScalar
Definition: DenseBase.h:68
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
Sequence of Householder reflections acting on subspaces with decreasing size.
Expression of the inverse of another expression.
Definition: Inverse.h:46
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:52
const ColPivHouseholderQR< PlainObject, PermutationIndex > colPivHouseholderQr() const
Base::PlainObject PlainObject
Definition: Matrix.h:194
InverseReturnType transpose() const
void resize(Index newSize)
Derived & applyTranspositionOnTheRight(Index i, Index j)
const IndicesType & indices() const
Pseudo expression representing a solving operation.
Definition: Solve.h:65
A base class for matrix decomposition and solvers.
Definition: SolverBase.h:71
internal::traits< ColPivHouseholderQR< MatrixType_, PermutationIndex_ > >::Scalar Scalar
Definition: SolverBase.h:75
ColPivHouseholderQR< MatrixType_, PermutationIndex_ > & derived()
Definition: EigenBase.h:48
ComputationInfo
Definition: Constants.h:444
@ Success
Definition: Constants.h:446
void swap(scoped_array< T > &a, scoped_array< T > &b)
Definition: Memory.h:788
bool abs2(bool x)
EIGEN_ALWAYS_INLINE float sqrt(const float &x)
EIGEN_ALWAYS_INLINE T mini(const T &x, const T &y)
bool is_exactly_zero(const X &x)
Definition: Meta.h:475
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
Default_t
Definition: Constants.h:364
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
Derived & derived()
Definition: EigenBase.h:48
EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT
Definition: EigenBase.h:65
Eigen::Index Index
The interface type of indices.
Definition: EigenBase.h:41
EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT
Definition: EigenBase.h:62
EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT
Definition: EigenBase.h:69
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:231
std::ptrdiff_t j