Eigen  3.2.10
 
Loading...
Searching...
No Matches
ColPivHouseholderQR.h
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
14namespace Eigen {
15
37template<typename _MatrixType> class ColPivHouseholderQR
38{
39 public:
40
41 typedef _MatrixType MatrixType;
42 enum {
43 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
44 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
45 Options = MatrixType::Options,
46 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
47 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
48 };
49 typedef typename MatrixType::Scalar Scalar;
50 typedef typename MatrixType::RealScalar RealScalar;
51 typedef typename MatrixType::Index Index;
53 typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
55 typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
56 typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
57 typedef typename internal::plain_row_type<MatrixType, RealScalar>::type RealRowVectorType;
59
60 private:
61
62 typedef typename PermutationType::Index PermIndexType;
63
64 public:
65
73 : m_qr(),
74 m_hCoeffs(),
75 m_colsPermutation(),
76 m_colsTranspositions(),
77 m_temp(),
78 m_colSqNorms(),
79 m_isInitialized(false),
80 m_usePrescribedThreshold(false) {}
81
88 ColPivHouseholderQR(Index rows, Index cols)
89 : m_qr(rows, cols),
90 m_hCoeffs((std::min)(rows,cols)),
91 m_colsPermutation(PermIndexType(cols)),
92 m_colsTranspositions(cols),
93 m_temp(cols),
94 m_colSqNorms(cols),
95 m_isInitialized(false),
96 m_usePrescribedThreshold(false) {}
97
110 ColPivHouseholderQR(const MatrixType& matrix)
111 : m_qr(matrix.rows(), matrix.cols()),
112 m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
113 m_colsPermutation(PermIndexType(matrix.cols())),
114 m_colsTranspositions(matrix.cols()),
115 m_temp(matrix.cols()),
116 m_colSqNorms(matrix.cols()),
117 m_isInitialized(false),
118 m_usePrescribedThreshold(false)
119 {
120 compute(matrix);
121 }
122
137 template<typename Rhs>
138 inline const internal::solve_retval<ColPivHouseholderQR, Rhs>
139 solve(const MatrixBase<Rhs>& b) const
140 {
141 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
142 return internal::solve_retval<ColPivHouseholderQR, Rhs>(*this, b.derived());
143 }
144
145 HouseholderSequenceType householderQ(void) const;
146 HouseholderSequenceType matrixQ(void) const
147 {
148 return householderQ();
149 }
150
153 const MatrixType& matrixQR() const
154 {
155 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
156 return m_qr;
157 }
158
168 const MatrixType& matrixR() const
169 {
170 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
171 return m_qr;
172 }
173
174 ColPivHouseholderQR& compute(const MatrixType& matrix);
175
177 const PermutationType& colsPermutation() const
178 {
179 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
180 return m_colsPermutation;
181 }
182
196 typename MatrixType::RealScalar absDeterminant() const;
197
210 typename MatrixType::RealScalar logAbsDeterminant() const;
211
218 inline Index rank() const
219 {
220 using std::abs;
221 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
222 RealScalar premultiplied_threshold = abs(m_maxpivot) * threshold();
223 Index result = 0;
224 for(Index i = 0; i < m_nonzero_pivots; ++i)
225 result += (abs(m_qr.coeff(i,i)) > premultiplied_threshold);
226 return result;
227 }
228
235 inline Index dimensionOfKernel() const
236 {
237 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
238 return cols() - rank();
239 }
240
248 inline bool isInjective() const
249 {
250 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
251 return rank() == cols();
252 }
253
261 inline bool isSurjective() const
262 {
263 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
264 return rank() == rows();
265 }
266
273 inline bool isInvertible() const
274 {
275 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
276 return isInjective() && isSurjective();
277 }
278
284 inline const
285 internal::solve_retval<ColPivHouseholderQR, typename MatrixType::IdentityReturnType>
286 inverse() const
287 {
288 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
289 return internal::solve_retval<ColPivHouseholderQR,typename MatrixType::IdentityReturnType>
290 (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()));
291 }
292
293 inline Index rows() const { return m_qr.rows(); }
294 inline Index cols() const { return m_qr.cols(); }
295
300 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
301
320 {
321 m_usePrescribedThreshold = true;
322 m_prescribedThreshold = threshold;
323 return *this;
324 }
325
335 {
336 m_usePrescribedThreshold = false;
337 return *this;
338 }
339
344 RealScalar threshold() const
345 {
346 eigen_assert(m_isInitialized || m_usePrescribedThreshold);
347 return m_usePrescribedThreshold ? m_prescribedThreshold
348 // this formula comes from experimenting (see "LU precision tuning" thread on the list)
349 // and turns out to be identical to Higham's formula used already in LDLt.
350 : NumTraits<Scalar>::epsilon() * RealScalar(m_qr.diagonalSize());
351 }
352
360 inline Index nonzeroPivots() const
361 {
362 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
363 return m_nonzero_pivots;
364 }
365
367 * diagonal coefficient of R.
368 */
369 RealScalar maxPivot() const { return m_maxpivot; }
370
378 {
379 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
380 return Success;
381 }
382
383 protected:
384
385 static void check_template_parameters()
386 {
387 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
388 }
389
390 MatrixType m_qr;
391 HCoeffsType m_hCoeffs;
392 PermutationType m_colsPermutation;
393 IntRowVectorType m_colsTranspositions;
394 RowVectorType m_temp;
395 RealRowVectorType m_colSqNorms;
396 bool m_isInitialized, m_usePrescribedThreshold;
397 RealScalar m_prescribedThreshold, m_maxpivot;
398 Index m_nonzero_pivots;
399 Index m_det_pq;
400};
401
402template<typename MatrixType>
403typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::absDeterminant() const
404{
405 using std::abs;
406 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
407 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
408 return abs(m_qr.diagonal().prod());
409}
410
411template<typename MatrixType>
412typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDeterminant() const
413{
414 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
415 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
416 return m_qr.diagonal().cwiseAbs().array().log().sum();
417}
418
425template<typename MatrixType>
427{
428 check_template_parameters();
429
430 using std::abs;
431 Index rows = matrix.rows();
432 Index cols = matrix.cols();
433 Index size = matrix.diagonalSize();
434
435 // the column permutation is stored as int indices, so just to be sure:
436 eigen_assert(cols<=NumTraits<int>::highest());
437
438 m_qr = matrix;
439 m_hCoeffs.resize(size);
440
441 m_temp.resize(cols);
442
443 m_colsTranspositions.resize(matrix.cols());
444 Index number_of_transpositions = 0;
445
446 m_colSqNorms.resize(cols);
447 for(Index k = 0; k < cols; ++k)
448 m_colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm();
449
450 RealScalar threshold_helper = m_colSqNorms.maxCoeff() * numext::abs2(NumTraits<Scalar>::epsilon()) / RealScalar(rows);
451
452 m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
453 m_maxpivot = RealScalar(0);
454
455 for(Index k = 0; k < size; ++k)
456 {
457 // first, we look up in our table m_colSqNorms which column has the biggest squared norm
458 Index biggest_col_index;
459 RealScalar biggest_col_sq_norm = m_colSqNorms.tail(cols-k).maxCoeff(&biggest_col_index);
460 biggest_col_index += k;
461
462 // since our table m_colSqNorms accumulates imprecision at every step, we must now recompute
463 // the actual squared norm of the selected column.
464 // Note that not doing so does result in solve() sometimes returning inf/nan values
465 // when running the unit test with 1000 repetitions.
466 biggest_col_sq_norm = m_qr.col(biggest_col_index).tail(rows-k).squaredNorm();
467
468 // we store that back into our table: it can't hurt to correct our table.
469 m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm;
470
471 // Track the number of meaningful pivots but do not stop the decomposition to make
472 // sure that the initial matrix is properly reproduced. See bug 941.
473 if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
474 m_nonzero_pivots = k;
475
476 // apply the transposition to the columns
477 m_colsTranspositions.coeffRef(k) = biggest_col_index;
478 if(k != biggest_col_index) {
479 m_qr.col(k).swap(m_qr.col(biggest_col_index));
480 std::swap(m_colSqNorms.coeffRef(k), m_colSqNorms.coeffRef(biggest_col_index));
481 ++number_of_transpositions;
482 }
483
484 // generate the householder vector, store it below the diagonal
485 RealScalar beta;
486 m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
487
488 // apply the householder transformation to the diagonal coefficient
489 m_qr.coeffRef(k,k) = beta;
490
491 // remember the maximum absolute value of diagonal coefficients
492 if(abs(beta) > m_maxpivot) m_maxpivot = abs(beta);
493
494 // apply the householder transformation
495 m_qr.bottomRightCorner(rows-k, cols-k-1)
496 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
497
498 // update our table of squared norms of the columns
499 m_colSqNorms.tail(cols-k-1) -= m_qr.row(k).tail(cols-k-1).cwiseAbs2();
500 }
501
502 m_colsPermutation.setIdentity(PermIndexType(cols));
503 for(PermIndexType k = 0; k < size/*m_nonzero_pivots*/; ++k)
504 m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(m_colsTranspositions.coeff(k)));
505
506 m_det_pq = (number_of_transpositions%2) ? -1 : 1;
507 m_isInitialized = true;
508
509 return *this;
510}
511
512namespace internal {
513
514template<typename _MatrixType, typename Rhs>
515struct solve_retval<ColPivHouseholderQR<_MatrixType>, Rhs>
516 : solve_retval_base<ColPivHouseholderQR<_MatrixType>, Rhs>
517{
518 EIGEN_MAKE_SOLVE_HELPERS(ColPivHouseholderQR<_MatrixType>,Rhs)
519
520 template<typename Dest> void evalTo(Dest& dst) const
521 {
522 eigen_assert(rhs().rows() == dec().rows());
523
524 const Index cols = dec().cols(),
525 nonzero_pivots = dec().nonzeroPivots();
526
527 if(nonzero_pivots == 0)
528 {
529 dst.setZero();
530 return;
531 }
532
533 typename Rhs::PlainObject c(rhs());
534
535 // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T
536 c.applyOnTheLeft(householderSequence(dec().matrixQR(), dec().hCoeffs())
537 .setLength(dec().nonzeroPivots())
538 .transpose()
539 );
540
541 dec().matrixR()
542 .topLeftCorner(nonzero_pivots, nonzero_pivots)
543 .template triangularView<Upper>()
544 .solveInPlace(c.topRows(nonzero_pivots));
545
546 for(Index i = 0; i < nonzero_pivots; ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i);
547 for(Index i = nonzero_pivots; i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero();
548 }
549};
550
551} // end namespace internal
552
556template<typename MatrixType>
557typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType>
559{
560 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
561 return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
562}
563
568template<typename Derived>
574
575} // end namespace Eigen
576
577#endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
Householder rank-revealing QR decomposition of a matrix with column-pivoting.
Definition ColPivHouseholderQR.h:38
MatrixType::RealScalar absDeterminant() const
Definition ColPivHouseholderQR.h:403
HouseholderSequenceType householderQ(void) const
Definition ColPivHouseholderQR.h:558
ColPivHouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
Definition ColPivHouseholderQR.h:88
MatrixType::RealScalar logAbsDeterminant() const
Definition ColPivHouseholderQR.h:412
const internal::solve_retval< ColPivHouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
Definition ColPivHouseholderQR.h:139
ColPivHouseholderQR & setThreshold(const RealScalar &threshold)
Definition ColPivHouseholderQR.h:319
ColPivHouseholderQR()
Default Constructor.
Definition ColPivHouseholderQR.h:72
RealScalar maxPivot() const
Definition ColPivHouseholderQR.h:369
ColPivHouseholderQR & compute(const MatrixType &matrix)
Definition ColPivHouseholderQR.h:426
const MatrixType & matrixR() const
Definition ColPivHouseholderQR.h:168
bool isInvertible() const
Definition ColPivHouseholderQR.h:273
bool isInjective() const
Definition ColPivHouseholderQR.h:248
const HCoeffsType & hCoeffs() const
Definition ColPivHouseholderQR.h:300
ColPivHouseholderQR & setThreshold(Default_t)
Definition ColPivHouseholderQR.h:334
const internal::solve_retval< ColPivHouseholderQR, typename MatrixType::IdentityReturnType > inverse() const
Definition ColPivHouseholderQR.h:286
const MatrixType & matrixQR() const
Definition ColPivHouseholderQR.h:153
Index rank() const
Definition ColPivHouseholderQR.h:218
ComputationInfo info() const
Reports whether the QR factorization was succesful.
Definition ColPivHouseholderQR.h:377
ColPivHouseholderQR(const MatrixType &matrix)
Constructs a QR factorization from a given matrix.
Definition ColPivHouseholderQR.h:110
Index dimensionOfKernel() const
Definition ColPivHouseholderQR.h:235
bool isSurjective() const
Definition ColPivHouseholderQR.h:261
RealScalar threshold() const
Definition ColPivHouseholderQR.h:344
const PermutationType & colsPermutation() const
Definition ColPivHouseholderQR.h:177
Index nonzeroPivots() const
Definition ColPivHouseholderQR.h:360
EvalReturnType eval() const
Definition DenseBase.h:360
Sequence of Householder reflections acting on subspaces with decreasing size.
Definition HouseholderSequence.h:114
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:50
const ColPivHouseholderQR< PlainObject > colPivHouseholderQr() const
Definition ColPivHouseholderQR.h:570
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:129
Permutation matrix.
Definition PermutationMatrix.h:313
HouseholderSequence< VectorsType, CoeffsType > householderSequence(const VectorsType &v, const CoeffsType &h)
Convenience function for constructing a Householder sequence.
Definition HouseholderSequence.h:423
ComputationInfo
Definition Constants.h:374
@ Success
Definition Constants.h:376
Definition LDLT.h:18