$darkmode
Eigen  5.0.1-dev
GeneralizedEigenSolver.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2012-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2010,2012 Jitse Niesen <jitse@maths.leeds.ac.uk>
6 // Copyright (C) 2016 Tobias Wood <tobias@spinicist.org.uk>
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_GENERALIZEDEIGENSOLVER_H
13 #define EIGEN_GENERALIZEDEIGENSOLVER_H
14 
15 #include "./RealQZ.h"
16 
17 // IWYU pragma: private
18 #include "./InternalHeaderCheck.h"
19 
20 namespace Eigen {
21 
61 template <typename MatrixType_>
63  public:
65  typedef MatrixType_ MatrixType;
66 
67  enum {
68  RowsAtCompileTime = MatrixType::RowsAtCompileTime,
69  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
70  Options = internal::traits<MatrixType>::Options,
71  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
72  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
73  };
74 
76  typedef typename MatrixType::Scalar Scalar;
77  typedef typename NumTraits<Scalar>::Real RealScalar;
78  typedef Eigen::Index Index;
79 
86  typedef internal::make_complex_t<Scalar> ComplexScalar;
87 
94 
101 
106 
112  typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime,
113  MaxColsAtCompileTime>
115 
124  : m_eivec(), m_alphas(), m_betas(), m_computeEigenvectors(false), m_isInitialized(false), m_realQZ() {}
125 
133  : m_eivec(size, size),
134  m_alphas(size),
135  m_betas(size),
136  m_computeEigenvectors(false),
137  m_isInitialized(false),
138  m_realQZ(size),
139  m_tmp(size) {}
140 
153  GeneralizedEigenSolver(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true)
154  : m_eivec(A.rows(), A.cols()),
155  m_alphas(A.cols()),
156  m_betas(A.cols()),
157  m_computeEigenvectors(false),
158  m_isInitialized(false),
159  m_realQZ(A.cols()),
160  m_tmp(A.cols()) {
161  compute(A, B, computeEigenvectors);
162  }
163 
177  eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute eigenvectors");
178  eigen_assert(m_computeEigenvectors && "Eigenvectors for GeneralizedEigenSolver were not calculated");
179  return m_eivec;
180  }
181 
201  eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute eigenvalues.");
202  return EigenvalueType(m_alphas, m_betas);
203  }
204 
210  const ComplexVectorType& alphas() const {
211  eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute alphas.");
212  return m_alphas;
213  }
214 
220  const VectorType& betas() const {
221  eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute betas.");
222  return m_betas;
223  }
224 
248  GeneralizedEigenSolver& compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true);
249 
250  ComputationInfo info() const {
251  eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
252  return m_realQZ.info();
253  }
254 
258  m_realQZ.setMaxIterations(maxIters);
259  return *this;
260  }
261 
262  protected:
263  EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
264  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
265 
266  EigenvectorsType m_eivec;
267  ComplexVectorType m_alphas;
268  VectorType m_betas;
269  bool m_computeEigenvectors;
270  bool m_isInitialized;
271  RealQZ<MatrixType> m_realQZ;
272  ComplexVectorType m_tmp;
273 };
274 
275 template <typename MatrixType>
277  const MatrixType& B,
278  bool computeEigenvectors) {
279  using std::abs;
280  using std::sqrt;
281  eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows());
282  Index size = A.cols();
283  // Reduce to generalized real Schur form:
284  // A = Q S Z and B = Q T Z
285  m_realQZ.compute(A, B, computeEigenvectors);
286  if (m_realQZ.info() == Success) {
287  // Resize storage
288  m_alphas.resize(size);
289  m_betas.resize(size);
290  if (computeEigenvectors) {
291  m_eivec.resize(size, size);
292  m_tmp.resize(size);
293  }
294 
295  // Aliases:
296  Map<VectorType> v(reinterpret_cast<Scalar*>(m_tmp.data()), size);
297  ComplexVectorType& cv = m_tmp;
298  const MatrixType& mS = m_realQZ.matrixS();
299  const MatrixType& mT = m_realQZ.matrixT();
300 
301  Index i = 0;
302  while (i < size) {
303  if (i == size - 1 || mS.coeff(i + 1, i) == Scalar(0)) {
304  // Real eigenvalue
305  m_alphas.coeffRef(i) = mS.diagonal().coeff(i);
306  m_betas.coeffRef(i) = mT.diagonal().coeff(i);
307  if (computeEigenvectors) {
308  v.setConstant(Scalar(0.0));
309  v.coeffRef(i) = Scalar(1.0);
310  // For singular eigenvalues do nothing more
311  if (abs(m_betas.coeffRef(i)) >= (std::numeric_limits<RealScalar>::min)()) {
312  // Non-singular eigenvalue
313  const Scalar alpha = real(m_alphas.coeffRef(i));
314  const Scalar beta = m_betas.coeffRef(i);
315  for (Index j = i - 1; j >= 0; j--) {
316  const Index st = j + 1;
317  const Index sz = i - j;
318  if (j > 0 && mS.coeff(j, j - 1) != Scalar(0)) {
319  // 2x2 block
320  Matrix<Scalar, 2, 1> rhs = (alpha * mT.template block<2, Dynamic>(j - 1, st, 2, sz) -
321  beta * mS.template block<2, Dynamic>(j - 1, st, 2, sz))
322  .lazyProduct(v.segment(st, sz));
324  beta * mS.template block<2, 2>(j - 1, j - 1) - alpha * mT.template block<2, 2>(j - 1, j - 1);
325  v.template segment<2>(j - 1) = lhs.partialPivLu().solve(rhs);
326  j--;
327  } else {
328  v.coeffRef(j) = -v.segment(st, sz)
329  .transpose()
330  .cwiseProduct(beta * mS.block(j, st, 1, sz) - alpha * mT.block(j, st, 1, sz))
331  .sum() /
332  (beta * mS.coeffRef(j, j) - alpha * mT.coeffRef(j, j));
333  }
334  }
335  }
336  m_eivec.col(i).real().noalias() = m_realQZ.matrixZ().transpose() * v;
337  m_eivec.col(i).real().normalize();
338  m_eivec.col(i).imag().setConstant(0);
339  }
340  ++i;
341  } else {
342  // We need to extract the generalized eigenvalues of the pair of a general 2x2 block S and a positive diagonal
343  // 2x2 block T Then taking beta=T_00*T_11, we can avoid any division, and alpha is the eigenvalues of A = (U^-1
344  // * S * U) * diag(T_11,T_00):
345 
346  // T = [a 0]
347  // [0 b]
348  RealScalar a = mT.diagonal().coeff(i), b = mT.diagonal().coeff(i + 1);
349  const RealScalar beta = m_betas.coeffRef(i) = m_betas.coeffRef(i + 1) = a * b;
350 
351  // ^^ NOTE: using diagonal()(i) instead of coeff(i,i) workarounds a MSVC bug.
352  Matrix<RealScalar, 2, 2> S2 = mS.template block<2, 2>(i, i) * Matrix<Scalar, 2, 1>(b, a).asDiagonal();
353 
354  Scalar p = Scalar(0.5) * (S2.coeff(0, 0) - S2.coeff(1, 1));
355  Scalar z = sqrt(abs(p * p + S2.coeff(1, 0) * S2.coeff(0, 1)));
356  const ComplexScalar alpha = ComplexScalar(S2.coeff(1, 1) + p, (beta > 0) ? z : -z);
357  m_alphas.coeffRef(i) = conj(alpha);
358  m_alphas.coeffRef(i + 1) = alpha;
359 
360  if (computeEigenvectors) {
361  // Compute eigenvector in position (i+1) and then position (i) is just the conjugate
362  cv.setZero();
363  cv.coeffRef(i + 1) = Scalar(1.0);
364  // here, the "static_cast" workaround expression template issues.
365  cv.coeffRef(i) = -(static_cast<Scalar>(beta * mS.coeffRef(i, i + 1)) - alpha * mT.coeffRef(i, i + 1)) /
366  (static_cast<Scalar>(beta * mS.coeffRef(i, i)) - alpha * mT.coeffRef(i, i));
367  for (Index j = i - 1; j >= 0; j--) {
368  const Index st = j + 1;
369  const Index sz = i + 1 - j;
370  if (j > 0 && mS.coeff(j, j - 1) != Scalar(0)) {
371  // 2x2 block
372  Matrix<ComplexScalar, 2, 1> rhs = (alpha * mT.template block<2, Dynamic>(j - 1, st, 2, sz) -
373  beta * mS.template block<2, Dynamic>(j - 1, st, 2, sz))
374  .lazyProduct(cv.segment(st, sz));
376  beta * mS.template block<2, 2>(j - 1, j - 1) - alpha * mT.template block<2, 2>(j - 1, j - 1);
377  cv.template segment<2>(j - 1) = lhs.partialPivLu().solve(rhs);
378  j--;
379  } else {
380  cv.coeffRef(j) = cv.segment(st, sz)
381  .transpose()
382  .cwiseProduct(beta * mS.block(j, st, 1, sz) - alpha * mT.block(j, st, 1, sz))
383  .sum() /
384  (alpha * mT.coeffRef(j, j) - static_cast<Scalar>(beta * mS.coeffRef(j, j)));
385  }
386  }
387  m_eivec.col(i + 1).noalias() = (m_realQZ.matrixZ().transpose() * cv);
388  m_eivec.col(i + 1).normalize();
389  m_eivec.col(i) = m_eivec.col(i + 1).conjugate();
390  }
391  i += 2;
392  }
393  }
394  }
395  m_computeEigenvectors = computeEigenvectors;
396  m_isInitialized = true;
397  return *this;
398 }
399 
400 } // end namespace Eigen
401 
402 #endif // EIGEN_GENERALIZEDEIGENSOLVER_H
MatrixType_ MatrixType
Synonym for the template parameter MatrixType_.
Definition: GeneralizedEigenSolver.h:65
RealQZ & setMaxIterations(Index maxIters)
Definition: RealQZ.h:185
CwiseBinaryOp< internal::scalar_quotient_op< ComplexScalar, Scalar >, ComplexVectorType, VectorType > EigenvalueType
Expression type for the eigenvalues as returned by eigenvalues().
Definition: GeneralizedEigenSolver.h:105
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:96
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)
Matrix< Scalar, ColsAtCompileTime, 1, Options &~RowMajor, MaxColsAtCompileTime, 1 > VectorType
Type for vector of real scalar values eigenvalues as returned by betas().
Definition: GeneralizedEigenSolver.h:93
GeneralizedEigenSolver()
Default constructor.
Definition: GeneralizedEigenSolver.h:123
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1
const ComplexVectorType & alphas() const
Definition: GeneralizedEigenSolver.h:210
Holds information about the various numeric (i.e. scalar) types allowed by Eigen. ...
Definition: NumTraits.h:232
internal::make_complex_t< Scalar > ComplexScalar
Complex scalar type for MatrixType.
Definition: GeneralizedEigenSolver.h:86
GeneralizedEigenSolver & compute(const MatrixType &A, const MatrixType &B, bool computeEigenvectors=true)
Computes generalized eigendecomposition of given matrix.
Definition: GeneralizedEigenSolver.h:276
Matrix< ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime > EigenvectorsType
Type for matrix of eigenvectors as returned by eigenvectors().
Definition: GeneralizedEigenSolver.h:114
Derived & setZero(Index size)
Definition: CwiseNullaryOp.h:567
Generic expression where a coefficient-wise binary operator is applied to two expressions.
Definition: CwiseBinaryOp.h:75
EigenvectorsType eigenvectors() const
Returns the computed generalized eigenvectors.
Definition: GeneralizedEigenSolver.h:176
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const VectorType & betas() const
Definition: GeneralizedEigenSolver.h:220
MatrixType::Scalar Scalar
Scalar type for matrices of type MatrixType.
Definition: GeneralizedEigenSolver.h:76
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_real_op< typename Derived::Scalar >, const Derived > real(const Eigen::ArrayBase< Derived > &x)
Definition: Constants.h:440
GeneralizedEigenSolver & setMaxIterations(Index maxIters)
Definition: GeneralizedEigenSolver.h:257
GeneralizedEigenSolver(const MatrixType &A, const MatrixType &B, bool computeEigenvectors=true)
Constructor; computes the generalized eigendecomposition of given matrix pair.
Definition: GeneralizedEigenSolver.h:153
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: RealQZ.h:170
constexpr const Scalar & coeff(Index rowId, Index colId) const
Definition: PlainObjectBase.h:172
Eigen::Index Index
Definition: GeneralizedEigenSolver.h:78
Matrix< ComplexScalar, ColsAtCompileTime, 1, Options &~RowMajor, MaxColsAtCompileTime, 1 > ComplexVectorType
Type for vector of complex scalar values eigenvalues as returned by alphas().
Definition: GeneralizedEigenSolver.h:100
constexpr Scalar & coeffRef(Index rowId, Index colId)
Definition: PlainObjectBase.h:191
GeneralizedEigenSolver(Index size)
Default constructor with memory preallocation.
Definition: GeneralizedEigenSolver.h:132
Computes the generalized eigenvalues and eigenvectors of a pair of general matrices.
Definition: GeneralizedEigenSolver.h:62
ComputationInfo
Definition: Constants.h:438
EigenvalueType eigenvalues() const
Returns an expression of the computed generalized eigenvalues.
Definition: GeneralizedEigenSolver.h:200