Eigen  5.0.1
 
Loading...
Searching...
No Matches
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// SPDX-License-Identifier: MPL-2.0
11
12#ifndef EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
13#define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
14
15// IWYU pragma: private
16#include "./InternalHeaderCheck.h"
17
18namespace Eigen {
19
20namespace internal {
21
22template <typename MatrixType_, typename PermutationIndex_>
23struct traits<FullPivHouseholderQR<MatrixType_, PermutationIndex_> > : traits<MatrixType_> {
24 using XprKind = MatrixXpr;
25 using StorageKind = SolverStorage;
26 using PermutationIndex = PermutationIndex_;
27 enum { Flags = 0 };
28};
29
30template <typename MatrixType, typename PermutationIndex>
32
33template <typename MatrixType, typename PermutationIndex>
34struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType, PermutationIndex> > {
35 using ReturnType = typename MatrixType::PlainObject;
36};
37
38} // end namespace internal
39
64template <typename MatrixType_, typename PermutationIndex_>
65class FullPivHouseholderQR : public SolverBase<FullPivHouseholderQR<MatrixType_, PermutationIndex_> >,
66 public RankRevealingBase<FullPivHouseholderQR<MatrixType_, PermutationIndex_> > {
67 public:
68 using MatrixType = MatrixType_;
70 using RankRevealingBase_ = RankRevealingBase<FullPivHouseholderQR>;
71 friend class SolverBase<FullPivHouseholderQR>;
72 friend class RankRevealingBase<FullPivHouseholderQR>;
82 using PermutationIndex = PermutationIndex_;
83 EIGEN_GENERIC_PUBLIC_INTERFACE(FullPivHouseholderQR)
84
85 enum {
86 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
87 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
88 };
90 using HCoeffsType = typename internal::plain_diag_type<MatrixType>::type;
91 using IntDiagSizeVectorType =
92 Matrix<PermutationIndex, 1, internal::min_size_prefer_dynamic(ColsAtCompileTime, RowsAtCompileTime), RowMajor, 1,
93 internal::min_size_prefer_fixed(MaxColsAtCompileTime, MaxRowsAtCompileTime)>;
95 using RowVectorType = typename internal::plain_row_type<MatrixType>::type;
96 using ColVectorType = typename internal::plain_col_type<MatrixType>::type;
97 using PlainObject = typename MatrixType::PlainObject;
98
106 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
107 return Success;
108 }
109
116 : m_qr(),
117 m_hCoeffs(),
118 m_rows_transpositions(),
119 m_cols_transpositions(),
120 m_cols_permutation(),
121 m_temp(),
122 m_isInitialized(false) {}
123
131 : m_qr(rows, cols),
132 m_hCoeffs((std::min)(rows, cols)),
133 m_rows_transpositions((std::min)(rows, cols)),
134 m_cols_transpositions((std::min)(rows, cols)),
135 m_cols_permutation(cols),
136 m_temp(cols),
137 m_isInitialized(false) {}
138
151 template <typename InputType>
153 : m_qr(matrix.rows(), matrix.cols()),
154 m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
155 m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
156 m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
157 m_cols_permutation(matrix.cols()),
158 m_temp(matrix.cols()),
159 m_isInitialized(false) {
160 compute(matrix.derived());
161 }
162
170 template <typename InputType>
172 : m_qr(matrix.derived()),
173 m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
174 m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())),
175 m_cols_transpositions((std::min)(matrix.rows(), matrix.cols())),
176 m_cols_permutation(matrix.cols()),
177 m_temp(matrix.cols()),
178 m_isInitialized(false) {
179 computeInPlace();
180 }
181
182#ifdef EIGEN_PARSED_BY_DOXYGEN
201 template <typename Rhs>
203#endif
204
207 MatrixQReturnType matrixQ(void) const;
208
211 const MatrixType& matrixQR() const {
212 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
213 return m_qr;
214 }
215
216 template <typename InputType>
217 FullPivHouseholderQR& compute(const EigenBase<InputType>& matrix);
218
220 const PermutationType& colsPermutation() const {
221 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
222 return m_cols_permutation;
223 }
224
226 const IntDiagSizeVectorType& rowsTranspositions() const {
227 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
228 return m_rows_transpositions;
229 }
230
244 typename MatrixType::Scalar determinant() const;
245
259 typename MatrixType::RealScalar absDeterminant() const;
260
273 typename MatrixType::RealScalar logAbsDeterminant() const;
274
287 typename MatrixType::Scalar signDeterminant() const;
288
290 RealScalar pivotCoeff(Index i) const {
291 using std::abs;
292 return abs(m_qr.coeff(i, i));
293 }
294
301 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
302 return Inverse<FullPivHouseholderQR>(*this);
303 }
304
305 inline Index rows() const { return m_qr.rows(); }
306 inline Index cols() const { return m_qr.cols(); }
307
312 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
313
314#ifndef EIGEN_PARSED_BY_DOXYGEN
315 template <typename RhsType, typename DstType>
316 void _solve_impl(const RhsType& rhs, DstType& dst) const;
317
318 template <bool Conjugate, typename RhsType, typename DstType>
319 void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const;
320#endif
321
322 protected:
323 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
324
325 void computeInPlace();
326
327 MatrixType m_qr;
328 HCoeffsType m_hCoeffs;
329 IntDiagSizeVectorType m_rows_transpositions;
330 IntDiagSizeVectorType m_cols_transpositions;
331 PermutationType m_cols_permutation;
332 RowVectorType m_temp;
333 bool m_isInitialized;
334 RealScalar m_precision;
335 Index m_det_p;
336};
337
338template <typename MatrixType, typename PermutationIndex>
340 eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
341 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
342 Scalar detQ;
343 internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ);
344 return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().prod() : Scalar(0);
345}
346
347template <typename MatrixType, typename PermutationIndex>
349 using std::abs;
350 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
351 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
352 return isInjective() ? abs(m_qr.diagonal().prod()) : RealScalar(0);
353}
354
355template <typename MatrixType, typename PermutationIndex>
357 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
358 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
359 return isInjective() ? m_qr.diagonal().cwiseAbs().array().log().sum() : -NumTraits<RealScalar>::infinity();
360}
361
362template <typename MatrixType, typename PermutationIndex>
364 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
365 eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
366 Scalar detQ;
367 internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ);
368 return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().array().sign().prod() : Scalar(0);
369}
370
377template <typename MatrixType, typename PermutationIndex>
378template <typename InputType>
379FullPivHouseholderQR<MatrixType, PermutationIndex>& FullPivHouseholderQR<MatrixType, PermutationIndex>::compute(
380 const EigenBase<InputType>& matrix) {
381 m_qr = matrix.derived();
382 computeInPlace();
383 return *this;
384}
385
386template <typename MatrixType, typename PermutationIndex>
387void FullPivHouseholderQR<MatrixType, PermutationIndex>::computeInPlace() {
388 eigen_assert(m_qr.cols() <= NumTraits<PermutationIndex>::highest());
389 using std::abs;
390 Index rows = m_qr.rows();
391 Index cols = m_qr.cols();
392 Index size = (std::min)(rows, cols);
393
394 m_hCoeffs.resize(size);
395
396 m_temp.resize(cols);
397
398 m_precision = NumTraits<Scalar>::epsilon() * RealScalar(size);
399
400 m_rows_transpositions.resize(size);
401 m_cols_transpositions.resize(size);
402 Index number_of_transpositions = 0;
403
404 RealScalar biggest(0);
405
406 this->m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
407 this->m_maxpivot = RealScalar(0);
408
409 for (Index k = 0; k < size; ++k) {
410 Index row_of_biggest_in_corner, col_of_biggest_in_corner;
411 using Scoring = internal::scalar_score_coeff_op<Scalar>;
412 using Score = typename Scoring::result_type;
413
414 Score score = m_qr.bottomRightCorner(rows - k, cols - k)
415 .unaryExpr(Scoring())
416 .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
417 row_of_biggest_in_corner += k;
418 col_of_biggest_in_corner += k;
419 RealScalar biggest_in_corner =
420 internal::abs_knowing_score<Scalar>()(m_qr(row_of_biggest_in_corner, col_of_biggest_in_corner), score);
421 if (k == 0) biggest = biggest_in_corner;
422
423 // if the corner is negligible, then we have less than full rank, and we can finish early
424 if (internal::isMuchSmallerThan(biggest_in_corner, biggest, m_precision)) {
425 this->m_nonzero_pivots = k;
426 for (Index i = k; i < size; i++) {
427 m_rows_transpositions.coeffRef(i) = internal::convert_index<PermutationIndex>(i);
428 m_cols_transpositions.coeffRef(i) = internal::convert_index<PermutationIndex>(i);
429 m_hCoeffs.coeffRef(i) = Scalar(0);
430 }
431 break;
432 }
433
434 m_rows_transpositions.coeffRef(k) = internal::convert_index<PermutationIndex>(row_of_biggest_in_corner);
435 m_cols_transpositions.coeffRef(k) = internal::convert_index<PermutationIndex>(col_of_biggest_in_corner);
436 if (k != row_of_biggest_in_corner) {
437 m_qr.row(k).tail(cols - k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols - k));
438 ++number_of_transpositions;
439 }
440 if (k != col_of_biggest_in_corner) {
441 m_qr.col(k).swap(m_qr.col(col_of_biggest_in_corner));
442 ++number_of_transpositions;
443 }
444
445 RealScalar beta;
446 m_qr.col(k).tail(rows - k).makeHouseholderInPlace(m_hCoeffs.coeffRef(k), beta);
447 m_qr.coeffRef(k, k) = beta;
448
449 // remember the maximum absolute value of diagonal coefficients
450 if (abs(beta) > this->m_maxpivot) this->m_maxpivot = abs(beta);
451
452 m_qr.bottomRightCorner(rows - k, cols - k - 1)
453 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows - k - 1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k + 1));
454 }
455
456 m_cols_permutation.setIdentity(cols);
457 for (Index k = 0; k < size; ++k) m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));
458
459 m_det_p = (number_of_transpositions % 2) ? -1 : 1;
460 m_isInitialized = true;
461}
462
463#ifndef EIGEN_PARSED_BY_DOXYGEN
464template <typename MatrixType_, typename PermutationIndex_>
465template <typename RhsType, typename DstType>
466void FullPivHouseholderQR<MatrixType_, PermutationIndex_>::_solve_impl(const RhsType& rhs, DstType& dst) const {
467 const Index l_rank = rank();
468
469 // FIXME: introduce nonzeroPivots() and apply the same improvements as in FullPivLU.
470 if (l_rank == 0) {
471 dst.setZero();
472 return;
473 }
474
475 typename RhsType::PlainObject c(rhs);
476
478 for (Index k = 0; k < l_rank; ++k) {
479 Index remainingSize = rows() - k;
480 c.row(k).swap(c.row(m_rows_transpositions.coeff(k)));
481 c.bottomRightCorner(remainingSize, rhs.cols())
482 .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize - 1), m_hCoeffs.coeff(k), &temp.coeffRef(0));
483 }
484
485 m_qr.topLeftCorner(l_rank, l_rank).template triangularView<Upper>().solveInPlace(c.topRows(l_rank));
486
487 for (Index i = 0; i < l_rank; ++i) dst.row(m_cols_permutation.indices().coeff(i)) = c.row(i);
488 for (Index i = l_rank; i < cols(); ++i) dst.row(m_cols_permutation.indices().coeff(i)).setZero();
489}
490
491template <typename MatrixType_, typename PermutationIndex_>
492template <bool Conjugate, typename RhsType, typename DstType>
494 DstType& dst) const {
495 const Index l_rank = rank();
496
497 if (l_rank == 0) {
498 dst.setZero();
499 return;
500 }
501
502 typename RhsType::PlainObject c(m_cols_permutation.transpose() * rhs);
503
504 m_qr.topLeftCorner(l_rank, l_rank)
505 .template triangularView<Upper>()
506 .transpose()
507 .template conjugateIf<Conjugate>()
508 .solveInPlace(c.topRows(l_rank));
509
510 dst.topRows(l_rank) = c.topRows(l_rank);
511 dst.bottomRows(rows() - l_rank).setZero();
512
514 const Index size = (std::min)(rows(), cols());
515 for (Index k = size - 1; k >= 0; --k) {
516 Index remainingSize = rows() - k;
517
518 dst.bottomRightCorner(remainingSize, dst.cols())
519 .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize - 1).template conjugateIf<!Conjugate>(),
520 m_hCoeffs.template conjugateIf<Conjugate>().coeff(k), &temp.coeffRef(0));
521
522 dst.row(k).swap(dst.row(m_rows_transpositions.coeff(k)));
523 }
524}
525#endif
526
527namespace internal {
528
529template <typename DstXprType, typename MatrixType, typename PermutationIndex>
530struct Assignment<DstXprType, Inverse<FullPivHouseholderQR<MatrixType, PermutationIndex> >,
531 internal::assign_op<typename DstXprType::Scalar,
532 typename FullPivHouseholderQR<MatrixType, PermutationIndex>::Scalar>,
533 Dense2Dense> {
534 using QrType = FullPivHouseholderQR<MatrixType, PermutationIndex>;
535 using SrcXprType = Inverse<QrType>;
536 static void run(DstXprType& dst, const SrcXprType& src,
537 const internal::assign_op<typename DstXprType::Scalar, typename QrType::Scalar>&) {
538 dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols()));
539 }
540};
541
548template <typename MatrixType, typename PermutationIndex>
549struct FullPivHouseholderQRMatrixQReturnType
550 : public ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType, PermutationIndex> > {
551 public:
552 using IntDiagSizeVectorType = typename FullPivHouseholderQR<MatrixType, PermutationIndex>::IntDiagSizeVectorType;
553 using HCoeffsType = typename internal::plain_diag_type<MatrixType>::type;
554 using WorkVectorType = Matrix<typename MatrixType::Scalar, 1, MatrixType::RowsAtCompileTime, RowMajor, 1,
555 MatrixType::MaxRowsAtCompileTime>;
556
557 FullPivHouseholderQRMatrixQReturnType(const MatrixType& qr, const HCoeffsType& hCoeffs,
558 const IntDiagSizeVectorType& rowsTranspositions)
559 : m_qr(qr), m_hCoeffs(hCoeffs), m_rowsTranspositions(rowsTranspositions) {}
560
561 template <typename ResultType>
562 void evalTo(ResultType& result) const {
563 const Index rows = m_qr.rows();
564 WorkVectorType workspace(rows);
565 evalTo(result, workspace);
566 }
567
568 template <typename ResultType>
569 void evalTo(ResultType& result, WorkVectorType& workspace) const {
570 using numext::conj;
571 // compute the product H'_0 H'_1 ... H'_n-1,
572 // where H_k is the k-th Householder transformation I - h_k v_k v_k'
573 // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
574 const Index rows = m_qr.rows();
575 const Index cols = m_qr.cols();
576 const Index size = (std::min)(rows, cols);
577 workspace.resize(rows);
578 result.setIdentity(rows, rows);
579 for (Index k = size - 1; k >= 0; k--) {
580 result.block(k, k, rows - k, rows - k)
581 .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows - k - 1), conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k));
582 result.row(k).swap(result.row(m_rowsTranspositions.coeff(k)));
583 }
584 }
585
586 Index rows() const { return m_qr.rows(); }
587 Index cols() const { return m_qr.rows(); }
588
589 protected:
590 typename MatrixType::Nested m_qr;
591 typename HCoeffsType::Nested m_hCoeffs;
592 typename IntDiagSizeVectorType::Nested m_rowsTranspositions;
593};
594
595} // end namespace internal
596
597template <typename MatrixType, typename PermutationIndex>
598inline typename FullPivHouseholderQR<MatrixType, PermutationIndex>::MatrixQReturnType
600 eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
601 return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions);
602}
603
608template <typename Derived>
609template <typename PermutationIndex>
611MatrixBase<Derived>::fullPivHouseholderQr() const {
613}
614
615} // end namespace Eigen
616
617#endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H
EvalReturnType eval() const
Definition DenseBase.h:385
Householder rank-revealing QR decomposition of a matrix with full pivoting.
Definition FullPivHouseholderQR.h:66
const MatrixType & matrixQR() const
Definition FullPivHouseholderQR.h:211
ComputationInfo info() const
Reports whether the QR factorization was successful.
Definition FullPivHouseholderQR.h:105
MatrixQReturnType matrixQ(void) const
Definition FullPivHouseholderQR.h:599
Inverse< FullPivHouseholderQR > inverse() const
Definition FullPivHouseholderQR.h:300
Solve< FullPivHouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
MatrixType::RealScalar logAbsDeterminant() const
Definition FullPivHouseholderQR.h:356
const PermutationType & colsPermutation() const
Definition FullPivHouseholderQR.h:220
const IntDiagSizeVectorType & rowsTranspositions() const
Definition FullPivHouseholderQR.h:226
MatrixType::Scalar determinant() const
Definition FullPivHouseholderQR.h:339
FullPivHouseholderQR()
Default Constructor.
Definition FullPivHouseholderQR.h:115
const HCoeffsType & hCoeffs() const
Definition FullPivHouseholderQR.h:312
MatrixType::RealScalar absDeterminant() const
Definition FullPivHouseholderQR.h:348
FullPivHouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
Definition FullPivHouseholderQR.h:130
bool isInjective() const
Definition RankRevealingBase.h:122
FullPivHouseholderQR(const EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
Definition FullPivHouseholderQR.h:152
RealScalar pivotCoeff(Index i) const
Definition FullPivHouseholderQR.h:290
FullPivHouseholderQR(EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
Definition FullPivHouseholderQR.h:171
MatrixType::Scalar signDeterminant() const
Definition FullPivHouseholderQR.h:363
Expression of the inverse of another expression.
Definition Inverse.h:44
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
constexpr Scalar & coeffRef(Index rowId, Index colId)
Definition PlainObjectBase.h:205
Permutation matrix.
Definition PermutationMatrix.h:346
constexpr void resize(Index rows, Index cols)
Definition PlainObjectBase.h:282
Index dimensionOfKernel() const
Definition RankRevealingBase.h:110
bool isInjective() const
Definition RankRevealingBase.h:122
bool isSurjective() const
Definition RankRevealingBase.h:134
FullPivHouseholderQR & 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
@ RowMajor
Definition Constants.h:321
Definition EigenBase.h:34
constexpr Derived & derived()
Definition EigenBase.h:50
Eigen::Index Index
The interface type of indices.
Definition EigenBase.h:44
Expression type for return value of FullPivHouseholderQR::matrixQ()
Definition FullPivHouseholderQR.h:550