GeneralizedEigenSolver.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) 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,
71  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
72  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
73  };
74 
76  typedef typename MatrixType::Scalar Scalar;
78  typedef Eigen::Index Index;
79 
86  typedef std::complex<RealScalar> ComplexScalar;
87 
94 
101 
106 
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.");
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 
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:
264  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
265 
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
290  if (computeEigenvectors) {
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
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);
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
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
int i
Definition: BiCGSTAB_step_by_step.cpp:9
#define eigen_assert(x)
Definition: Macros.h:910
m block< 2, Dynamic >(1, 1, 2, 3).setZero()
#define EIGEN_STATIC_ASSERT(X, MSG)
Definition: StaticAssert.h:26
#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE)
Definition: StaticAssert.h:74
float * p
Definition: Tutorial_Map_using.cpp:9
int rows
Definition: Tutorial_commainit_02.cpp:1
int cols
Definition: Tutorial_commainit_02.cpp:1
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
Scalar * b
Definition: benchVecAdd.cpp:17
SCALAR Scalar
Definition: bench_gemm.cpp:45
MatrixXf MatrixType
Definition: benchmark-blocking-sizes.cpp:52
Generic expression where a coefficient-wise binary operator is applied to two expressions.
Definition: CwiseBinaryOp.h:79
Computes the generalized eigenvalues and eigenvectors of a pair of general matrices.
Definition: GeneralizedEigenSolver.h:62
bool m_isInitialized
Definition: GeneralizedEigenSolver.h:270
CwiseBinaryOp< internal::scalar_quotient_op< ComplexScalar, Scalar >, ComplexVectorType, VectorType > EigenvalueType
Expression type for the eigenvalues as returned by eigenvalues().
Definition: GeneralizedEigenSolver.h:105
EigenvectorsType m_eivec
Definition: GeneralizedEigenSolver.h:266
EigenvectorsType eigenvectors() const
Returns the computed generalized eigenvectors.
Definition: GeneralizedEigenSolver.h:176
ComputationInfo info() const
Definition: GeneralizedEigenSolver.h:250
GeneralizedEigenSolver & compute(const MatrixType &A, const MatrixType &B, bool computeEigenvectors=true)
Computes generalized eigendecomposition of given matrix.
Definition: GeneralizedEigenSolver.h:276
ComplexVectorType m_alphas
Definition: GeneralizedEigenSolver.h:267
GeneralizedEigenSolver & setMaxIterations(Index maxIters)
Definition: GeneralizedEigenSolver.h:257
ComplexVectorType m_tmp
Definition: GeneralizedEigenSolver.h:272
std::complex< RealScalar > ComplexScalar
Complex scalar type for MatrixType.
Definition: GeneralizedEigenSolver.h:86
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
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
const VectorType & betas() const
Definition: GeneralizedEigenSolver.h:220
bool m_computeEigenvectors
Definition: GeneralizedEigenSolver.h:269
MatrixType::Scalar Scalar
Scalar type for matrices of type MatrixType.
Definition: GeneralizedEigenSolver.h:76
GeneralizedEigenSolver()
Default constructor.
Definition: GeneralizedEigenSolver.h:123
Eigen::Index Index
Definition: GeneralizedEigenSolver.h:78
const ComplexVectorType & alphas() const
Definition: GeneralizedEigenSolver.h:210
GeneralizedEigenSolver(const MatrixType &A, const MatrixType &B, bool computeEigenvectors=true)
Constructor; computes the generalized eigendecomposition of given matrix pair.
Definition: GeneralizedEigenSolver.h:153
EigenvalueType eigenvalues() const
Returns an expression of the computed generalized eigenvalues.
Definition: GeneralizedEigenSolver.h:200
NumTraits< Scalar >::Real RealScalar
Definition: GeneralizedEigenSolver.h:77
GeneralizedEigenSolver(Index size)
Default constructor with memory preallocation.
Definition: GeneralizedEigenSolver.h:132
VectorType m_betas
Definition: GeneralizedEigenSolver.h:268
RealQZ< MatrixType > m_realQZ
Definition: GeneralizedEigenSolver.h:271
@ ColsAtCompileTime
Definition: GeneralizedEigenSolver.h:69
@ MaxColsAtCompileTime
Definition: GeneralizedEigenSolver.h:72
@ MaxRowsAtCompileTime
Definition: GeneralizedEigenSolver.h:71
@ Options
Definition: GeneralizedEigenSolver.h:70
@ RowsAtCompileTime
Definition: GeneralizedEigenSolver.h:68
Matrix< ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime > EigenvectorsType
Type for matrix of eigenvectors as returned by eigenvectors().
Definition: GeneralizedEigenSolver.h:114
MatrixType_ MatrixType
Synonym for the template parameter MatrixType_.
Definition: GeneralizedEigenSolver.h:65
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:96
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar & coeffRef(Index rowId, Index colId)
Definition: PlainObjectBase.h:217
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE const Scalar & coeff(Index rowId, Index colId) const
Definition: PlainObjectBase.h:198
constexpr EIGEN_DEVICE_FUNC const Scalar * data() const
Definition: PlainObjectBase.h:273
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT
Definition: PlainObjectBase.h:192
EIGEN_DEVICE_FUNC Derived & setZero(Index size)
Definition: CwiseNullaryOp.h:569
EIGEN_DEVICE_FUNC Derived & setConstant(Index size, const Scalar &val)
Definition: CwiseNullaryOp.h:365
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE void resize(Index rows, Index cols)
Definition: PlainObjectBase.h:294
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT
Definition: PlainObjectBase.h:191
Performs a real QZ decomposition of a pair of square matrices.
Definition: RealQZ.h:61
RealQZ & compute(const MatrixType &A, const MatrixType &B, bool computeQZ=true)
Computes QZ decomposition of given matrix.
Definition: RealQZ.h:502
RealQZ & setMaxIterations(Index maxIters)
Definition: RealQZ.h:185
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: RealQZ.h:170
const MatrixType & matrixZ() const
Returns matrix Z in the QZ decomposition.
Definition: RealQZ.h:133
const MatrixType & matrixT() const
Returns matrix S in the QZ decomposition.
Definition: RealQZ.h:152
const MatrixType & matrixS() const
Returns matrix S in the QZ decomposition.
Definition: RealQZ.h:143
Definition: matrices.h:74
#define min(a, b)
Definition: datatypes.h:22
ComputationInfo
Definition: Constants.h:438
@ Success
Definition: Constants.h:440
RealScalar alpha
Definition: level1_cplx_impl.h:151
const Scalar * a
Definition: level2_cplx_impl.h:32
Scalar beta
Definition: level2_cplx_impl.h:36
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
const AutoDiffScalar< DerType > & real(const AutoDiffScalar< DerType > &x)
Definition: AutoDiffScalar.h:486
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:83
const AutoDiffScalar< DerType > & conj(const AutoDiffScalar< DerType > &x)
Definition: AutoDiffScalar.h:482
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:217
Definition: ForwardDeclarations.h:21
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2