$darkmode
Eigen  5.0.1-dev
Tridiagonalization.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
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 
11 #ifndef EIGEN_TRIDIAGONALIZATION_H
12 #define EIGEN_TRIDIAGONALIZATION_H
13 
14 // IWYU pragma: private
15 #include "./InternalHeaderCheck.h"
16 
17 namespace Eigen {
18 
19 namespace internal {
20 
21 template <typename MatrixType>
22 struct TridiagonalizationMatrixTReturnType;
23 template <typename MatrixType>
24 struct traits<TridiagonalizationMatrixTReturnType<MatrixType>> : public traits<typename MatrixType::PlainObject> {
25  typedef typename MatrixType::PlainObject ReturnType; // FIXME shall it be a BandMatrix?
26  enum { Flags = 0 };
27 };
28 
29 template <typename MatrixType, typename CoeffVectorType>
30 EIGEN_DEVICE_FUNC void tridiagonalization_inplace(MatrixType& matA, CoeffVectorType& hCoeffs);
31 } // namespace internal
32 
65 template <typename MatrixType_>
67  public:
69  typedef MatrixType_ MatrixType;
70 
71  typedef typename MatrixType::Scalar Scalar;
72  typedef typename NumTraits<Scalar>::Real RealScalar;
73  typedef Eigen::Index Index;
74 
75  enum {
76  Size = MatrixType::RowsAtCompileTime,
77  SizeMinusOne = Size == Dynamic ? Dynamic : (Size > 1 ? Size - 1 : 1),
78  Options = internal::traits<MatrixType>::Options,
79  MaxSize = MatrixType::MaxRowsAtCompileTime,
80  MaxSizeMinusOne = MaxSize == Dynamic ? Dynamic : (MaxSize > 1 ? MaxSize - 1 : 1)
81  };
82 
84  typedef typename internal::plain_col_type<MatrixType, RealScalar>::type DiagonalType;
86  typedef internal::remove_all_t<typename MatrixType::RealReturnType> MatrixTypeRealView;
87  typedef internal::TridiagonalizationMatrixTReturnType<MatrixTypeRealView> MatrixTReturnType;
88 
89  typedef std::conditional_t<NumTraits<Scalar>::IsComplex,
90  internal::add_const_on_value_type_t<typename Diagonal<const MatrixType>::RealReturnType>,
92  DiagonalReturnType;
93 
94  typedef std::conditional_t<
96  internal::add_const_on_value_type_t<typename Diagonal<const MatrixType, -1>::RealReturnType>,
97  const Diagonal<const MatrixType, -1>>
98  SubDiagonalReturnType;
99 
103 
116  explicit Tridiagonalization(Index size = Size == Dynamic ? 2 : Size)
117  : m_matrix(size, size), m_hCoeffs(size > 1 ? size - 1 : 1), m_isInitialized(false) {}
118 
129  template <typename InputType>
130  explicit Tridiagonalization(const EigenBase<InputType>& matrix)
131  : m_matrix(matrix.derived()), m_hCoeffs(matrix.cols() > 1 ? matrix.cols() - 1 : 1), m_isInitialized(false) {
132  internal::tridiagonalization_inplace(m_matrix, m_hCoeffs);
133  m_isInitialized = true;
134  }
135 
153  template <typename InputType>
155  m_matrix = matrix.derived();
156  m_hCoeffs.resize(matrix.rows() - 1, 1);
157  internal::tridiagonalization_inplace(m_matrix, m_hCoeffs);
158  m_isInitialized = true;
159  return *this;
160  }
161 
179  eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
180  return m_hCoeffs;
181  }
182 
214  inline const MatrixType& packedMatrix() const {
215  eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
216  return m_matrix;
217  }
218 
235  eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
236  return HouseholderSequenceType(m_matrix, m_hCoeffs.conjugate()).setLength(m_matrix.rows() - 1).setShift(1);
237  }
238 
256  MatrixTReturnType matrixT() const {
257  eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
258  return MatrixTReturnType(m_matrix.real());
259  }
260 
274  DiagonalReturnType diagonal() const;
275 
286  SubDiagonalReturnType subDiagonal() const;
287 
288  protected:
289  MatrixType m_matrix;
290  CoeffVectorType m_hCoeffs;
291  bool m_isInitialized;
292 };
293 
294 template <typename MatrixType>
295 typename Tridiagonalization<MatrixType>::DiagonalReturnType Tridiagonalization<MatrixType>::diagonal() const {
296  eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
297  return m_matrix.diagonal().real();
298 }
299 
300 template <typename MatrixType>
301 typename Tridiagonalization<MatrixType>::SubDiagonalReturnType Tridiagonalization<MatrixType>::subDiagonal() const {
302  eigen_assert(m_isInitialized && "Tridiagonalization is not initialized.");
303  return m_matrix.template diagonal<-1>().real();
304 }
305 
306 namespace internal {
307 
331 template <typename MatrixType, typename CoeffVectorType>
332 EIGEN_DEVICE_FUNC void tridiagonalization_inplace(MatrixType& matA, CoeffVectorType& hCoeffs) {
333  using numext::conj;
334  typedef typename MatrixType::Scalar Scalar;
335  typedef typename MatrixType::RealScalar RealScalar;
336  Index n = matA.rows();
337  eigen_assert(n == matA.cols());
338  eigen_assert(n == hCoeffs.size() + 1 || n == 1);
339 
340  for (Index i = 0; i < n - 1; ++i) {
341  Index remainingSize = n - i - 1;
342  RealScalar beta;
343  Scalar h;
344  matA.col(i).tail(remainingSize).makeHouseholderInPlace(h, beta);
345 
346  // Apply similarity transformation to remaining columns,
347  // i.e., A = H A H' where H = I - h v v' and v = matA.col(i).tail(n-i-1)
348  matA.col(i).coeffRef(i + 1) = Scalar(1);
349 
350  hCoeffs.tail(n - i - 1).noalias() =
351  (matA.bottomRightCorner(remainingSize, remainingSize).template selfadjointView<Lower>() *
352  (conj(h) * matA.col(i).tail(remainingSize)));
353 
354  hCoeffs.tail(n - i - 1) +=
355  (conj(h) * RealScalar(-0.5) * (hCoeffs.tail(remainingSize).dot(matA.col(i).tail(remainingSize)))) *
356  matA.col(i).tail(n - i - 1);
357 
358  matA.bottomRightCorner(remainingSize, remainingSize)
359  .template selfadjointView<Lower>()
360  .rankUpdate(matA.col(i).tail(remainingSize), hCoeffs.tail(remainingSize), Scalar(-1));
361 
362  matA.col(i).coeffRef(i + 1) = beta;
363  hCoeffs.coeffRef(i) = h;
364  }
365 }
366 
367 // forward declaration, implementation at the end of this file
368 template <typename MatrixType, int Size = MatrixType::ColsAtCompileTime,
369  bool IsComplex = NumTraits<typename MatrixType::Scalar>::IsComplex>
370 struct tridiagonalization_inplace_selector;
371 
414 template <typename MatrixType, typename DiagonalType, typename SubDiagonalType, typename CoeffVectorType,
415  typename WorkSpaceType>
416 EIGEN_DEVICE_FUNC void tridiagonalization_inplace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag,
417  CoeffVectorType& hcoeffs, WorkSpaceType& workspace, bool extractQ) {
418  eigen_assert(mat.cols() == mat.rows() && diag.size() == mat.rows() && subdiag.size() == mat.rows() - 1);
419  tridiagonalization_inplace_selector<MatrixType>::run(mat, diag, subdiag, hcoeffs, workspace, extractQ);
420 }
421 
425 template <typename MatrixType, int Size, bool IsComplex>
426 struct tridiagonalization_inplace_selector {
427  typedef typename Tridiagonalization<MatrixType>::HouseholderSequenceType HouseholderSequenceType;
428  template <typename DiagonalType, typename SubDiagonalType, typename CoeffVectorType, typename WorkSpaceType>
429  static EIGEN_DEVICE_FUNC void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag,
430  CoeffVectorType& hCoeffs, WorkSpaceType& workspace, bool extractQ) {
431  tridiagonalization_inplace(mat, hCoeffs);
432  diag = mat.diagonal().real();
433  subdiag = mat.template diagonal<-1>().real();
434  if (extractQ) {
435  HouseholderSequenceType(mat, hCoeffs.conjugate()).setLength(mat.rows() - 1).setShift(1).evalTo(mat, workspace);
436  }
437  }
438 };
439 
444 template <typename MatrixType>
445 struct tridiagonalization_inplace_selector<MatrixType, 3, false> {
446  typedef typename MatrixType::Scalar Scalar;
447  typedef typename MatrixType::RealScalar RealScalar;
448 
449  template <typename DiagonalType, typename SubDiagonalType, typename CoeffVectorType, typename WorkSpaceType>
450  static EIGEN_DEVICE_FUNC void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, CoeffVectorType&,
451  WorkSpaceType&, bool extractQ) {
452  using std::sqrt;
453  const RealScalar tol = (std::numeric_limits<RealScalar>::min)();
454  diag[0] = mat(0, 0);
455  RealScalar v1norm2 = numext::abs2(mat(2, 0));
456  if (v1norm2 <= tol) {
457  diag[1] = mat(1, 1);
458  diag[2] = mat(2, 2);
459  subdiag[0] = mat(1, 0);
460  subdiag[1] = mat(2, 1);
461  if (extractQ) mat.setIdentity();
462  } else {
463  RealScalar beta = sqrt(numext::abs2(mat(1, 0)) + v1norm2);
464  RealScalar invBeta = RealScalar(1) / beta;
465  Scalar m01 = mat(1, 0) * invBeta;
466  Scalar m02 = mat(2, 0) * invBeta;
467  Scalar q = RealScalar(2) * m01 * mat(2, 1) + m02 * (mat(2, 2) - mat(1, 1));
468  diag[1] = mat(1, 1) + m02 * q;
469  diag[2] = mat(2, 2) - m02 * q;
470  subdiag[0] = beta;
471  subdiag[1] = mat(2, 1) - m01 * q;
472  if (extractQ) {
473  mat << 1, 0, 0, 0, m01, m02, 0, m02, -m01;
474  }
475  }
476  }
477 };
478 
482 template <typename MatrixType, bool IsComplex>
483 struct tridiagonalization_inplace_selector<MatrixType, 1, IsComplex> {
484  typedef typename MatrixType::Scalar Scalar;
485 
486  template <typename DiagonalType, typename SubDiagonalType, typename CoeffVectorType, typename WorkSpaceType>
487  static EIGEN_DEVICE_FUNC void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType&, CoeffVectorType&,
488  WorkSpaceType&, bool extractQ) {
489  diag(0, 0) = numext::real(mat(0, 0));
490  if (extractQ) mat(0, 0) = Scalar(1);
491  }
492 };
493 
501 template <typename MatrixType>
502 struct TridiagonalizationMatrixTReturnType : public ReturnByValue<TridiagonalizationMatrixTReturnType<MatrixType>> {
503  public:
508  TridiagonalizationMatrixTReturnType(const MatrixType& mat) : m_matrix(mat) {}
509 
510  template <typename ResultType>
511  inline void evalTo(ResultType& result) const {
512  result.setZero();
513  result.template diagonal<1>() = m_matrix.template diagonal<-1>().conjugate();
514  result.diagonal() = m_matrix.diagonal();
515  result.template diagonal<-1>() = m_matrix.template diagonal<-1>();
516  }
517 
518  constexpr Index rows() const noexcept { return m_matrix.rows(); }
519  constexpr Index cols() const noexcept { return m_matrix.cols(); }
520 
521  protected:
522  typename MatrixType::Nested m_matrix;
523 };
524 
525 } // end namespace internal
526 
527 } // end namespace Eigen
528 
529 #endif // EIGEN_TRIDIAGONALIZATION_H
DiagonalReturnType diagonal() const
Returns the diagonal of the tridiagonal matrix T in the decomposition.
Definition: Tridiagonalization.h:295
constexpr void resize(Index rows, Index cols)
Definition: PlainObjectBase.h:268
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1
Tridiagonalization & compute(const EigenBase< InputType > &matrix)
Computes tridiagonal decomposition of given matrix.
Definition: Tridiagonalization.h:154
Holds information about the various numeric (i.e. scalar) types allowed by Eigen. ...
Definition: NumTraits.h:232
Tridiagonal decomposition of a selfadjoint matrix.
Definition: Tridiagonalization.h:66
Eigen::Index Index
Definition: Tridiagonalization.h:73
constexpr Index rows() const noexcept
Definition: EigenBase.h:59
Definition: EigenBase.h:33
Sequence of Householder reflections acting on subspaces with decreasing size.
Definition: ForwardDeclarations.h:445
MatrixType_ MatrixType
Synonym for the template parameter MatrixType_.
Definition: Tridiagonalization.h:69
HouseholderSequenceType matrixQ() const
Returns the unitary matrix Q in the decomposition.
Definition: Tridiagonalization.h:234
const MatrixType & packedMatrix() const
Returns the internal representation of the decomposition.
Definition: Tridiagonalization.h:214
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
Tridiagonalization(const EigenBase< InputType > &matrix)
Constructor; computes tridiagonal decomposition of given matrix.
Definition: Tridiagonalization.h:130
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_real_op< typename Derived::Scalar >, const Derived > real(const Eigen::ArrayBase< Derived > &x)
constexpr Derived & derived()
Definition: EigenBase.h:49
CoeffVectorType householderCoefficients() const
Returns the Householder coefficients.
Definition: Tridiagonalization.h:178
HouseholderSequence< MatrixType, internal::remove_all_t< typename CoeffVectorType::ConjugateReturnType > > HouseholderSequenceType
Return type of matrixQ()
Definition: Tridiagonalization.h:102
Expression of a diagonal/subdiagonal/superdiagonal in a matrix.
Definition: Diagonal.h:68
const int Dynamic
Definition: Constants.h:25
MatrixTReturnType matrixT() const
Returns an expression of the tridiagonal matrix T in the decomposition.
Definition: Tridiagonalization.h:256
SubDiagonalReturnType subDiagonal() const
Returns the subdiagonal of the tridiagonal matrix T in the decomposition.
Definition: Tridiagonalization.h:301
Tridiagonalization(Index size=Size==Dynamic ? 2 :Size)
Default constructor.
Definition: Tridiagonalization.h:116