Eigen  5.0.1
 
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// SPDX-License-Identifier: MPL-2.0
11
12#ifndef EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
13#define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
14
15// IWYU pragma: private
16#include "./InternalHeaderCheck.h"
17
18namespace Eigen {
19
20namespace internal {
21template <typename MatrixType_, typename PermutationIndex_>
22struct traits<ColPivHouseholderQR<MatrixType_, PermutationIndex_>> : traits<MatrixType_> {
23 using XprKind = MatrixXpr;
24 using StorageKind = SolverStorage;
25 using PermutationIndex = PermutationIndex_;
26 enum { Flags = 0 };
27};
28
29} // end namespace internal
30
54template <typename MatrixType_, typename PermutationIndex_>
55class ColPivHouseholderQR : public SolverBase<ColPivHouseholderQR<MatrixType_, PermutationIndex_>>,
56 public RankRevealingBase<ColPivHouseholderQR<MatrixType_, PermutationIndex_>> {
57 public:
58 using MatrixType = MatrixType_;
60 using RankRevealingBase_ = RankRevealingBase<ColPivHouseholderQR>;
61 friend class SolverBase<ColPivHouseholderQR>;
62 friend class RankRevealingBase<ColPivHouseholderQR>;
72 using PermutationIndex = PermutationIndex_;
73 EIGEN_GENERIC_PUBLIC_INTERFACE(ColPivHouseholderQR)
74
75 enum {
76 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
77 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
78 };
79 using HCoeffsType = typename internal::plain_diag_type<MatrixType>::type;
81 using IntRowVectorType = typename internal::plain_row_type<MatrixType, PermutationIndex>::type;
82 using RowVectorType = typename internal::plain_row_type<MatrixType>::type;
83 using RealRowVectorType = typename internal::plain_row_type<MatrixType, RealScalar>::type;
84 using HouseholderSequenceType =
86 using PlainObject = typename MatrixType::PlainObject;
87
88 private:
89 void init(Index rows, Index cols) {
90 Index diag = numext::mini(rows, cols);
91 m_hCoeffs.resize(diag);
92 m_colsPermutation.resize(cols);
93 m_colsTranspositions.resize(cols);
94 m_temp.resize(cols);
95 m_colNormsUpdated.resize(cols);
96 m_colNormsDirect.resize(cols);
97 m_isInitialized = false;
98 }
99
100 public:
108 : m_qr(),
109 m_hCoeffs(),
110 m_colsPermutation(),
111 m_colsTranspositions(),
112 m_temp(),
113 m_colNormsUpdated(),
114 m_colNormsDirect(),
115 m_isInitialized(false) {}
116
123 ColPivHouseholderQR(Index rows, Index cols) : m_qr(rows, cols) { init(rows, cols); }
124
137 template <typename InputType>
138 explicit ColPivHouseholderQR(const EigenBase<InputType>& matrix) : m_qr(matrix.rows(), matrix.cols()) {
139 init(matrix.rows(), matrix.cols());
140 compute(matrix.derived());
141 }
142
150 template <typename InputType>
151 explicit ColPivHouseholderQR(EigenBase<InputType>& matrix) : m_qr(matrix.derived()) {
152 init(matrix.rows(), matrix.cols());
153 computeInPlace();
154 }
155
156#ifdef EIGEN_PARSED_BY_DOXYGEN
171 template <typename Rhs>
173#endif
174
175 HouseholderSequenceType householderQ() const;
176 HouseholderSequenceType matrixQ() const { return householderQ(); }
177
180 const MatrixType& matrixQR() const {
181 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
182 return m_qr;
183 }
184
194 const MatrixType& matrixR() const {
195 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
196 return m_qr;
197 }
198
199 template <typename InputType>
200 ColPivHouseholderQR& compute(const EigenBase<InputType>& matrix);
201
203 const PermutationType& colsPermutation() const {
204 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
205 return m_colsPermutation;
206 }
207
221 typename MatrixType::Scalar determinant() const;
222
236 typename MatrixType::RealScalar absDeterminant() const;
237
250 typename MatrixType::RealScalar logAbsDeterminant() const;
251
264 typename MatrixType::Scalar signDeterminant() const;
265
267 RealScalar pivotCoeff(Index i) const {
268 using std::abs;
269 return abs(m_qr.coeff(i, i));
270 }
271
278 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
279 return Inverse<ColPivHouseholderQR>(*this);
280 }
281
282 inline Index rows() const { return m_qr.rows(); }
283 inline Index cols() const { return m_qr.cols(); }
284
289 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
290
298 eigen_assert(m_isInitialized && "Decomposition is not initialized.");
299 return Success;
300 }
301
302#ifndef EIGEN_PARSED_BY_DOXYGEN
303 template <typename RhsType, typename DstType>
304 void _solve_impl(const RhsType& rhs, DstType& dst) const;
305
306 template <bool Conjugate, typename RhsType, typename DstType>
307 void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const;
308#endif
309
310 protected:
311 friend class internal::CompleteOrthogonalDecompositionImpl<MatrixType, PermutationIndex, ColPivHouseholderQR>;
312
313 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
314
315 void computeInPlace();
316
317 MatrixType m_qr;
318 HCoeffsType m_hCoeffs;
319 PermutationType m_colsPermutation;
320 IntRowVectorType m_colsTranspositions;
321 RowVectorType m_temp;
322 RealRowVectorType m_colNormsUpdated;
323 RealRowVectorType m_colNormsDirect;
324 bool m_isInitialized;
325 Index m_det_p;
326};
327
328template <typename MatrixType, typename PermutationIndex>
330 eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
331 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
332 Scalar detQ;
333 internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ);
334 return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().prod() : Scalar(0);
335}
336
337template <typename MatrixType, typename PermutationIndex>
339 using std::abs;
340 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
341 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
342 return isInjective() ? abs(m_qr.diagonal().prod()) : RealScalar(0);
343}
344
345template <typename MatrixType, typename PermutationIndex>
347 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
348 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
349 return isInjective() ? m_qr.diagonal().cwiseAbs().array().log().sum() : -NumTraits<RealScalar>::infinity();
350}
351
352template <typename MatrixType, typename PermutationIndex>
354 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
355 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
356 Scalar detQ;
357 internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ);
358 return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().array().sign().prod() : Scalar(0);
359}
360
367template <typename MatrixType, typename PermutationIndex>
368template <typename InputType>
369ColPivHouseholderQR<MatrixType, PermutationIndex>& ColPivHouseholderQR<MatrixType, PermutationIndex>::compute(
370 const EigenBase<InputType>& matrix) {
371 m_qr = matrix.derived();
372 computeInPlace();
373 return *this;
374}
375
376template <typename MatrixType, typename PermutationIndex>
377void ColPivHouseholderQR<MatrixType, PermutationIndex>::computeInPlace() {
378 eigen_assert(m_qr.cols() <= NumTraits<PermutationIndex>::highest());
379
380 using std::abs;
381
382 Index rows = m_qr.rows();
383 Index cols = m_qr.cols();
384 Index size = m_qr.diagonalSize();
385
386 m_hCoeffs.resize(size);
387
388 m_temp.resize(cols);
389
390 m_colsTranspositions.resize(m_qr.cols());
391 Index number_of_transpositions = 0;
392
393 // m_colNormsDirect caches the most recent directly computed column norms.
394 m_colNormsDirect = m_qr.colwise().norm();
395 m_colNormsUpdated = m_colNormsDirect;
396
397 RealScalar threshold_helper =
398 cols == 0 ? RealScalar(0)
399 : numext::abs2<RealScalar>(m_colNormsUpdated.maxCoeff() * NumTraits<RealScalar>::epsilon()) /
400 RealScalar(rows);
401 RealScalar norm_downdate_threshold = numext::sqrt(NumTraits<RealScalar>::epsilon());
402
403 this->m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
404 this->m_maxpivot = RealScalar(0);
405
406 for (Index k = 0; k < size; ++k) {
407 // first, we look up in our table m_colNormsUpdated which column has the biggest norm
408 Index biggest_col_index;
409 RealScalar biggest_col_sq_norm = numext::abs2(m_colNormsUpdated.tail(cols - k).maxCoeff(&biggest_col_index));
410 biggest_col_index += k;
411
412 // Track the number of meaningful pivots but do not stop the decomposition to make
413 // sure that the initial matrix is properly reproduced. See bug 941.
414 if (this->m_nonzero_pivots == size && biggest_col_sq_norm < threshold_helper * RealScalar(rows - k))
415 this->m_nonzero_pivots = k;
416
417 // apply the transposition to the columns
418 m_colsTranspositions.coeffRef(k) = static_cast<PermutationIndex>(biggest_col_index);
419 if (k != biggest_col_index) {
420 m_qr.col(k).swap(m_qr.col(biggest_col_index));
421 std::swap(m_colNormsUpdated.coeffRef(k), m_colNormsUpdated.coeffRef(biggest_col_index));
422 std::swap(m_colNormsDirect.coeffRef(k), m_colNormsDirect.coeffRef(biggest_col_index));
423 ++number_of_transpositions;
424 }
425
426 // generate the householder vector, store it below the diagonal
427 RealScalar beta;
428 m_qr.col(k).tail(rows - k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
429
430 // apply the householder transformation to the diagonal coefficient
431 m_qr.coeffRef(k, k) = beta;
432
433 // remember the maximum absolute value of diagonal coefficients
434 if (abs(beta) > this->m_maxpivot) this->m_maxpivot = abs(beta);
435
436 // apply the householder transformation
437 m_qr.bottomRightCorner(rows - k, cols - k - 1)
438 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows - k - 1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k + 1));
439
440 // update our table of norms of the columns
441 for (Index j = k + 1; j < cols; ++j) {
442 // The following implements the stable norm downgrade step discussed in
443 // http://www.netlib.org/lapack/lawnspdf/lawn176.pdf
444 // and used in LAPACK routines xGEQPF and xGEQP3.
445 // See lines 278-297 in http://www.netlib.org/lapack/explore-html/dc/df4/sgeqpf_8f_source.html
446 if (!numext::is_exactly_zero(m_colNormsUpdated.coeffRef(j))) {
447 RealScalar temp = abs(m_qr.coeffRef(k, j)) / m_colNormsUpdated.coeffRef(j);
448 temp = (RealScalar(1) + temp) * (RealScalar(1) - temp);
449 temp = temp < RealScalar(0) ? RealScalar(0) : temp;
450 RealScalar temp2 =
451 temp * numext::abs2<RealScalar>(m_colNormsUpdated.coeffRef(j) / m_colNormsDirect.coeffRef(j));
452 if (temp2 <= norm_downdate_threshold) {
453 // The updated norm has become too inaccurate so re-compute the column
454 // norm directly.
455 m_colNormsDirect.coeffRef(j) = m_qr.col(j).tail(rows - k - 1).norm();
456 m_colNormsUpdated.coeffRef(j) = m_colNormsDirect.coeffRef(j);
457 } else {
458 m_colNormsUpdated.coeffRef(j) *= numext::sqrt(temp);
459 }
460 }
461 }
462 }
463
464 m_colsPermutation.setIdentity(cols);
465 for (Index k = 0; k < size; ++k)
466 m_colsPermutation.applyTranspositionOnTheRight(k, static_cast<Index>(m_colsTranspositions.coeff(k)));
467
468 m_det_p = (number_of_transpositions % 2) ? -1 : 1;
469 m_isInitialized = true;
470}
471
472#ifndef EIGEN_PARSED_BY_DOXYGEN
473template <typename MatrixType_, typename PermutationIndex_>
474template <typename RhsType, typename DstType>
475void ColPivHouseholderQR<MatrixType_, PermutationIndex_>::_solve_impl(const RhsType& rhs, DstType& dst) const {
476 const Index nonzero_pivots = nonzeroPivots();
477
478 if (nonzero_pivots == 0) {
479 dst.setZero();
480 return;
481 }
482
483 typename RhsType::PlainObject c(rhs);
484
485 c.applyOnTheLeft(householderQ().setLength(nonzero_pivots).adjoint());
486
487 m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
488 .template triangularView<Upper>()
489 .solveInPlace(c.topRows(nonzero_pivots));
490
491 for (Index i = 0; i < nonzero_pivots; ++i) dst.row(m_colsPermutation.indices().coeff(i)) = c.row(i);
492 for (Index i = nonzero_pivots; i < cols(); ++i) dst.row(m_colsPermutation.indices().coeff(i)).setZero();
493}
494
495template <typename MatrixType_, typename PermutationIndex_>
496template <bool Conjugate, typename RhsType, typename DstType>
498 DstType& dst) const {
499 const Index nonzero_pivots = nonzeroPivots();
500
501 if (nonzero_pivots == 0) {
502 dst.setZero();
503 return;
504 }
505
506 typename RhsType::PlainObject c(m_colsPermutation.transpose() * rhs);
507
508 m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
509 .template triangularView<Upper>()
510 .transpose()
511 .template conjugateIf<Conjugate>()
512 .solveInPlace(c.topRows(nonzero_pivots));
513
514 dst.topRows(nonzero_pivots) = c.topRows(nonzero_pivots);
515 dst.bottomRows(rows() - nonzero_pivots).setZero();
516
517 dst.applyOnTheLeft(householderQ().setLength(nonzero_pivots).template conjugateIf<!Conjugate>());
518}
519#endif
520
521namespace internal {
522
523template <typename DstXprType, typename MatrixType, typename PermutationIndex>
524struct Assignment<DstXprType, Inverse<ColPivHouseholderQR<MatrixType, PermutationIndex>>,
525 internal::assign_op<typename DstXprType::Scalar,
526 typename ColPivHouseholderQR<MatrixType, PermutationIndex>::Scalar>,
527 Dense2Dense> {
528 using QrType = ColPivHouseholderQR<MatrixType, PermutationIndex>;
529 using SrcXprType = Inverse<QrType>;
530 static void run(DstXprType& dst, const SrcXprType& src,
531 const internal::assign_op<typename DstXprType::Scalar, typename QrType::Scalar>&) {
532 dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
533 }
534};
535
536} // end namespace internal
537
541template <typename MatrixType, typename PermutationIndex>
542typename ColPivHouseholderQR<MatrixType, PermutationIndex>::HouseholderSequenceType
544 eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
545 return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
546}
547
552template <typename Derived>
553template <typename PermutationIndexType>
555MatrixBase<Derived>::colPivHouseholderQr() const {
557}
558
559} // end namespace Eigen
560
561#endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H
Householder rank-revealing QR decomposition of a matrix with column-pivoting.
Definition ColPivHouseholderQR.h:56
Solve< ColPivHouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
RealScalar pivotCoeff(Index i) const
Definition ColPivHouseholderQR.h:267
const HCoeffsType & hCoeffs() const
Definition ColPivHouseholderQR.h:289
MatrixType::Scalar signDeterminant() const
Definition ColPivHouseholderQR.h:353
MatrixType::RealScalar absDeterminant() const
Definition ColPivHouseholderQR.h:338
ColPivHouseholderQR(EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
Definition ColPivHouseholderQR.h:151
bool isInjective() const
Definition RankRevealingBase.h:122
const PermutationType & colsPermutation() const
Definition ColPivHouseholderQR.h:203
const MatrixType & matrixQR() const
Definition ColPivHouseholderQR.h:180
ComputationInfo info() const
Reports whether the QR factorization was successful.
Definition ColPivHouseholderQR.h:297
ColPivHouseholderQR()
Default Constructor.
Definition ColPivHouseholderQR.h:107
HouseholderSequenceType householderQ() const
Definition ColPivHouseholderQR.h:543
MatrixType::Scalar determinant() const
Definition ColPivHouseholderQR.h:329
MatrixType::RealScalar logAbsDeterminant() const
Definition ColPivHouseholderQR.h:346
ColPivHouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
Definition ColPivHouseholderQR.h:123
const MatrixType & matrixR() const
Definition ColPivHouseholderQR.h:194
Inverse< ColPivHouseholderQR > inverse() const
Definition ColPivHouseholderQR.h:277
ColPivHouseholderQR(const EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
Definition ColPivHouseholderQR.h:138
EvalReturnType eval() const
Definition DenseBase.h:385
Sequence of Householder reflections acting on subspaces with decreasing size.
Definition HouseholderSequence.h:140
Expression of the inverse of another expression.
Definition Inverse.h:44
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
Permutation matrix.
Definition PermutationMatrix.h:346
Index dimensionOfKernel() const
Definition RankRevealingBase.h:110
bool isInjective() const
Definition RankRevealingBase.h:122
bool isSurjective() const
Definition RankRevealingBase.h:134
ColPivHouseholderQR & setThreshold(const RealScalar &threshold)
Definition RankRevealingBase.h:57
Index nonzeroPivots() const
Definition RankRevealingBase.h:157
RealScalar threshold() const
Definition RankRevealingBase.h:80
RealScalar maxPivot() const
Definition RankRevealingBase.h:165
Index rank() const
Definition RankRevealingBase.h:95
bool isInvertible() const
Definition RankRevealingBase.h:145
Pseudo expression representing a solving operation.
Definition Solve.h:63
constexpr Derived & derived()
Definition EigenBase.h:50
ComputationInfo
Definition Constants.h:455
@ Success
Definition Constants.h:457
Definition EigenBase.h:34
constexpr Index cols() const noexcept
Definition EigenBase.h:62
constexpr Derived & derived()
Definition EigenBase.h:50
constexpr Index rows() const noexcept
Definition EigenBase.h:60
Eigen::Index Index
The interface type of indices.
Definition EigenBase.h:44
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition NumTraits.h:233