HouseholderQR.h
Go to the documentation of this file.
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 
12 #ifndef EIGEN_QR_H
13 #define EIGEN_QR_H
14 
15 #include "./InternalHeaderCheck.h"
16 
17 namespace Eigen {
18 
19 namespace internal {
20 template<typename MatrixType_> struct traits<HouseholderQR<MatrixType_> >
21  : traits<MatrixType_>
22 {
23  typedef MatrixXpr XprKind;
24  typedef SolverStorage StorageKind;
25  typedef int StorageIndex;
26  enum { Flags = 0 };
27 };
28 
29 } // end namespace internal
30 
58 template<typename MatrixType_> class HouseholderQR
59  : public SolverBase<HouseholderQR<MatrixType_> >
60 {
61  public:
62 
63  typedef MatrixType_ MatrixType;
65  friend class SolverBase<HouseholderQR>;
66 
68  enum {
69  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
70  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
71  };
73  typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
74  typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
76 
84 
92  : m_qr(rows, cols),
93  m_hCoeffs((std::min)(rows,cols)),
94  m_temp(cols),
95  m_isInitialized(false) {}
96 
109  template<typename InputType>
110  explicit HouseholderQR(const EigenBase<InputType>& matrix)
111  : m_qr(matrix.rows(), matrix.cols()),
112  m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
113  m_temp(matrix.cols()),
114  m_isInitialized(false)
115  {
116  compute(matrix.derived());
117  }
118 
119 
127  template<typename InputType>
129  : m_qr(matrix.derived()),
130  m_hCoeffs((std::min)(matrix.rows(),matrix.cols())),
131  m_temp(matrix.cols()),
132  m_isInitialized(false)
133  {
134  computeInPlace();
135  }
136 
137  #ifdef EIGEN_PARSED_BY_DOXYGEN
152  template<typename Rhs>
153  inline const Solve<HouseholderQR, Rhs>
154  solve(const MatrixBase<Rhs>& b) const;
155  #endif
156 
166  {
167  eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
168  return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
169  }
170 
174  const MatrixType& matrixQR() const
175  {
176  eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
177  return m_qr;
178  }
179 
180  template<typename InputType>
182  m_qr = matrix.derived();
183  computeInPlace();
184  return *this;
185  }
186 
200  typename MatrixType::Scalar determinant() const;
201 
216 
230 
231  inline Index rows() const { return m_qr.rows(); }
232  inline Index cols() const { return m_qr.cols(); }
233 
238  const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
239 
240  #ifndef EIGEN_PARSED_BY_DOXYGEN
241  template<typename RhsType, typename DstType>
242  void _solve_impl(const RhsType &rhs, DstType &dst) const;
243 
244  template<bool Conjugate, typename RhsType, typename DstType>
245  void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
246  #endif
247 
248  protected:
249 
251 
253 
258 };
259 
260 namespace internal {
261 
263 template<typename HCoeffs, typename Scalar, bool IsComplex>
264 struct householder_determinant
265 {
266  static void run(const HCoeffs& hCoeffs, Scalar& out_det)
267  {
268  out_det = Scalar(1);
269  Index size = hCoeffs.rows();
270  for (Index i = 0; i < size; i ++)
271  {
272  // For each valid reflection Q_n,
273  // det(Q_n) = - conj(h_n) / h_n
274  // where h_n is the Householder coefficient.
275  if (hCoeffs(i) != Scalar(0))
276  out_det *= - numext::conj(hCoeffs(i)) / hCoeffs(i);
277  }
278  }
279 };
280 
282 template<typename HCoeffs, typename Scalar>
283 struct householder_determinant<HCoeffs, Scalar, false>
284 {
285  static void run(const HCoeffs& hCoeffs, Scalar& out_det)
286  {
287  bool negated = false;
288  Index size = hCoeffs.rows();
289  for (Index i = 0; i < size; i ++)
290  {
291  // Each valid reflection negates the determinant.
292  if (hCoeffs(i) != Scalar(0))
293  negated ^= true;
294  }
295  out_det = negated ? Scalar(-1) : Scalar(1);
296  }
297 };
298 
299 } // end namespace internal
300 
301 template<typename MatrixType>
303 {
304  eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
305  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
306  Scalar detQ;
307  internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ);
308  return m_qr.diagonal().prod() * detQ;
309 }
310 
311 template<typename MatrixType>
313 {
314  using std::abs;
315  eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
316  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
317  return abs(m_qr.diagonal().prod());
318 }
319 
320 template<typename MatrixType>
322 {
323  eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
324  eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!");
325  return m_qr.diagonal().cwiseAbs().array().log().sum();
326 }
327 
328 namespace internal {
329 
331 template<typename MatrixQR, typename HCoeffs>
332 void householder_qr_inplace_unblocked(MatrixQR& mat, HCoeffs& hCoeffs, typename MatrixQR::Scalar* tempData = 0)
333 {
334  typedef typename MatrixQR::Scalar Scalar;
335  typedef typename MatrixQR::RealScalar RealScalar;
336  Index rows = mat.rows();
337  Index cols = mat.cols();
338  Index size = (std::min)(rows,cols);
339 
340  eigen_assert(hCoeffs.size() == size);
341 
343  TempType tempVector;
344  if(tempData==0)
345  {
346  tempVector.resize(cols);
347  tempData = tempVector.data();
348  }
349 
350  for(Index k = 0; k < size; ++k)
351  {
352  Index remainingRows = rows - k;
353  Index remainingCols = cols - k - 1;
354 
355  RealScalar beta;
356  mat.col(k).tail(remainingRows).makeHouseholderInPlace(hCoeffs.coeffRef(k), beta);
357  mat.coeffRef(k,k) = beta;
358 
359  // apply H to remaining part of m_qr from the left
360  mat.bottomRightCorner(remainingRows, remainingCols)
361  .applyHouseholderOnTheLeft(mat.col(k).tail(remainingRows-1), hCoeffs.coeffRef(k), tempData+k+1);
362  }
363 }
364 
365 // TODO: add a corresponding public API for updating a QR factorization
374 template <typename MatrixQR, typename HCoeffs, typename VectorQR>
375 void householder_qr_inplace_update(MatrixQR& mat, HCoeffs& hCoeffs, const VectorQR& newColumn,
376  typename MatrixQR::Index k, typename MatrixQR::Scalar* tempData) {
377  typedef typename MatrixQR::Index Index;
378  typedef typename MatrixQR::RealScalar RealScalar;
379  Index rows = mat.rows();
380 
381  eigen_assert(k < mat.cols());
382  eigen_assert(k < rows);
383  eigen_assert(hCoeffs.size() == mat.cols());
384  eigen_assert(newColumn.size() == rows);
385  eigen_assert(tempData);
386 
387  // Store new column in mat at column k
388  mat.col(k) = newColumn;
389  // Apply H = H_1...H_{k-1} on newColumn (skip if k=0)
390  for (Index i = 0; i < k; ++i) {
391  Index remainingRows = rows - i;
392  mat.col(k)
393  .tail(remainingRows)
394  .applyHouseholderOnTheLeft(mat.col(i).tail(remainingRows - 1), hCoeffs.coeffRef(i), tempData + i + 1);
395  }
396  // Construct Householder projector in-place in column k
397  RealScalar beta;
398  mat.col(k).tail(rows - k).makeHouseholderInPlace(hCoeffs.coeffRef(k), beta);
399  mat.coeffRef(k, k) = beta;
400 }
401 
403 template<typename MatrixQR, typename HCoeffs,
404  typename MatrixQRScalar = typename MatrixQR::Scalar,
405  bool InnerStrideIsOne = (MatrixQR::InnerStrideAtCompileTime == 1 && HCoeffs::InnerStrideAtCompileTime == 1)>
406 struct householder_qr_inplace_blocked
407 {
408  // This is specialized for LAPACK-supported Scalar types in HouseholderQR_LAPACKE.h
409  static void run(MatrixQR& mat, HCoeffs& hCoeffs, Index maxBlockSize=32,
410  typename MatrixQR::Scalar* tempData = 0)
411  {
412  typedef typename MatrixQR::Scalar Scalar;
413  typedef Block<MatrixQR,Dynamic,Dynamic> BlockType;
414 
415  Index rows = mat.rows();
416  Index cols = mat.cols();
417  Index size = (std::min)(rows, cols);
418 
420  TempType tempVector;
421  if(tempData==0)
422  {
423  tempVector.resize(cols);
424  tempData = tempVector.data();
425  }
426 
427  Index blockSize = (std::min)(maxBlockSize,size);
428 
429  Index k = 0;
430  for (k = 0; k < size; k += blockSize)
431  {
432  Index bs = (std::min)(size-k,blockSize); // actual size of the block
433  Index tcols = cols - k - bs; // trailing columns
434  Index brows = rows-k; // rows of the block
435 
436  // partition the matrix:
437  // A00 | A01 | A02
438  // mat = A10 | A11 | A12
439  // A20 | A21 | A22
440  // and performs the qr dec of [A11^T A12^T]^T
441  // and update [A21^T A22^T]^T using level 3 operations.
442  // Finally, the algorithm continue on A22
443 
444  BlockType A11_21 = mat.block(k,k,brows,bs);
445  Block<HCoeffs,Dynamic,1> hCoeffsSegment = hCoeffs.segment(k,bs);
446 
447  householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData);
448 
449  if(tcols)
450  {
451  BlockType A21_22 = mat.block(k,k+bs,brows,tcols);
452  apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment, false); // false == backward
453  }
454  }
455  }
456 };
457 
458 } // end namespace internal
459 
460 #ifndef EIGEN_PARSED_BY_DOXYGEN
461 template<typename MatrixType_>
462 template<typename RhsType, typename DstType>
463 void HouseholderQR<MatrixType_>::_solve_impl(const RhsType &rhs, DstType &dst) const
464 {
465  const Index rank = (std::min)(rows(), cols());
466 
467  typename RhsType::PlainObject c(rhs);
468 
469  c.applyOnTheLeft(householderQ().setLength(rank).adjoint() );
470 
471  m_qr.topLeftCorner(rank, rank)
472  .template triangularView<Upper>()
473  .solveInPlace(c.topRows(rank));
474 
475  dst.topRows(rank) = c.topRows(rank);
476  dst.bottomRows(cols()-rank).setZero();
477 }
478 
479 template<typename MatrixType_>
480 template<bool Conjugate, typename RhsType, typename DstType>
481 void HouseholderQR<MatrixType_>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
482 {
483  const Index rank = (std::min)(rows(), cols());
484 
485  typename RhsType::PlainObject c(rhs);
486 
487  m_qr.topLeftCorner(rank, rank)
488  .template triangularView<Upper>()
489  .transpose().template conjugateIf<Conjugate>()
490  .solveInPlace(c.topRows(rank));
491 
492  dst.topRows(rank) = c.topRows(rank);
493  dst.bottomRows(rows()-rank).setZero();
494 
495  dst.applyOnTheLeft(householderQ().setLength(rank).template conjugateIf<!Conjugate>() );
496 }
497 #endif
498 
505 template<typename MatrixType>
507 {
508  Index rows = m_qr.rows();
509  Index cols = m_qr.cols();
510  Index size = (std::min)(rows,cols);
511 
512  m_hCoeffs.resize(size);
513 
514  m_temp.resize(cols);
515 
516  internal::householder_qr_inplace_blocked<MatrixType, HCoeffsType>::run(m_qr, m_hCoeffs, 48, m_temp.data());
517 
518  m_isInitialized = true;
519 }
520 
525 template<typename Derived>
528 {
529  return HouseholderQR<PlainObject>(eval());
530 }
531 
532 } // end namespace Eigen
533 
534 #endif // EIGEN_QR_H
const AbsReturnType abs() const
Array< int, 3, 1 > b
Array33i c
#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived)
Definition: Macros.h:1149
#define eigen_assert(x)
Definition: Macros.h:902
#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE)
Definition: StaticAssert.h:81
Expression of a fixed-size or dynamic-size block.
Definition: Block.h:107
NumTraits< Scalar >::Real RealScalar
Definition: DenseBase.h:68
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
Householder QR decomposition of a matrix.
Definition: HouseholderQR.h:60
HouseholderQR(Index rows, Index cols)
Default Constructor with memory preallocation.
Definition: HouseholderQR.h:91
HouseholderQR(EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
const Solve< HouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
HouseholderSequence< MatrixType, internal::remove_all_t< typename HCoeffsType::ConjugateReturnType > > HouseholderSequenceType
Definition: HouseholderQR.h:75
HouseholderQR(const EigenBase< InputType > &matrix)
Constructs a QR factorization from a given matrix.
MatrixType_ MatrixType
Definition: HouseholderQR.h:63
Index rows() const
MatrixType::Scalar determinant() const
const HCoeffsType & hCoeffs() const
internal::plain_diag_type< MatrixType >::type HCoeffsType
Definition: HouseholderQR.h:73
HouseholderSequenceType householderQ() const
HouseholderQR()
Default Constructor.
Definition: HouseholderQR.h:83
MatrixType::RealScalar absDeterminant() const
const MatrixType & matrixQR() const
HouseholderQR & compute(const EigenBase< InputType > &matrix)
Index cols() const
SolverBase< HouseholderQR > Base
Definition: HouseholderQR.h:64
internal::plain_row_type< MatrixType >::type RowVectorType
Definition: HouseholderQR.h:74
RowVectorType m_temp
MatrixType::RealScalar logAbsDeterminant() const
Sequence of Householder reflections acting on subspaces with decreasing size.
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:52
const HouseholderQR< PlainObject > householderQr() const
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:182
constexpr void resize(Index rows, Index cols)
Pseudo expression representing a solving operation.
Definition: Solve.h:65
A base class for matrix decomposition and solvers.
Definition: SolverBase.h:71
internal::traits< HouseholderQR< MatrixType_ > >::Scalar Scalar
Definition: SolverBase.h:75
HouseholderQR< MatrixType_ > & derived()
Definition: EigenBase.h:48
const AdjointReturnType adjoint() const
Definition: SolverBase.h:141
@ ColMajor
Definition: Constants.h:321
@ RowMajor
Definition: Constants.h:323
const unsigned int RowMajorBit
Definition: Constants.h:68
bfloat16() min(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:684
void householder_qr_inplace_unblocked(MatrixQR &mat, HCoeffs &hCoeffs, typename MatrixQR::Scalar *tempData=0)
void householder_qr_inplace_update(MatrixQR &mat, HCoeffs &hCoeffs, const VectorQR &newColumn, typename MatrixQR::Index k, typename MatrixQR::Scalar *tempData)
void apply_block_householder_on_the_left(MatrixType &mat, const VectorsType &vectors, const CoeffsType &hCoeffs, bool forward)
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
Definition: BFloat16.h:222
Derived & derived()
Definition: EigenBase.h:48
Eigen::Index Index
The interface type of indices.
Definition: EigenBase.h:41
EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT
Definition: EigenBase.h:69