Eigen  5.0.1
 
Loading...
Searching...
No Matches
HouseholderQR.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
5// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
6// Copyright (C) 2010 Vincent Lejeune
7//
8// This Source Code Form is subject to the terms of the Mozilla
9// Public License v. 2.0. If a copy of the MPL was not distributed
10// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
11// SPDX-License-Identifier: MPL-2.0
12
13#ifndef EIGEN_QR_H
14#define EIGEN_QR_H
15
16// IWYU pragma: private
17#include "./InternalHeaderCheck.h"
18
19namespace Eigen {
20
21namespace internal {
22template <typename MatrixType_>
23struct traits<HouseholderQR<MatrixType_>> : traits<MatrixType_> {
24 using XprKind = MatrixXpr;
25 using StorageKind = SolverStorage;
26 using StorageIndex = int;
27 enum { Flags = 0 };
28};
29
30} // end namespace internal
31
76template <typename MatrixType_>
77class HouseholderQR : public SolverBase<HouseholderQR<MatrixType_>> {
78 public:
79 using MatrixType = MatrixType_;
80 using Base = SolverBase<HouseholderQR>;
81 friend class SolverBase<HouseholderQR>;
82
83 EIGEN_GENERIC_PUBLIC_INTERFACE(HouseholderQR)
84 enum {
85 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
86 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
87 };
88 using MatrixQType =
89 Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, (MatrixType::Flags & RowMajorBit) ? RowMajor : ColMajor,
90 MaxRowsAtCompileTime, MaxRowsAtCompileTime>;
91 using HCoeffsType = typename internal::plain_diag_type<MatrixType>::type;
92 using RowVectorType = typename internal::plain_row_type<MatrixType>::type;
93 using HouseholderSequenceType =
95
103 eigen_assert(m_isInitialized && "HouseHolderQR is not initialized.");
104 return Success;
105 }
106
113 HouseholderQR() : m_qr(), m_hCoeffs(), m_temp(), m_isInitialized(false) {}
114
122 : m_qr(rows, cols), m_hCoeffs((std::min)(rows, cols)), m_temp(cols), m_isInitialized(false) {}
123
136 template <typename InputType>
137 explicit HouseholderQR(const EigenBase<InputType>& matrix)
138 : m_qr(matrix.rows(), matrix.cols()),
139 m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
140 m_temp(matrix.cols()),
141 m_isInitialized(false) {
142 compute(matrix.derived());
143 }
144
152 template <typename InputType>
154 : m_qr(matrix.derived()),
155 m_hCoeffs((std::min)(matrix.rows(), matrix.cols())),
156 m_temp(matrix.cols()),
157 m_isInitialized(false) {
159 }
160
161#ifdef EIGEN_PARSED_BY_DOXYGEN
176 template <typename Rhs>
178#endif
179
189 HouseholderSequenceType householderQ() const {
190 eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
191 return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
192 }
193
197 const MatrixType& matrixQR() const {
198 eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
199 return m_qr;
200 }
201
202 template <typename InputType>
203 HouseholderQR& compute(const EigenBase<InputType>& matrix) {
204 m_qr = matrix.derived();
206 return *this;
207 }
208
224 typename MatrixType::Scalar determinant() const;
225
241 typename MatrixType::RealScalar absDeterminant() const;
242
258 typename MatrixType::RealScalar logAbsDeterminant() const;
259
275 typename MatrixType::Scalar signDeterminant() const;
276
277 inline Index rows() const { return m_qr.rows(); }
278 inline Index cols() const { return m_qr.cols(); }
279
284 const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
285
286#ifndef EIGEN_PARSED_BY_DOXYGEN
287 template <typename RhsType, typename DstType>
288 void _solve_impl(const RhsType& rhs, DstType& dst) const;
289
290 template <bool Conjugate, typename RhsType, typename DstType>
291 void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const;
292#endif
293
294 protected:
295 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
296
298
299 MatrixType m_qr;
300 HCoeffsType m_hCoeffs;
301 RowVectorType m_temp;
302 bool m_isInitialized;
303};
304
305namespace internal {
306
308template <typename HCoeffs, typename Scalar, bool IsComplex>
309struct householder_determinant {
310 static void run(const HCoeffs& hCoeffs, Scalar& out_det) {
311 out_det = Scalar(1);
312 Index size = hCoeffs.rows();
313 for (Index i = 0; i < size; i++) {
314 // For each valid reflection Q_n,
315 // det(Q_n) = - conj(h_n) / h_n
316 // where h_n is the Householder coefficient.
317 if (hCoeffs(i) != Scalar(0)) out_det *= -numext::conj(hCoeffs(i)) / hCoeffs(i);
318 }
319 }
320};
321
323template <typename HCoeffs, typename Scalar>
324struct householder_determinant<HCoeffs, Scalar, false> {
325 static void run(const HCoeffs& hCoeffs, Scalar& out_det) {
326 bool negated = false;
327 Index size = hCoeffs.rows();
328 for (Index i = 0; i < size; i++) {
329 // Each valid reflection negates the determinant.
330 if (hCoeffs(i) != Scalar(0)) negated ^= true;
331 }
332 out_det = negated ? Scalar(-1) : Scalar(1);
333 }
334};
335
336} // end namespace internal
337
338template <typename MatrixType>
339typename MatrixType::Scalar HouseholderQR<MatrixType>::determinant() const {
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 m_qr.diagonal().prod() * detQ;
345}
346
347template <typename MatrixType>
348typename MatrixType::RealScalar HouseholderQR<MatrixType>::absDeterminant() const {
349 using std::abs;
350 eigen_assert(m_isInitialized && "HouseholderQR 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 abs(m_qr.diagonal().prod());
353}
354
355template <typename MatrixType>
356typename MatrixType::RealScalar HouseholderQR<MatrixType>::logAbsDeterminant() const {
357 eigen_assert(m_isInitialized && "HouseholderQR 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 m_qr.diagonal().cwiseAbs().array().log().sum();
360}
361
362template <typename MatrixType>
363typename MatrixType::Scalar HouseholderQR<MatrixType>::signDeterminant() const {
364 eigen_assert(m_isInitialized && "HouseholderQR 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 detQ * m_qr.diagonal().array().sign().prod();
369}
370
371namespace internal {
374template <typename MatrixQR, typename HCoeffs>
375void householder_qr_inplace_unblocked(MatrixQR& mat, HCoeffs& hCoeffs, typename MatrixQR::Scalar* tempData = 0) {
376 using Scalar = typename MatrixQR::Scalar;
377 using RealScalar = typename MatrixQR::RealScalar;
378 Index rows = mat.rows();
379 Index cols = mat.cols();
380 Index size = (std::min)(rows, cols);
381
382 eigen_assert(hCoeffs.size() == size);
383
385 TempType tempVector;
386 if (tempData == 0) {
387 tempVector.resize(cols);
388 tempData = tempVector.data();
389 }
390
391 for (Index k = 0; k < size; ++k) {
392 Index remainingRows = rows - k;
393 Index remainingCols = cols - k - 1;
394
395 RealScalar beta;
396 mat.col(k).tail(remainingRows).makeHouseholderInPlace(hCoeffs.coeffRef(k), beta);
397 mat.coeffRef(k, k) = beta;
398
399 // apply H to remaining part of mat from the left
400 mat.bottomRightCorner(remainingRows, remainingCols)
401 .applyHouseholderOnTheLeft(mat.col(k).tail(remainingRows - 1), hCoeffs.coeffRef(k), tempData + k + 1);
402 }
403}
404
418template <typename MatrixQR, typename HCoeffs, typename VectorQR>
419void householder_qr_inplace_update(MatrixQR& mat, HCoeffs& hCoeffs, const VectorQR& newColumn,
420 typename MatrixQR::Index k, typename MatrixQR::Scalar* tempData) {
421 using Index = typename MatrixQR::Index;
422 using RealScalar = typename MatrixQR::RealScalar;
423 Index rows = mat.rows();
424
425 eigen_assert(k < mat.cols());
426 eigen_assert(k < rows);
427 eigen_assert(hCoeffs.size() == mat.cols());
428 eigen_assert(newColumn.size() == rows);
429 eigen_assert(tempData);
430
431 // Store new column in mat at column k
432 mat.col(k) = newColumn;
433 // Apply H = H_1...H_{k-1} on newColumn (skip if k=0)
434 for (Index i = 0; i < k; ++i) {
435 Index remainingRows = rows - i;
436 mat.col(k)
437 .tail(remainingRows)
438 .applyHouseholderOnTheLeft(mat.col(i).tail(remainingRows - 1), hCoeffs.coeffRef(i), tempData + i + 1);
439 }
440 // Construct Householder projector in-place in column k
441 RealScalar beta;
442 mat.col(k).tail(rows - k).makeHouseholderInPlace(hCoeffs.coeffRef(k), beta);
443 mat.coeffRef(k, k) = beta;
444}
445
447template <typename MatrixQR, typename HCoeffs, typename MatrixQRScalar = typename MatrixQR::Scalar,
448 bool InnerStrideIsOne = (MatrixQR::InnerStrideAtCompileTime == 1 && HCoeffs::InnerStrideAtCompileTime == 1)>
449struct householder_qr_inplace_blocked {
450 // This is specialized for LAPACK-supported Scalar types in HouseholderQR_LAPACKE.h
451 static void run(MatrixQR& mat, HCoeffs& hCoeffs, Index maxBlockSize = 32, typename MatrixQR::Scalar* tempData = 0) {
452 using Scalar = typename MatrixQR::Scalar;
453 using BlockType = Block<MatrixQR, Dynamic, Dynamic>;
454
455 Index rows = mat.rows();
456 Index cols = mat.cols();
457 Index size = (std::min)(rows, cols);
458
459 using TempType = Matrix<Scalar, Dynamic, 1, ColMajor, MatrixQR::MaxColsAtCompileTime, 1>;
460 TempType tempVector;
461 if (tempData == 0) {
462 tempVector.resize(cols);
463 tempData = tempVector.data();
464 }
465
466 Index blockSize = (std::min)(maxBlockSize, size);
467
468 Index k = 0;
469 for (k = 0; k < size; k += blockSize) {
470 Index bs = (std::min)(size - k, blockSize); // actual size of the block
471 Index tcols = cols - k - bs; // trailing columns
472 Index brows = rows - k; // rows of the block
473
474 // partition the matrix:
475 // A00 | A01 | A02
476 // mat = A10 | A11 | A12
477 // A20 | A21 | A22
478 // and performs the qr dec of [A11^T A12^T]^T
479 // and update [A21^T A22^T]^T using level 3 operations.
480 // Finally, the algorithm continues on A22
481
482 BlockType A11_21 = mat.block(k, k, brows, bs);
483 Block<HCoeffs, Dynamic, 1> hCoeffsSegment = hCoeffs.segment(k, bs);
484
485 householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData);
486
487 if (tcols) {
488 BlockType A21_22 = mat.block(k, k + bs, brows, tcols);
489 apply_block_householder_on_the_left(A21_22, A11_21, hCoeffsSegment, false); // false == backward
490 }
491 }
492 }
493};
494
507template <typename Scalar>
508Index householder_qr_panel_width(Index rows, Index cols) {
509 const Index size = numext::mini(rows, cols);
510 const double m = double(rows), n = double(cols), s = double(size);
511 if (m * n * s <= 64.0 * 64.0 * 64.0) return size;
512 const double P = m * s - s * s / 2;
513 const double Q = m * n * s - (m + n) * s * s / 2 + s * s * s / 3;
514 const double target = numext::sqrt(3 * Q / P);
515 constexpr Index kPacketSize = packet_traits<Scalar>::size;
516 const Index kWidths[] = {8, 16, 24, 32, 48};
517 Index width = kPacketSize;
518 double distance = NumTraits<double>::highest();
519 for (Index w : kWidths) {
520 const double d = numext::maxi(double(w) / target, target / double(w));
521 if (w % kPacketSize == 0 && d < distance) {
522 width = w;
523 distance = d;
524 }
525 }
526 return width;
527}
528
529} // end namespace internal
530
531#ifndef EIGEN_PARSED_BY_DOXYGEN
532template <typename MatrixType_>
533template <typename RhsType, typename DstType>
534void HouseholderQR<MatrixType_>::_solve_impl(const RhsType& rhs, DstType& dst) const {
535 const Index rank = (std::min)(rows(), cols());
536
537 typename RhsType::PlainObject c(rhs);
538
539 c.applyOnTheLeft(householderQ().setLength(rank).adjoint());
540
541 m_qr.topLeftCorner(rank, rank).template triangularView<Upper>().solveInPlace(c.topRows(rank));
542
543 dst.topRows(rank) = c.topRows(rank);
544 dst.bottomRows(cols() - rank).setZero();
545}
546
547template <typename MatrixType_>
548template <bool Conjugate, typename RhsType, typename DstType>
549void HouseholderQR<MatrixType_>::_solve_impl_transposed(const RhsType& rhs, DstType& dst) const {
550 const Index rank = (std::min)(rows(), cols());
551
552 typename RhsType::PlainObject c(rhs);
553
554 m_qr.topLeftCorner(rank, rank)
555 .template triangularView<Upper>()
556 .transpose()
557 .template conjugateIf<Conjugate>()
558 .solveInPlace(c.topRows(rank));
559
560 dst.topRows(rank) = c.topRows(rank);
561 dst.bottomRows(rows() - rank).setZero();
562
563 dst.applyOnTheLeft(householderQ().setLength(rank).template conjugateIf<!Conjugate>());
564}
565#endif
566
573template <typename MatrixType>
575 Index rows = m_qr.rows();
576 Index cols = m_qr.cols();
577 Index size = (std::min)(rows, cols);
578
579 m_hCoeffs.resize(size);
580
581 m_temp.resize(cols);
582
583 const Index maxBlockSize = internal::householder_qr_panel_width<Scalar>(rows, cols);
584 internal::householder_qr_inplace_blocked<MatrixType, HCoeffsType>::run(m_qr, m_hCoeffs, maxBlockSize, m_temp.data());
585
586 m_isInitialized = true;
587}
588
593template <typename Derived>
597
598} // end namespace Eigen
599
600#endif // EIGEN_QR_H
EvalReturnType eval() const
Definition DenseBase.h:385
typename internal::traits< Derived >::Scalar Scalar
Definition DenseBase.h:63
Householder QR decomposition of a matrix.
Definition HouseholderQR.h:77
MatrixType::Scalar signDeterminant() const
Definition HouseholderQR.h:363
HouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
Definition HouseholderQR.h:121
HouseholderQR(EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
Definition HouseholderQR.h:153
const HCoeffsType & hCoeffs() const
Definition HouseholderQR.h:284
void computeInPlace()
Definition HouseholderQR.h:574
HouseholderQR(const EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
Definition HouseholderQR.h:137
Solve< HouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
ComputationInfo info() const
Reports whether the QR factorization was successful.
Definition HouseholderQR.h:102
MatrixType::Scalar determinant() const
Definition HouseholderQR.h:339
HouseholderSequenceType householderQ() const
Definition HouseholderQR.h:189
const MatrixType & matrixQR() const
Definition HouseholderQR.h:197
HouseholderQR()
Default Constructor.
Definition HouseholderQR.h:113
MatrixType::RealScalar absDeterminant() const
Definition HouseholderQR.h:348
MatrixType::RealScalar logAbsDeterminant() const
Definition HouseholderQR.h:356
Sequence of Householder reflections acting on subspaces with decreasing size.
Definition HouseholderSequence.h:140
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
HouseholderQR< PlainObject > householderQr() const
Definition HouseholderQR.h:594
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
Pseudo expression representing a solving operation.
Definition Solve.h:63
constexpr Derived & derived()
Definition EigenBase.h:50
const AdjointReturnType adjoint() const
Definition SolverBase.h:143
ComputationInfo
Definition Constants.h:455
@ Success
Definition Constants.h:457
@ ColMajor
Definition Constants.h:319
@ RowMajor
Definition Constants.h:321
constexpr unsigned int RowMajorBit
Definition Constants.h:71
Definition EigenBase.h:34
constexpr Derived & derived()
Definition EigenBase.h:50
constexpr Index size() const noexcept
Definition EigenBase.h:65
Eigen::Index Index
The interface type of indices.
Definition EigenBase.h:44