| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr> | |
| // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> | |
| // Copyright (C) 2010 Vincent Lejeune | |
| // | |
| // This Source Code Form is subject to the terms of the Mozilla | |
| // Public License v. 2.0. If a copy of the MPL was not distributed | |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_QR_H | |
| #define EIGEN_QR_H | |
| // IWYU pragma: private | |
| #include "./InternalHeaderCheck.h" | |
| namespace Eigen { | |
| namespace internal { | |
| template <typename MatrixType_> | |
| struct traits<HouseholderQR<MatrixType_>> : traits<MatrixType_> { | |
| using XprKind = MatrixXpr; | |
| using StorageKind = SolverStorage; | |
| using StorageIndex = int; | |
| enum { Flags = 0 }; | |
| }; | |
| } // end namespace internal | |
| /** \ingroup QR_Module | |
| * | |
| * | |
| * \class HouseholderQR | |
| * | |
| * \brief Householder QR decomposition of a matrix | |
| * | |
| * \tparam MatrixType_ the type of the matrix of which we are computing the QR decomposition | |
| * | |
| * This class performs a QR decomposition of a matrix \b A into matrices \b Q and \b R | |
| * such that | |
| * \f[ | |
| * \mathbf{A} = \mathbf{Q} \, \mathbf{R} | |
| * \f] | |
| * by using Householder transformations. Here, \b Q a unitary matrix and \b R an upper triangular matrix. | |
| * The result is stored in a compact way compatible with LAPACK. | |
| * | |
| * Note that no pivoting is performed. This is \b not a rank-revealing decomposition. | |
| * If you want that feature, use FullPivHouseholderQR or ColPivHouseholderQR instead. | |
| * | |
| * This Householder QR decomposition is faster, but less numerically stable and less feature-full than | |
| * FullPivHouseholderQR or ColPivHouseholderQR. | |
| * | |
| * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. | |
| * | |
| * \warning For a wide m-by-n matrix (m < n), transpose().solve() and adjoint().solve() use only | |
| * the first m equations, through the leading m-by-m triangular block of R. This block can be | |
| * ill-conditioned or singular even when A is well-conditioned and has full row rank. The remaining | |
| * equations are satisfied only insofar as the right-hand side is consistent and rounding errors permit; | |
| * these calls do not compute a least-squares solution for an inconsistent right-hand side. | |
| * To solve using all equations when A has full row rank, factor the transpose directly: | |
| * \code | |
| * x = A.transpose().householderQr().solve(b); | |
| * \endcode | |
| * For rank-deficient A, or to reuse a decomposition of A, use CompleteOrthogonalDecomposition | |
| * to obtain the minimum-norm least-squares solution: | |
| * \code | |
| * auto cod = A.completeOrthogonalDecomposition(); | |
| * x = cod.transpose().solve(b); | |
| * \endcode | |
| * Replace transpose() with adjoint() in these examples for the adjoint system. | |
| * | |
| * \sa MatrixBase::householderQr() | |
| */ | |
| template <typename MatrixType_> | |
| class HouseholderQR : public SolverBase<HouseholderQR<MatrixType_>> { | |
| public: | |
| using MatrixType = MatrixType_; | |
| using Base = SolverBase<HouseholderQR>; | |
| friend class SolverBase<HouseholderQR>; | |
| EIGEN_GENERIC_PUBLIC_INTERFACE(HouseholderQR) | |
| enum { | |
| MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, | |
| MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime | |
| }; | |
| using MatrixQType = | |
| Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, (MatrixType::Flags & RowMajorBit) ? RowMajor : ColMajor, | |
| MaxRowsAtCompileTime, MaxRowsAtCompileTime>; | |
| using HCoeffsType = typename internal::plain_diag_type<MatrixType>::type; | |
| using RowVectorType = typename internal::plain_row_type<MatrixType>::type; | |
| using HouseholderSequenceType = | |
| HouseholderSequence<MatrixType, internal::remove_all_t<typename HCoeffsType::ConjugateReturnType>>; | |
| /** \brief Reports whether the QR factorization was successful. | |
| * | |
| * \note This function always returns \c Success. It is provided for compatibility | |
| * with other factorization routines. | |
| * \returns \c Success | |
| */ | |
| ComputationInfo info() const { | |
| eigen_assert(m_isInitialized && "HouseHolderQR is not initialized."); | |
| return Success; | |
| } | |
| /** | |
| * \brief Default Constructor. | |
| * | |
| * The default constructor is useful in cases in which the user intends to | |
| * perform decompositions via HouseholderQR::compute(const MatrixType&). | |
| */ | |
| HouseholderQR() : m_qr(), m_hCoeffs(), m_temp(), m_isInitialized(false) {} | |
| /** \brief Default Constructor with memory preallocation | |
| * | |
| * Like the default constructor but with preallocation of the internal data | |
| * according to the specified problem \a size. | |
| * \sa HouseholderQR() | |
| */ | |
| HouseholderQR(Index rows, Index cols) | |
| : m_qr(rows, cols), m_hCoeffs((std::min)(rows, cols)), m_temp(cols), m_isInitialized(false) {} | |
| /** \brief Constructs a QR factorization from a given matrix | |
| * | |
| * This constructor computes the QR factorization of the matrix \a matrix by calling | |
| * the method compute(). It is a short cut for: | |
| * | |
| * \code | |
| * HouseholderQR<MatrixType> qr(matrix.rows(), matrix.cols()); | |
| * qr.compute(matrix); | |
| * \endcode | |
| * | |
| * \sa compute() | |
| */ | |
| template <typename InputType> | |
| explicit HouseholderQR(const EigenBase<InputType>& matrix) | |
| : m_qr(matrix.rows(), matrix.cols()), | |
| m_hCoeffs((std::min)(matrix.rows(), matrix.cols())), | |
| m_temp(matrix.cols()), | |
| m_isInitialized(false) { | |
| compute(matrix.derived()); | |
| } | |
| /** \brief Constructs a QR factorization from a given matrix | |
| * | |
| * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when | |
| * \c MatrixType is a Eigen::Ref. | |
| * | |
| * \sa HouseholderQR(const EigenBase&) | |
| */ | |
| template <typename InputType> | |
| explicit HouseholderQR(EigenBase<InputType>& matrix) | |
| : m_qr(matrix.derived()), | |
| m_hCoeffs((std::min)(matrix.rows(), matrix.cols())), | |
| m_temp(matrix.cols()), | |
| m_isInitialized(false) { | |
| computeInPlace(); | |
| } | |
| #ifdef EIGEN_PARSED_BY_DOXYGEN | |
| /** This method finds a solution x to the equation Ax=b, where A is the matrix of which | |
| * *this is the QR decomposition, if any exists. | |
| * | |
| * \param b the right-hand-side of the equation to solve. | |
| * | |
| * \returns a solution. | |
| * | |
| * \note_about_checking_solutions | |
| * | |
| * \note_about_arbitrary_choice_of_solution | |
| * | |
| * Example: \include HouseholderQR_solve.cpp | |
| * Output: \verbinclude HouseholderQR_solve.out | |
| */ | |
| template <typename Rhs> | |
| inline Solve<HouseholderQR, Rhs> solve(const MatrixBase<Rhs>& b) const; | |
| #endif | |
| /** This method returns an expression of the unitary matrix Q as a sequence of Householder transformations. | |
| * | |
| * The returned expression can directly be used to perform matrix products. It can also be assigned to a dense Matrix | |
| * object. Here is an example showing how to recover the full or thin matrix Q, as well as how to perform matrix | |
| * products using operator*: | |
| * | |
| * Example: \include HouseholderQR_householderQ.cpp | |
| * Output: \verbinclude HouseholderQR_householderQ.out | |
| */ | |
| HouseholderSequenceType householderQ() const { | |
| eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); | |
| return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()); | |
| } | |
| /** \returns a reference to the matrix where the Householder QR decomposition is stored | |
| * in a LAPACK-compatible way. | |
| */ | |
| const MatrixType& matrixQR() const { | |
| eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); | |
| return m_qr; | |
| } | |
| template <typename InputType> | |
| HouseholderQR& compute(const EigenBase<InputType>& matrix) { | |
| m_qr = matrix.derived(); | |
| computeInPlace(); | |
| return *this; | |
| } | |
| /** \returns the determinant of the matrix of which | |
| * *this is the QR decomposition. It has only linear complexity | |
| * (that is, O(n) where n is the dimension of the square matrix) | |
| * as the QR decomposition has already been computed. | |
| * | |
| * \note This is only for square matrices. | |
| * | |
| * \warning a determinant can be very big or small, so for matrices | |
| * of large enough dimension, there is a risk of overflow/underflow. | |
| * One way to work around that is to use logAbsDeterminant() instead. | |
| * Also, do not rely on the determinant being exactly zero for testing | |
| * singularity or rank-deficiency. | |
| * | |
| * \sa absDeterminant(), logAbsDeterminant(), MatrixBase::determinant() | |
| */ | |
| typename MatrixType::Scalar determinant() const; | |
| /** \returns the absolute value of the determinant of the matrix of which | |
| * *this is the QR decomposition. It has only linear complexity | |
| * (that is, O(n) where n is the dimension of the square matrix) | |
| * as the QR decomposition has already been computed. | |
| * | |
| * \note This is only for square matrices. | |
| * | |
| * \warning a determinant can be very big or small, so for matrices | |
| * of large enough dimension, there is a risk of overflow/underflow. | |
| * One way to work around that is to use logAbsDeterminant() instead. | |
| * Also, do not rely on the determinant being exactly zero for testing | |
| * singularity or rank-deficiency. | |
| * | |
| * \sa determinant(), logAbsDeterminant(), MatrixBase::determinant() | |
| */ | |
| typename MatrixType::RealScalar absDeterminant() const; | |
| /** \returns the natural log of the absolute value of the determinant of the matrix of which | |
| * *this is the QR decomposition. It has only linear complexity | |
| * (that is, O(n) where n is the dimension of the square matrix) | |
| * as the QR decomposition has already been computed. | |
| * | |
| * \note This is only for square matrices. | |
| * | |
| * \note This method is useful to work around the risk of overflow/underflow that's inherent | |
| * to determinant computation. | |
| * | |
| * \warning Do not rely on the determinant being exactly zero for testing | |
| * singularity or rank-deficiency. | |
| * | |
| * \sa determinant(), absDeterminant(), MatrixBase::determinant() | |
| */ | |
| typename MatrixType::RealScalar logAbsDeterminant() const; | |
| /** \returns the sign of the determinant of the matrix of which | |
| * *this is the QR decomposition. It has only linear complexity | |
| * (that is, O(n) where n is the dimension of the square matrix) | |
| * as the QR decomposition has already been computed. | |
| * | |
| * \note This is only for square matrices. | |
| * | |
| * \note This method is useful to work around the risk of overflow/underflow that's inherent | |
| * to determinant computation. | |
| * | |
| * \warning Do not rely on the determinant being exactly zero for testing | |
| * singularity or rank-deficiency. | |
| * | |
| * \sa determinant(), absDeterminant(), MatrixBase::determinant() | |
| */ | |
| typename MatrixType::Scalar signDeterminant() const; | |
| inline Index rows() const { return m_qr.rows(); } | |
| inline Index cols() const { return m_qr.cols(); } | |
| /** \returns a const reference to the vector of Householder coefficients used to represent the factor \c Q. | |
| * | |
| * For advanced uses only. | |
| */ | |
| const HCoeffsType& hCoeffs() const { return m_hCoeffs; } | |
| #ifndef EIGEN_PARSED_BY_DOXYGEN | |
| template <typename RhsType, typename DstType> | |
| void _solve_impl(const RhsType& rhs, DstType& dst) const; | |
| template <bool Conjugate, typename RhsType, typename DstType> | |
| void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const; | |
| #endif | |
| protected: | |
| EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) | |
| void computeInPlace(); | |
| MatrixType m_qr; | |
| HCoeffsType m_hCoeffs; | |
| RowVectorType m_temp; | |
| bool m_isInitialized; | |
| }; | |
| namespace internal { | |
| /** \internal */ | |
| template <typename HCoeffs, typename Scalar, bool IsComplex> | |
| struct householder_determinant { | |
| static void run(const HCoeffs& hCoeffs, Scalar& out_det) { | |
| out_det = Scalar(1); | |
| Index size = hCoeffs.rows(); | |
| for (Index i = 0; i < size; i++) { | |
| // For each valid reflection Q_n, | |
| // det(Q_n) = - conj(h_n) / h_n | |
| // where h_n is the Householder coefficient. | |
| if (hCoeffs(i) != Scalar(0)) out_det *= -numext::conj(hCoeffs(i)) / hCoeffs(i); | |
| } | |
| } | |
| }; | |
| /** \internal */ | |
| template <typename HCoeffs, typename Scalar> | |
| struct householder_determinant<HCoeffs, Scalar, false> { | |
| static void run(const HCoeffs& hCoeffs, Scalar& out_det) { | |
| bool negated = false; | |
| Index size = hCoeffs.rows(); | |
| for (Index i = 0; i < size; i++) { | |
| // Each valid reflection negates the determinant. | |
| if (hCoeffs(i) != Scalar(0)) negated ^= true; | |
| } | |
| out_det = negated ? Scalar(-1) : Scalar(1); | |
| } | |
| }; | |
| } // end namespace internal | |
| template <typename MatrixType> | |
| typename MatrixType::Scalar HouseholderQR<MatrixType>::determinant() const { | |
| eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); | |
| EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); | |
| Scalar detQ; | |
| internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); | |
| return m_qr.diagonal().prod() * detQ; | |
| } | |
| template <typename MatrixType> | |
| typename MatrixType::RealScalar HouseholderQR<MatrixType>::absDeterminant() const { | |
| using std::abs; | |
| eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); | |
| EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); | |
| return abs(m_qr.diagonal().prod()); | |
| } | |
| template <typename MatrixType> | |
| typename MatrixType::RealScalar HouseholderQR<MatrixType>::logAbsDeterminant() const { | |
| eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); | |
| EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); | |
| return m_qr.diagonal().cwiseAbs().array().log().sum(); | |
| } | |
| template <typename MatrixType> | |
| typename MatrixType::Scalar HouseholderQR<MatrixType>::signDeterminant() const { | |
| eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); | |
| EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); | |
| Scalar detQ; | |
| internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); | |
| return detQ * m_qr.diagonal().array().sign().prod(); | |
| } | |
| namespace internal { | |
| /** \internal */ | |
| template <typename MatrixQR, typename HCoeffs> | |
| void householder_qr_inplace_unblocked(MatrixQR& mat, HCoeffs& hCoeffs, typename MatrixQR::Scalar* tempData = 0) { | |
| using Scalar = typename MatrixQR::Scalar; | |
| using RealScalar = typename MatrixQR::RealScalar; | |
| Index rows = mat.rows(); | |
| Index cols = mat.cols(); | |
| Index size = (std::min)(rows, cols); | |
| eigen_assert(hCoeffs.size() == size); | |
| using TempType = Matrix<Scalar, MatrixQR::ColsAtCompileTime, 1>; | |
| TempType tempVector; | |
| if (tempData == 0) { | |
| tempVector.resize(cols); | |
| tempData = tempVector.data(); | |
| } | |
| for (Index k = 0; k < size; ++k) { | |
| Index remainingRows = rows - k; | |
| Index remainingCols = cols - k - 1; | |
| RealScalar beta; | |
| mat.col(k).tail(remainingRows).makeHouseholderInPlace(hCoeffs.coeffRef(k), beta); | |
| mat.coeffRef(k, k) = beta; | |
| // apply H to remaining part of mat from the left | |
| mat.bottomRightCorner(remainingRows, remainingCols) | |
| .applyHouseholderOnTheLeft(mat.col(k).tail(remainingRows - 1), hCoeffs.coeffRef(k), tempData + k + 1); | |
| } | |
| } | |
| /** \internal | |
| * Column-insert / column-replace helper for a compact-storage Householder QR. | |
| * Given a matrix @c mat and @c hCoeffs holding the QR factorization of the first @c k columns of | |
| * some matrix A, this function replaces column @c k of that factorization with @c newColumn: it | |
| * applies the existing k Householder reflectors (stored in columns 0..k-1 of @c mat and in | |
| * @c hCoeffs.head(k)) to @c newColumn, then computes the k-th reflector in place. On exit | |
| * @c mat.leftCols(k+1) and @c hCoeffs.head(k+1) hold the QR factorization of A.leftCols(k) with | |
| * @c newColumn inserted at position @c k. @c tempData must point to at least @c mat.cols() scalars. | |
| * | |
| * Despite the historical "rank-1 update" label, this is not a full QR update in the | |
| * Gill-Golub-Murray-Saunders sense: there is no public API for @c QR(A + u vT) or for column/row | |
| * delete. See libeigen/eigen#3072 for a tracker of that feature gap. Currently only NNLS relies on | |
| * this helper; the signature is tuned to its active-set bookkeeping. */ | |
| template <typename MatrixQR, typename HCoeffs, typename VectorQR> | |
| void householder_qr_inplace_update(MatrixQR& mat, HCoeffs& hCoeffs, const VectorQR& newColumn, | |
| typename MatrixQR::Index k, typename MatrixQR::Scalar* tempData) { | |
| using Index = typename MatrixQR::Index; | |
| using RealScalar = typename MatrixQR::RealScalar; | |
| Index rows = mat.rows(); | |
| eigen_assert(k < mat.cols()); | |
| eigen_assert(k < rows); | |
| EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(hCoeffs, mat); | |
| EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(newColumn, mat); | |
| eigen_assert(tempData); | |
| // Store new column in mat at column k | |
| mat.col(k) = newColumn; | |
| // Apply H = H_1...H_{k-1} on newColumn (skip if k=0) | |
| for (Index i = 0; i < k; ++i) { | |
| Index remainingRows = rows - i; | |
| mat.col(k) | |
| .tail(remainingRows) | |
| .applyHouseholderOnTheLeft(mat.col(i).tail(remainingRows - 1), hCoeffs.coeffRef(i), tempData + i + 1); | |
| } | |
| // Construct Householder projector in-place in column k | |
| RealScalar beta; | |
| mat.col(k).tail(rows - k).makeHouseholderInPlace(hCoeffs.coeffRef(k), beta); | |
| mat.coeffRef(k, k) = beta; | |
| } | |
| /** \internal */ | |
| template <typename MatrixQR, typename HCoeffs, typename MatrixQRScalar = typename MatrixQR::Scalar, | |
| bool InnerStrideIsOne = (MatrixQR::InnerStrideAtCompileTime == 1 && HCoeffs::InnerStrideAtCompileTime == 1)> | |
| struct householder_qr_inplace_blocked { | |
| // This is specialized for LAPACK-supported Scalar types in HouseholderQR_LAPACKE.h | |
| static void run(MatrixQR& mat, HCoeffs& hCoeffs, Index maxBlockSize = 32, typename MatrixQR::Scalar* tempData = 0) { | |
| using Scalar = typename MatrixQR::Scalar; | |
| using BlockType = Block<MatrixQR, Dynamic, Dynamic>; | |
| Index rows = mat.rows(); | |
| Index cols = mat.cols(); | |
| Index size = (std::min)(rows, cols); | |
| using TempType = Matrix<Scalar, Dynamic, 1, ColMajor, MatrixQR::MaxColsAtCompileTime, 1>; | |
| TempType tempVector; | |
| if (tempData == 0) { | |
| tempVector.resize(cols); | |
| tempData = tempVector.data(); | |
| } | |
| Index blockSize = (std::min)(maxBlockSize, size); | |
| Index k = 0; | |
| for (k = 0; k < size; k += blockSize) { | |
| Index bs = (std::min)(size - k, blockSize); // actual size of the block | |
| Index tcols = cols - k - bs; // trailing columns | |
| Index brows = rows - k; // rows of the block | |
| // partition the matrix: | |
| // A00 | A01 | A02 | |
| // mat = A10 | A11 | A12 | |
| // A20 | A21 | A22 | |
| // and performs the qr dec of [A11^T A12^T]^T | |
| // and update [A21^T A22^T]^T using level 3 operations. | |
| // Finally, the algorithm continues on A22 | |
| BlockType A11_21 = mat.block(k, k, brows, bs); | |
| Block<HCoeffs, Dynamic, 1> hCoeffsSegment = hCoeffs.segment(k, bs); | |
| householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData); | |
| if (tcols) { | |
| BlockType A21_22 = mat.block(k, k + bs, brows, tcols); | |
| apply_block_householder_on_the_left(A21_22, A11_21, hCoeffsSegment, false); // false == backward | |
| } | |
| } | |
| } | |
| }; | |
| /** \internal | |
| * Panel width b for householder_qr_inplace_blocked on a rows x cols matrix, with s = min(rows, cols). | |
| * Factoring a panel streams it O(b) times at level 2 and each trailing update streams the trailing block O(1) times, | |
| * so the factorization moves | |
| * ~ c_p * b * P + c_t * Q / b, P = sum_{k<s} (rows - k), Q = sum_{k<s} (rows - k) * (cols - k) | |
| * coefficients (P and Q to leading order below), least at b = sqrt(kappa * Q / P); peak flop rate cancels, and | |
| * kappa = 3 fits the measured optimum on AVX-512, NEON and SME. The cost is flat in log(b) near the minimum, so b is | |
| * the nearest of 8, 16, 24, 32, 48 that is a whole number of packets, or one packet if none is: b is the row count of | |
| * the product V^* * C, which slows sharply on a partial packet. Panels wider than 48 measured no faster. Up to | |
| * rows * cols * s = 64^3 the per-panel overhead (forming T, product setup) outweighs the traffic saved, and a single | |
| * panel of width s is returned. | |
| */ | |
| template <typename Scalar> | |
| Index householder_qr_panel_width(Index rows, Index cols) { | |
| const Index size = numext::mini(rows, cols); | |
| const double m = double(rows), n = double(cols), s = double(size); | |
| if (m * n * s <= 64.0 * 64.0 * 64.0) return size; | |
| const double P = m * s - s * s / 2; | |
| const double Q = m * n * s - (m + n) * s * s / 2 + s * s * s / 3; | |
| const double target = numext::sqrt(3 * Q / P); | |
| constexpr Index kPacketSize = packet_traits<Scalar>::size; | |
| const Index kWidths[] = {8, 16, 24, 32, 48}; | |
| Index width = kPacketSize; | |
| double distance = NumTraits<double>::highest(); | |
| for (Index w : kWidths) { | |
| const double d = numext::maxi(double(w) / target, target / double(w)); | |
| if (w % kPacketSize == 0 && d < distance) { | |
| width = w; | |
| distance = d; | |
| } | |
| } | |
| return width; | |
| } | |
| } // end namespace internal | |
| #ifndef EIGEN_PARSED_BY_DOXYGEN | |
| template <typename MatrixType_> | |
| template <typename RhsType, typename DstType> | |
| void HouseholderQR<MatrixType_>::_solve_impl(const RhsType& rhs, DstType& dst) const { | |
| const Index rank = (std::min)(rows(), cols()); | |
| typename RhsType::PlainObject c(rhs); | |
| c.applyOnTheLeft(householderQ().setLength(rank).adjoint()); | |
| m_qr.topLeftCorner(rank, rank).template triangularView<Upper>().solveInPlace(c.topRows(rank)); | |
| dst.topRows(rank) = c.topRows(rank); | |
| dst.bottomRows(cols() - rank).setZero(); | |
| } | |
| template <typename MatrixType_> | |
| template <bool Conjugate, typename RhsType, typename DstType> | |
| void HouseholderQR<MatrixType_>::_solve_impl_transposed(const RhsType& rhs, DstType& dst) const { | |
| const Index rank = (std::min)(rows(), cols()); | |
| typename RhsType::PlainObject c(rhs); | |
| m_qr.topLeftCorner(rank, rank) | |
| .template triangularView<Upper>() | |
| .transpose() | |
| .template conjugateIf<Conjugate>() | |
| .solveInPlace(c.topRows(rank)); | |
| dst.topRows(rank) = c.topRows(rank); | |
| dst.bottomRows(rows() - rank).setZero(); | |
| dst.applyOnTheLeft(householderQ().setLength(rank).template conjugateIf<!Conjugate>()); | |
| } | |
| #endif | |
| /** Performs the QR factorization of the given matrix \a matrix. The result of | |
| * the factorization is stored into \c *this, and a reference to \c *this | |
| * is returned. | |
| * | |
| * \sa class HouseholderQR, HouseholderQR(const MatrixType&) | |
| */ | |
| template <typename MatrixType> | |
| void HouseholderQR<MatrixType>::computeInPlace() { | |
| Index rows = m_qr.rows(); | |
| Index cols = m_qr.cols(); | |
| Index size = (std::min)(rows, cols); | |
| m_hCoeffs.resize(size); | |
| m_temp.resize(cols); | |
| const Index maxBlockSize = internal::householder_qr_panel_width<Scalar>(rows, cols); | |
| internal::householder_qr_inplace_blocked<MatrixType, HCoeffsType>::run(m_qr, m_hCoeffs, maxBlockSize, m_temp.data()); | |
| m_isInitialized = true; | |
| } | |
| /** \return the Householder QR decomposition of \c *this. | |
| * | |
| * \sa class HouseholderQR | |
| */ | |
| template <typename Derived> | |
| HouseholderQR<typename MatrixBase<Derived>::PlainObject> MatrixBase<Derived>::householderQr() const { | |
| return HouseholderQR<PlainObject>(eval()); | |
| } | |
| } // end namespace Eigen | |
| #endif // EIGEN_QR_H |