FullPivHouseholderQR.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_FULLPIVOTINGHOUSEHOLDERQR_H
12#define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
13
14namespace Eigen {
15
16namespace internal {
17
18template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType;
19
20template<typename MatrixType>
21struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
22{
23 typedef typename MatrixType::PlainObject ReturnType;
24};
25
26}
27
49template<typename _MatrixType> class FullPivHouseholderQR
50{
51 public:
52
53 typedef _MatrixType MatrixType;
54 enum {
55 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
56 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
57 Options = MatrixType::Options,
58 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
59 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
60 };
61 typedef typename MatrixType::Scalar Scalar;
62 typedef typename MatrixType::RealScalar RealScalar;
63 typedef typename MatrixType::Index Index;
64 typedef internal::FullPivHouseholderQRMatrixQReturnType<MatrixType> MatrixQReturnType;
65 typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
66 typedef Matrix<Index, 1,
67 EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime,RowsAtCompileTime), RowMajor, 1,
68 EIGEN_SIZE_MIN_PREFER_FIXED(MaxColsAtCompileTime,MaxRowsAtCompileTime)> IntDiagSizeVectorType;
70 typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
71 typedef typename internal::plain_col_type<MatrixType>::type ColVectorType;
72
79 : m_qr(),
80 m_hCoeffs(),
81 m_rows_transpositions(),
82 m_cols_transpositions(),
83 m_cols_permutation(),
84 m_temp(),
85 m_isInitialized(false),
86 m_usePrescribedThreshold(false) {}
87
94 FullPivHouseholderQR(Index rows, Index cols)
95 : m_qr(rows, cols),
96 m_hCoeffs((std::min)(rows,cols)),
97 m_rows_transpositions(rows),
98 m_cols_transpositions(cols),
99 m_cols_permutation(cols),
100 m_temp((std::min)(rows,cols)),
101 m_isInitialized(false),
102 m_usePrescribedThreshold(false) {}
103
104 FullPivHouseholderQR(const MatrixType& matrix)
105 : m_qr(matrix.rows(), matrix.cols()),
106 m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
107 m_rows_transpositions(matrix.rows()),
108 m_cols_transpositions(matrix.cols()),
109 m_cols_permutation(matrix.cols()),
110 m_temp((std::min)(matrix.rows(), matrix.cols())),
111 m_isInitialized(false),
112 m_usePrescribedThreshold(false)
113 {
114 compute(matrix);
115 }
116
134 template<typename Rhs>
135 inline const internal::solve_retval<FullPivHouseholderQR, Rhs>
136 solve(const MatrixBase<Rhs>& b) const
137 {
138 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
139 return internal::solve_retval<FullPivHouseholderQR, Rhs>(*this, b.derived());
140 }
141
144 MatrixQReturnType matrixQ(void) const;
145
148 const MatrixType& matrixQR() const
149 {
150 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
151 return m_qr;
152 }
153
154 FullPivHouseholderQR& compute(const MatrixType& matrix);
155
156 const PermutationType& colsPermutation() const
157 {
158 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
159 return m_cols_permutation;
160 }
161
162 const IntDiagSizeVectorType& rowsTranspositions() const
163 {
164 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
165 return m_rows_transpositions;
166 }
167
181 typename MatrixType::RealScalar absDeterminant() const;
182
195 typename MatrixType::RealScalar logAbsDeterminant() const;
196
203 inline Index rank() const
204 {
205 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
206 RealScalar premultiplied_threshold = internal::abs(m_maxpivot) * threshold();
207 Index result = 0;
208 for(Index i = 0; i < m_nonzero_pivots; ++i)
209 result += (internal::abs(m_qr.coeff(i,i)) > premultiplied_threshold);
210 return result;
211 }
212
219 inline Index dimensionOfKernel() const
220 {
221 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
222 return cols() - rank();
223 }
224
232 inline bool isInjective() const
233 {
234 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
235 return rank() == cols();
236 }
237
245 inline bool isSurjective() const
246 {
247 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
248 return rank() == rows();
249 }
250
257 inline bool isInvertible() const
258 {
259 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
260 return isInjective() && isSurjective();
261 }
262 inline const
268 internal::solve_retval<FullPivHouseholderQR, typename MatrixType::IdentityReturnType>
269 inverse() const
270 {
271 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
272 return internal::solve_retval<FullPivHouseholderQR,typename MatrixType::IdentityReturnType>
273 (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()));
274 }
275
276 inline Index rows() const { return m_qr.rows(); }
277 inline Index cols() const { return m_qr.cols(); }
278 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
279
298 {
299 m_usePrescribedThreshold = true;
300 m_prescribedThreshold = threshold;
301 return *this;
302 }
303
313 {
314 m_usePrescribedThreshold = false;
315 return *this;
316 }
317
322 RealScalar threshold() const
323 {
324 eigen_assert(m_isInitialized || m_usePrescribedThreshold);
325 return m_usePrescribedThreshold ? m_prescribedThreshold
326 // this formula comes from experimenting (see "LU precision tuning" thread on the list)
327 // and turns out to be identical to Higham's formula used already in LDLt.
328 : NumTraits<Scalar>::epsilon() * m_qr.diagonalSize();
329 }
330
338 inline Index nonzeroPivots() const
339 {
340 eigen_assert(m_isInitialized && "LU is not initialized.");
341 return m_nonzero_pivots;
342 }
343
347 RealScalar maxPivot() const { return m_maxpivot; }
348
349 protected:
350 MatrixType m_qr;
351 HCoeffsType m_hCoeffs;
352 IntDiagSizeVectorType m_rows_transpositions;
353 IntDiagSizeVectorType m_cols_transpositions;
354 PermutationType m_cols_permutation;
355 RowVectorType m_temp;
356 bool m_isInitialized, m_usePrescribedThreshold;
357 RealScalar m_prescribedThreshold, m_maxpivot;
358 Index m_nonzero_pivots;
359 RealScalar m_precision;
360 Index m_det_pq;
361};
362
363template<typename MatrixType>
364typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::absDeterminant() const
365{
366 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
367 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
368 return internal::abs(m_qr.diagonal().prod());
369}
370
371template<typename MatrixType>
372typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDeterminant() const
373{
374 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
375 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
376 return m_qr.diagonal().cwiseAbs().array().log().sum();
377}
378
379template<typename MatrixType>
380FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
381{
382 Index rows = matrix.rows();
383 Index cols = matrix.cols();
384 Index size = (std::min)(rows,cols);
385
386 m_qr = matrix;
387 m_hCoeffs.resize(size);
388
389 m_temp.resize(cols);
390
391 m_precision = NumTraits<Scalar>::epsilon() * size;
392
393 m_rows_transpositions.resize(size);
394 m_cols_transpositions.resize(size);
395 Index number_of_transpositions = 0;
396
397 RealScalar biggest(0);
398
399 m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
400 m_maxpivot = RealScalar(0);
401
402 for (Index k = 0; k < size; ++k)
403 {
404 Index row_of_biggest_in_corner, col_of_biggest_in_corner;
405 RealScalar biggest_in_corner;
406
407 biggest_in_corner = m_qr.bottomRightCorner(rows-k, cols-k)
408 .cwiseAbs()
409 .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
410 row_of_biggest_in_corner += k;
411 col_of_biggest_in_corner += k;
412 if(k==0) biggest = biggest_in_corner;
413
414 // if the corner is negligible, then we have less than full rank, and we can finish early
415 if(internal::isMuchSmallerThan(biggest_in_corner, biggest, m_precision))
416 {
417 m_nonzero_pivots = k;
418 for(Index i = k; i < size; i++)
419 {
420 m_rows_transpositions.coeffRef(i) = i;
421 m_cols_transpositions.coeffRef(i) = i;
422 m_hCoeffs.coeffRef(i) = Scalar(0);
423 }
424 break;
425 }
426
427 m_rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
428 m_cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
429 if(k != row_of_biggest_in_corner) {
430 m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
431 ++number_of_transpositions;
432 }
433 if(k != col_of_biggest_in_corner) {
434 m_qr.col(k).swap(m_qr.col(col_of_biggest_in_corner));
435 ++number_of_transpositions;
436 }
437
438 RealScalar beta;
439 m_qr.col(k).tail(rows-k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
440 m_qr.coeffRef(k,k) = beta;
441
442 // remember the maximum absolute value of diagonal coefficients
443 if(internal::abs(beta) > m_maxpivot) m_maxpivot = internal::abs(beta);
444
445 m_qr.bottomRightCorner(rows-k, cols-k-1)
446 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
447 }
448
449 m_cols_permutation.setIdentity(cols);
450 for(Index k = 0; k < size; ++k)
451 m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));
452
453 m_det_pq = (number_of_transpositions%2) ? -1 : 1;
454 m_isInitialized = true;
455
456 return *this;
457}
458
459namespace internal {
460
461template<typename _MatrixType, typename Rhs>
462struct solve_retval<FullPivHouseholderQR<_MatrixType>, Rhs>
463 : solve_retval_base<FullPivHouseholderQR<_MatrixType>, Rhs>
464{
465 EIGEN_MAKE_SOLVE_HELPERS(FullPivHouseholderQR<_MatrixType>,Rhs)
466
467 template<typename Dest> void evalTo(Dest& dst) const
468 {
469 const Index rows = dec().rows(), cols = dec().cols();
470 eigen_assert(rhs().rows() == rows);
471
472 // FIXME introduce nonzeroPivots() and use it here. and more generally,
473 // make the same improvements in this dec as in FullPivLU.
474 if(dec().rank()==0)
475 {
476 dst.setZero();
477 return;
478 }
479
480 typename Rhs::PlainObject c(rhs());
481
482 Matrix<Scalar,1,Rhs::ColsAtCompileTime> temp(rhs().cols());
483 for (Index k = 0; k < dec().rank(); ++k)
484 {
485 Index remainingSize = rows-k;
486 c.row(k).swap(c.row(dec().rowsTranspositions().coeff(k)));
487 c.bottomRightCorner(remainingSize, rhs().cols())
488 .applyHouseholderOnTheLeft(dec().matrixQR().col(k).tail(remainingSize-1),
489 dec().hCoeffs().coeff(k), &temp.coeffRef(0));
490 }
491
492 if(!dec().isSurjective())
493 {
494 // is c is in the image of R ?
495 RealScalar biggest_in_upper_part_of_c = c.topRows( dec().rank() ).cwiseAbs().maxCoeff();
496 RealScalar biggest_in_lower_part_of_c = c.bottomRows(rows-dec().rank()).cwiseAbs().maxCoeff();
497 // FIXME brain dead
498 const RealScalar m_precision = NumTraits<Scalar>::epsilon() * (std::min)(rows,cols);
499 // this internal:: prefix is needed by at least gcc 3.4 and ICC
500 if(!internal::isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision))
501 return;
502 }
503 dec().matrixQR()
504 .topLeftCorner(dec().rank(), dec().rank())
505 .template triangularView<Upper>()
506 .solveInPlace(c.topRows(dec().rank()));
507
508 for(Index i = 0; i < dec().rank(); ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i);
509 for(Index i = dec().rank(); i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero();
510 }
511};
512
519template<typename MatrixType> struct FullPivHouseholderQRMatrixQReturnType
520 : public ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
521{
522public:
523 typedef typename MatrixType::Index Index;
524 typedef typename FullPivHouseholderQR<MatrixType>::IntDiagSizeVectorType IntDiagSizeVectorType;
525 typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
526 typedef Matrix<typename MatrixType::Scalar, 1, MatrixType::RowsAtCompileTime, RowMajor, 1,
527 MatrixType::MaxRowsAtCompileTime> WorkVectorType;
528
529 FullPivHouseholderQRMatrixQReturnType(const MatrixType& qr,
530 const HCoeffsType& hCoeffs,
531 const IntDiagSizeVectorType& rowsTranspositions)
532 : m_qr(qr),
533 m_hCoeffs(hCoeffs),
534 m_rowsTranspositions(rowsTranspositions)
535 {}
536
537 template <typename ResultType>
538 void evalTo(ResultType& result) const
539 {
540 const Index rows = m_qr.rows();
541 WorkVectorType workspace(rows);
542 evalTo(result, workspace);
543 }
544
545 template <typename ResultType>
546 void evalTo(ResultType& result, WorkVectorType& workspace) const
547 {
548 // compute the product H'_0 H'_1 ... H'_n-1,
549 // where H_k is the k-th Householder transformation I - h_k v_k v_k'
550 // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
551 const Index rows = m_qr.rows();
552 const Index cols = m_qr.cols();
553 const Index size = (std::min)(rows, cols);
554 workspace.resize(rows);
555 result.setIdentity(rows, rows);
556 for (Index k = size-1; k >= 0; k--)
557 {
558 result.block(k, k, rows-k, rows-k)
559 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), internal::conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k));
560 result.row(k).swap(result.row(m_rowsTranspositions.coeff(k)));
561 }
562 }
563
564 Index rows() const { return m_qr.rows(); }
565 Index cols() const { return m_qr.rows(); }
566
567protected:
568 typename MatrixType::Nested m_qr;
569 typename HCoeffsType::Nested m_hCoeffs;
570 typename IntDiagSizeVectorType::Nested m_rowsTranspositions;
571};
572
573} // end namespace internal
574
575template<typename MatrixType>
576inline typename FullPivHouseholderQR<MatrixType>::MatrixQReturnType FullPivHouseholderQR<MatrixType>::matrixQ() const
577{
578 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
579 return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions);
580}
581
586template<typename Derived>
592
593} // end namespace Eigen
594
595#endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
EvalReturnType eval() const
Definition DenseBase.h:372
internal::traits< MatrixWrapper< ExpressionType > >::Index Index
Definition DenseBase.h:51
Householder rank-revealing QR decomposition of a matrix with full pivoting.
Definition FullPivHouseholderQR.h:50
FullPivHouseholderQR & setThreshold(Default_t)
Definition FullPivHouseholderQR.h:312
MatrixType::RealScalar absDeterminant() const
Definition FullPivHouseholderQR.h:364
MatrixQReturnType matrixQ(void) const
Definition FullPivHouseholderQR.h:576
MatrixType::RealScalar logAbsDeterminant() const
Definition FullPivHouseholderQR.h:372
RealScalar maxPivot() const
Definition FullPivHouseholderQR.h:347
FullPivHouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
Definition FullPivHouseholderQR.h:94
bool isInvertible() const
Definition FullPivHouseholderQR.h:257
bool isInjective() const
Definition FullPivHouseholderQR.h:232
const MatrixType & matrixQR() const
Definition FullPivHouseholderQR.h:148
Index rank() const
Definition FullPivHouseholderQR.h:203
FullPivHouseholderQR & setThreshold(const RealScalar &threshold)
Definition FullPivHouseholderQR.h:297
Index dimensionOfKernel() const
Definition FullPivHouseholderQR.h:219
FullPivHouseholderQR()
Default Constructor.
Definition FullPivHouseholderQR.h:78
bool isSurjective() const
Definition FullPivHouseholderQR.h:245
RealScalar threshold() const
Definition FullPivHouseholderQR.h:322
Index nonzeroPivots() const
Definition FullPivHouseholderQR.h:338
const internal::solve_retval< FullPivHouseholderQR, typename MatrixType::IdentityReturnType > inverse() const
Definition FullPivHouseholderQR.h:269
const internal::solve_retval< FullPivHouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
Definition FullPivHouseholderQR.h:136
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:50
const FullPivHouseholderQR< PlainObject > fullPivHouseholderQr() const
Definition FullPivHouseholderQR.h:588
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:129
Permutation matrix.
Definition PermutationMatrix.h:284
@ RowMajor
Definition Constants.h:259
Definition LDLT.h:18