Eigen  5.0.1
 
Loading...
Searching...
No Matches
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// SPDX-License-Identifier: MPL-2.0
12
13#ifndef EIGEN_GENERALIZEDEIGENSOLVER_H
14#define EIGEN_GENERALIZEDEIGENSOLVER_H
15
16#include "./RealQZ.h"
17
18// IWYU pragma: private
19#include "./InternalHeaderCheck.h"
20
21namespace Eigen {
22
62template <typename MatrixType_>
64 public:
66 using MatrixType = MatrixType_;
67
68 enum {
69 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
70 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
71 Options = internal::plain_object_options<MatrixType>::value,
72 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
73 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
74 };
75
77 using Scalar = typename MatrixType::Scalar;
78 using RealScalar = typename NumTraits<Scalar>::Real;
79 using Index = Eigen::Index;
80
87 using ComplexScalar = internal::make_complex_t<Scalar>;
88
95
102
107
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 template <typename InputTypeA, typename InputTypeB>
155 bool computeEigenvectors = true)
156 : m_eivec(A.rows(), A.cols()),
157 m_alphas(A.cols()),
158 m_betas(A.cols()),
159 m_computeEigenvectors(false),
160 m_isInitialized(false),
161 m_realQZ(A.derived(), B.derived(), computeEigenvectors),
162 m_tmp(A.cols()) {
163 computeFromQZ(computeEigenvectors);
164 }
165
177 template <typename InputTypeA, typename InputTypeB>
179 : m_eivec(A.rows(), A.cols()),
180 m_alphas(A.cols()),
181 m_betas(A.cols()),
182 m_computeEigenvectors(false),
183 m_isInitialized(false),
184 m_realQZ(A.derived(), B.derived(), computeEigenvectors),
185 m_tmp(A.cols()) {
186 computeFromQZ(computeEigenvectors);
187 }
188
202 eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute eigenvectors");
203 eigen_assert(m_computeEigenvectors && "Eigenvectors for GeneralizedEigenSolver were not calculated");
204 return m_eivec;
205 }
206
226 eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute eigenvalues.");
227 return EigenvalueType(m_alphas, m_betas);
228 }
229
235 const ComplexVectorType& alphas() const {
236 eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute alphas.");
237 return m_alphas;
238 }
239
245 const VectorType& betas() const {
246 eigen_assert(info() == Success && "GeneralizedEigenSolver failed to compute betas.");
247 return m_betas;
248 }
249
273 template <typename InputTypeA, typename InputTypeB>
275 bool computeEigenvectors = true);
276
277 ComputationInfo info() const {
278 eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
279 return m_realQZ.info();
280 }
281
285 m_realQZ.setMaxIterations(maxIters);
286 return *this;
287 }
288
289 protected:
290 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
291 EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
292
293 EigenvectorsType m_eivec;
294 ComplexVectorType m_alphas;
295 VectorType m_betas;
296 bool m_computeEigenvectors;
297 bool m_isInitialized;
298 RealQZ<MatrixType> m_realQZ;
299 ComplexVectorType m_tmp;
300
301 private:
302 GeneralizedEigenSolver& computeFromQZ(bool computeEigenvectors);
303};
304
305template <typename MatrixType>
306template <typename InputTypeA, typename InputTypeB>
307GeneralizedEigenSolver<MatrixType>& GeneralizedEigenSolver<MatrixType>::compute(const EigenBase<InputTypeA>& A,
308 const EigenBase<InputTypeB>& B,
309 bool computeEigenvectors) {
310 eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows());
311 // Reduce to generalized real Schur form:
312 // A = Q S Z and B = Q T Z
313 m_realQZ.compute(A.derived(), B.derived(), computeEigenvectors);
314 return computeFromQZ(computeEigenvectors);
315}
316
319template <typename MatrixType>
320GeneralizedEigenSolver<MatrixType>& GeneralizedEigenSolver<MatrixType>::computeFromQZ(bool computeEigenvectors) {
321 const Index size = m_realQZ.matrixS().cols();
322 if (m_realQZ.info() == Success) {
323 // Resize storage
324 m_alphas.resize(size);
325 m_betas.resize(size);
326 if (computeEigenvectors) {
327 m_eivec.resize(size, size);
328 m_tmp.resize(size);
329 }
330
331 // Aliases:
332 Map<VectorType> v(reinterpret_cast<Scalar*>(m_tmp.data()), size);
333 ComplexVectorType& cv = m_tmp;
334 const MatrixType& mS = m_realQZ.matrixS();
335 const MatrixType& mT = m_realQZ.matrixT();
336
337 Index i = 0;
338 while (i < size) {
339 if (i == size - 1 || mS.coeff(i + 1, i) == Scalar(0)) {
340 // Real eigenvalue
341 m_alphas.coeffRef(i) = mS.diagonal().coeff(i);
342 m_betas.coeffRef(i) = mT.diagonal().coeff(i);
343 if (computeEigenvectors) {
344 v.setConstant(Scalar(0.0));
345 v.coeffRef(i) = Scalar(1.0);
346 // For singular eigenvalues do nothing more
347 if (numext::abs(m_betas.coeffRef(i)) >= (std::numeric_limits<RealScalar>::min)()) {
348 // Non-singular eigenvalue
349 const Scalar alpha = real(m_alphas.coeffRef(i));
350 const Scalar beta = m_betas.coeffRef(i);
351 for (Index j = i - 1; j >= 0; j--) {
352 const Index st = j + 1;
353 const Index sz = i - j;
354 if (j > 0 && mS.coeff(j, j - 1) != Scalar(0)) {
355 // 2x2 block
356 Matrix<Scalar, 2, 1> rhs = (alpha * mT.template block<2, Dynamic>(j - 1, st, 2, sz) -
357 beta * mS.template block<2, Dynamic>(j - 1, st, 2, sz))
358 .lazyProduct(v.segment(st, sz));
360 beta * mS.template block<2, 2>(j - 1, j - 1) - alpha * mT.template block<2, 2>(j - 1, j - 1);
361 v.template segment<2>(j - 1) = lhs.partialPivLu().solve(rhs);
362 j--;
363 } else {
364 v.coeffRef(j) = -v.segment(st, sz)
365 .transpose()
366 .cwiseProduct(beta * mS.block(j, st, 1, sz) - alpha * mT.block(j, st, 1, sz))
367 .sum() /
368 (beta * mS.coeffRef(j, j) - alpha * mT.coeffRef(j, j));
369 }
370 }
371 }
372 m_eivec.col(i).real().noalias() = m_realQZ.matrixZ().transpose() * v;
373 m_eivec.col(i).real().normalize();
374 m_eivec.col(i).imag().setConstant(0);
375 }
376 ++i;
377 } else {
378 // We need to extract the generalized eigenvalues of the pair of a general 2x2 block S and a positive diagonal
379 // 2x2 block T Then taking beta=T_00*T_11, we can avoid any division, and alpha is the eigenvalues of A = (U^-1
380 // * S * U) * diag(T_11,T_00):
381
382 // T = [a 0]
383 // [0 b]
384 RealScalar a = mT.diagonal().coeff(i), b = mT.diagonal().coeff(i + 1);
385 const RealScalar beta = m_betas.coeffRef(i) = m_betas.coeffRef(i + 1) = a * b;
386
387 // ^^ NOTE: using diagonal()(i) instead of coeff(i,i) workarounds a MSVC bug.
388 Matrix<RealScalar, 2, 2> S2 = mS.template block<2, 2>(i, i) * Matrix<Scalar, 2, 1>(b, a).asDiagonal();
389
390 Scalar p = Scalar(0.5) * (S2.coeff(0, 0) - S2.coeff(1, 1));
391 Scalar z = numext::sqrt(numext::abs(p * p + S2.coeff(1, 0) * S2.coeff(0, 1)));
392 const ComplexScalar alpha = ComplexScalar(S2.coeff(1, 1) + p, (beta > 0) ? z : -z);
393 m_alphas.coeffRef(i) = conj(alpha);
394 m_alphas.coeffRef(i + 1) = alpha;
395
396 if (computeEigenvectors) {
397 // Compute eigenvector in position (i+1) and then position (i) is just the conjugate
398 cv.setZero();
399 cv.coeffRef(i + 1) = Scalar(1.0);
400 // here, the "static_cast" works around expression template issues.
401 cv.coeffRef(i) = -(static_cast<Scalar>(beta * mS.coeffRef(i, i + 1)) - alpha * mT.coeffRef(i, i + 1)) /
402 (static_cast<Scalar>(beta * mS.coeffRef(i, i)) - alpha * mT.coeffRef(i, i));
403 for (Index j = i - 1; j >= 0; j--) {
404 const Index st = j + 1;
405 const Index sz = i + 1 - j;
406 if (j > 0 && mS.coeff(j, j - 1) != Scalar(0)) {
407 // 2x2 block
408 Matrix<ComplexScalar, 2, 1> rhs = (alpha * mT.template block<2, Dynamic>(j - 1, st, 2, sz) -
409 beta * mS.template block<2, Dynamic>(j - 1, st, 2, sz))
410 .lazyProduct(cv.segment(st, sz));
412 beta * mS.template block<2, 2>(j - 1, j - 1) - alpha * mT.template block<2, 2>(j - 1, j - 1);
413 cv.template segment<2>(j - 1) = lhs.partialPivLu().solve(rhs);
414 j--;
415 } else {
416 cv.coeffRef(j) = cv.segment(st, sz)
417 .transpose()
418 .cwiseProduct(beta * mS.block(j, st, 1, sz) - alpha * mT.block(j, st, 1, sz))
419 .sum() /
420 (alpha * mT.coeffRef(j, j) - static_cast<Scalar>(beta * mS.coeffRef(j, j)));
421 }
422 }
423 m_eivec.col(i + 1).noalias() = m_realQZ.matrixZ().transpose() * cv;
424 m_eivec.col(i + 1).normalize();
425 m_eivec.col(i) = m_eivec.col(i + 1).conjugate();
426 }
427 i += 2;
428 }
429 }
430 }
431 m_computeEigenvectors = computeEigenvectors;
432 m_isInitialized = true;
433 return *this;
434}
435
436} // end namespace Eigen
437
438#endif // EIGEN_GENERALIZEDEIGENSOLVER_H
Generic expression where a coefficient-wise binary operator is applied to two expressions.
Definition CwiseBinaryOp.h:80
Computes the generalized eigenvalues and eigenvectors of a pair of general matrices.
Definition GeneralizedEigenSolver.h:63
GeneralizedEigenSolver(EigenBase< InputTypeA > &A, EigenBase< InputTypeB > &B, bool computeEigenvectors=true)
Constructor for inplace decomposition .
Definition GeneralizedEigenSolver.h:178
internal::make_complex_t< Scalar > ComplexScalar
Complex scalar type for MatrixType.
Definition GeneralizedEigenSolver.h:87
Eigen::Index Index
Definition GeneralizedEigenSolver.h:79
EigenvectorsType eigenvectors() const
Returns the computed generalized eigenvectors.
Definition GeneralizedEigenSolver.h:201
Matrix< Scalar, ColsAtCompileTime, 1, Options &~RowMajor, MaxColsAtCompileTime, 1 > VectorType
Type for vector of real scalar values eigenvalues as returned by betas().
Definition GeneralizedEigenSolver.h:94
typename MatrixType::Scalar Scalar
Scalar type for matrices of type MatrixType.
Definition GeneralizedEigenSolver.h:77
MatrixType_ MatrixType
Synonym for the template parameter MatrixType_.
Definition GeneralizedEigenSolver.h:66
const VectorType & betas() const
Definition GeneralizedEigenSolver.h:245
CwiseBinaryOp< internal::scalar_quotient_op< ComplexScalar, Scalar >, ComplexVectorType, VectorType > EigenvalueType
Expression type for the eigenvalues as returned by eigenvalues().
Definition GeneralizedEigenSolver.h:105
GeneralizedEigenSolver()
Default constructor.
Definition GeneralizedEigenSolver.h:123
const ComplexVectorType & alphas() const
Definition GeneralizedEigenSolver.h:235
Matrix< ComplexScalar, ColsAtCompileTime, 1, Options &~RowMajor, MaxColsAtCompileTime, 1 > ComplexVectorType
Type for vector of complex scalar values eigenvalues as returned by alphas().
Definition GeneralizedEigenSolver.h:101
GeneralizedEigenSolver(const EigenBase< InputTypeA > &A, const EigenBase< InputTypeB > &B, bool computeEigenvectors=true)
Constructor; computes the generalized eigendecomposition of given matrix pair.
Definition GeneralizedEigenSolver.h:154
Matrix< ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime > EigenvectorsType
Type for matrix of eigenvectors as returned by eigenvectors().
Definition GeneralizedEigenSolver.h:113
EigenvalueType eigenvalues() const
Returns an expression of the computed generalized eigenvalues.
Definition GeneralizedEigenSolver.h:225
GeneralizedEigenSolver(Index size)
Default constructor with memory preallocation.
Definition GeneralizedEigenSolver.h:132
GeneralizedEigenSolver & setMaxIterations(Index maxIters)
Definition GeneralizedEigenSolver.h:284
GeneralizedEigenSolver & compute(const EigenBase< InputTypeA > &A, const EigenBase< InputTypeB > &B, bool computeEigenvectors=true)
Computes generalized eigendecomposition of given matrix.
A matrix or vector expression mapping an existing array of data.
Definition Map.h:97
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
Performs a real QZ decomposition of a pair of square matrices.
Definition RealQZ.h:62
ComputationInfo
Definition Constants.h:455
@ Success
Definition Constants.h:457
Definition EigenBase.h:34