1*bf2c3715SXin Li // This file is part of Eigen, a lightweight C++ template library
2*bf2c3715SXin Li // for linear algebra.
3*bf2c3715SXin Li //
4*bf2c3715SXin Li // Copyright (C) 2012-2016 Gael Guennebaud <[email protected]>
5*bf2c3715SXin Li // Copyright (C) 2010,2012 Jitse Niesen <[email protected]>
6*bf2c3715SXin Li // Copyright (C) 2016 Tobias Wood <[email protected]>
7*bf2c3715SXin Li //
8*bf2c3715SXin Li // This Source Code Form is subject to the terms of the Mozilla
9*bf2c3715SXin Li // Public License v. 2.0. If a copy of the MPL was not distributed
10*bf2c3715SXin Li // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
11*bf2c3715SXin Li
12*bf2c3715SXin Li #ifndef EIGEN_GENERALIZEDEIGENSOLVER_H
13*bf2c3715SXin Li #define EIGEN_GENERALIZEDEIGENSOLVER_H
14*bf2c3715SXin Li
15*bf2c3715SXin Li #include "./RealQZ.h"
16*bf2c3715SXin Li
17*bf2c3715SXin Li namespace Eigen {
18*bf2c3715SXin Li
19*bf2c3715SXin Li /** \eigenvalues_module \ingroup Eigenvalues_Module
20*bf2c3715SXin Li *
21*bf2c3715SXin Li *
22*bf2c3715SXin Li * \class GeneralizedEigenSolver
23*bf2c3715SXin Li *
24*bf2c3715SXin Li * \brief Computes the generalized eigenvalues and eigenvectors of a pair of general matrices
25*bf2c3715SXin Li *
26*bf2c3715SXin Li * \tparam _MatrixType the type of the matrices of which we are computing the
27*bf2c3715SXin Li * eigen-decomposition; this is expected to be an instantiation of the Matrix
28*bf2c3715SXin Li * class template. Currently, only real matrices are supported.
29*bf2c3715SXin Li *
30*bf2c3715SXin Li * The generalized eigenvalues and eigenvectors of a matrix pair \f$ A \f$ and \f$ B \f$ are scalars
31*bf2c3715SXin Li * \f$ \lambda \f$ and vectors \f$ v \f$ such that \f$ Av = \lambda Bv \f$. If
32*bf2c3715SXin Li * \f$ D \f$ is a diagonal matrix with the eigenvalues on the diagonal, and
33*bf2c3715SXin Li * \f$ V \f$ is a matrix with the eigenvectors as its columns, then \f$ A V =
34*bf2c3715SXin Li * B V D \f$. The matrix \f$ V \f$ is almost always invertible, in which case we
35*bf2c3715SXin Li * have \f$ A = B V D V^{-1} \f$. This is called the generalized eigen-decomposition.
36*bf2c3715SXin Li *
37*bf2c3715SXin Li * The generalized eigenvalues and eigenvectors of a matrix pair may be complex, even when the
38*bf2c3715SXin Li * matrices are real. Moreover, the generalized eigenvalue might be infinite if the matrix B is
39*bf2c3715SXin Li * singular. To workaround this difficulty, the eigenvalues are provided as a pair of complex \f$ \alpha \f$
40*bf2c3715SXin Li * and real \f$ \beta \f$ such that: \f$ \lambda_i = \alpha_i / \beta_i \f$. If \f$ \beta_i \f$ is (nearly) zero,
41*bf2c3715SXin Li * then one can consider the well defined left eigenvalue \f$ \mu = \beta_i / \alpha_i\f$ such that:
42*bf2c3715SXin Li * \f$ \mu_i A v_i = B v_i \f$, or even \f$ \mu_i u_i^T A = u_i^T B \f$ where \f$ u_i \f$ is
43*bf2c3715SXin Li * called the left eigenvector.
44*bf2c3715SXin Li *
45*bf2c3715SXin Li * Call the function compute() to compute the generalized eigenvalues and eigenvectors of
46*bf2c3715SXin Li * a given matrix pair. Alternatively, you can use the
47*bf2c3715SXin Li * GeneralizedEigenSolver(const MatrixType&, const MatrixType&, bool) constructor which computes the
48*bf2c3715SXin Li * eigenvalues and eigenvectors at construction time. Once the eigenvalue and
49*bf2c3715SXin Li * eigenvectors are computed, they can be retrieved with the eigenvalues() and
50*bf2c3715SXin Li * eigenvectors() functions.
51*bf2c3715SXin Li *
52*bf2c3715SXin Li * Here is an usage example of this class:
53*bf2c3715SXin Li * Example: \include GeneralizedEigenSolver.cpp
54*bf2c3715SXin Li * Output: \verbinclude GeneralizedEigenSolver.out
55*bf2c3715SXin Li *
56*bf2c3715SXin Li * \sa MatrixBase::eigenvalues(), class ComplexEigenSolver, class SelfAdjointEigenSolver
57*bf2c3715SXin Li */
58*bf2c3715SXin Li template<typename _MatrixType> class GeneralizedEigenSolver
59*bf2c3715SXin Li {
60*bf2c3715SXin Li public:
61*bf2c3715SXin Li
62*bf2c3715SXin Li /** \brief Synonym for the template parameter \p _MatrixType. */
63*bf2c3715SXin Li typedef _MatrixType MatrixType;
64*bf2c3715SXin Li
65*bf2c3715SXin Li enum {
66*bf2c3715SXin Li RowsAtCompileTime = MatrixType::RowsAtCompileTime,
67*bf2c3715SXin Li ColsAtCompileTime = MatrixType::ColsAtCompileTime,
68*bf2c3715SXin Li Options = MatrixType::Options,
69*bf2c3715SXin Li MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
70*bf2c3715SXin Li MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
71*bf2c3715SXin Li };
72*bf2c3715SXin Li
73*bf2c3715SXin Li /** \brief Scalar type for matrices of type #MatrixType. */
74*bf2c3715SXin Li typedef typename MatrixType::Scalar Scalar;
75*bf2c3715SXin Li typedef typename NumTraits<Scalar>::Real RealScalar;
76*bf2c3715SXin Li typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3
77*bf2c3715SXin Li
78*bf2c3715SXin Li /** \brief Complex scalar type for #MatrixType.
79*bf2c3715SXin Li *
80*bf2c3715SXin Li * This is \c std::complex<Scalar> if #Scalar is real (e.g.,
81*bf2c3715SXin Li * \c float or \c double) and just \c Scalar if #Scalar is
82*bf2c3715SXin Li * complex.
83*bf2c3715SXin Li */
84*bf2c3715SXin Li typedef std::complex<RealScalar> ComplexScalar;
85*bf2c3715SXin Li
86*bf2c3715SXin Li /** \brief Type for vector of real scalar values eigenvalues as returned by betas().
87*bf2c3715SXin Li *
88*bf2c3715SXin Li * This is a column vector with entries of type #Scalar.
89*bf2c3715SXin Li * The length of the vector is the size of #MatrixType.
90*bf2c3715SXin Li */
91*bf2c3715SXin Li typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> VectorType;
92*bf2c3715SXin Li
93*bf2c3715SXin Li /** \brief Type for vector of complex scalar values eigenvalues as returned by alphas().
94*bf2c3715SXin Li *
95*bf2c3715SXin Li * This is a column vector with entries of type #ComplexScalar.
96*bf2c3715SXin Li * The length of the vector is the size of #MatrixType.
97*bf2c3715SXin Li */
98*bf2c3715SXin Li typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ComplexVectorType;
99*bf2c3715SXin Li
100*bf2c3715SXin Li /** \brief Expression type for the eigenvalues as returned by eigenvalues().
101*bf2c3715SXin Li */
102*bf2c3715SXin Li typedef CwiseBinaryOp<internal::scalar_quotient_op<ComplexScalar,Scalar>,ComplexVectorType,VectorType> EigenvalueType;
103*bf2c3715SXin Li
104*bf2c3715SXin Li /** \brief Type for matrix of eigenvectors as returned by eigenvectors().
105*bf2c3715SXin Li *
106*bf2c3715SXin Li * This is a square matrix with entries of type #ComplexScalar.
107*bf2c3715SXin Li * The size is the same as the size of #MatrixType.
108*bf2c3715SXin Li */
109*bf2c3715SXin Li typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime> EigenvectorsType;
110*bf2c3715SXin Li
111*bf2c3715SXin Li /** \brief Default constructor.
112*bf2c3715SXin Li *
113*bf2c3715SXin Li * The default constructor is useful in cases in which the user intends to
114*bf2c3715SXin Li * perform decompositions via EigenSolver::compute(const MatrixType&, bool).
115*bf2c3715SXin Li *
116*bf2c3715SXin Li * \sa compute() for an example.
117*bf2c3715SXin Li */
GeneralizedEigenSolver()118*bf2c3715SXin Li GeneralizedEigenSolver()
119*bf2c3715SXin Li : m_eivec(),
120*bf2c3715SXin Li m_alphas(),
121*bf2c3715SXin Li m_betas(),
122*bf2c3715SXin Li m_valuesOkay(false),
123*bf2c3715SXin Li m_vectorsOkay(false),
124*bf2c3715SXin Li m_realQZ()
125*bf2c3715SXin Li {}
126*bf2c3715SXin Li
127*bf2c3715SXin Li /** \brief Default constructor with memory preallocation
128*bf2c3715SXin Li *
129*bf2c3715SXin Li * Like the default constructor but with preallocation of the internal data
130*bf2c3715SXin Li * according to the specified problem \a size.
131*bf2c3715SXin Li * \sa GeneralizedEigenSolver()
132*bf2c3715SXin Li */
GeneralizedEigenSolver(Index size)133*bf2c3715SXin Li explicit GeneralizedEigenSolver(Index size)
134*bf2c3715SXin Li : m_eivec(size, size),
135*bf2c3715SXin Li m_alphas(size),
136*bf2c3715SXin Li m_betas(size),
137*bf2c3715SXin Li m_valuesOkay(false),
138*bf2c3715SXin Li m_vectorsOkay(false),
139*bf2c3715SXin Li m_realQZ(size),
140*bf2c3715SXin Li m_tmp(size)
141*bf2c3715SXin Li {}
142*bf2c3715SXin Li
143*bf2c3715SXin Li /** \brief Constructor; computes the generalized eigendecomposition of given matrix pair.
144*bf2c3715SXin Li *
145*bf2c3715SXin Li * \param[in] A Square matrix whose eigendecomposition is to be computed.
146*bf2c3715SXin Li * \param[in] B Square matrix whose eigendecomposition is to be computed.
147*bf2c3715SXin Li * \param[in] computeEigenvectors If true, both the eigenvectors and the
148*bf2c3715SXin Li * eigenvalues are computed; if false, only the eigenvalues are computed.
149*bf2c3715SXin Li *
150*bf2c3715SXin Li * This constructor calls compute() to compute the generalized eigenvalues
151*bf2c3715SXin Li * and eigenvectors.
152*bf2c3715SXin Li *
153*bf2c3715SXin Li * \sa compute()
154*bf2c3715SXin Li */
155*bf2c3715SXin Li GeneralizedEigenSolver(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true)
156*bf2c3715SXin Li : m_eivec(A.rows(), A.cols()),
157*bf2c3715SXin Li m_alphas(A.cols()),
158*bf2c3715SXin Li m_betas(A.cols()),
159*bf2c3715SXin Li m_valuesOkay(false),
160*bf2c3715SXin Li m_vectorsOkay(false),
161*bf2c3715SXin Li m_realQZ(A.cols()),
162*bf2c3715SXin Li m_tmp(A.cols())
163*bf2c3715SXin Li {
164*bf2c3715SXin Li compute(A, B, computeEigenvectors);
165*bf2c3715SXin Li }
166*bf2c3715SXin Li
167*bf2c3715SXin Li /* \brief Returns the computed generalized eigenvectors.
168*bf2c3715SXin Li *
169*bf2c3715SXin Li * \returns %Matrix whose columns are the (possibly complex) right eigenvectors.
170*bf2c3715SXin Li * i.e. the eigenvectors that solve (A - l*B)x = 0. The ordering matches the eigenvalues.
171*bf2c3715SXin Li *
172*bf2c3715SXin Li * \pre Either the constructor
173*bf2c3715SXin Li * GeneralizedEigenSolver(const MatrixType&,const MatrixType&, bool) or the member function
174*bf2c3715SXin Li * compute(const MatrixType&, const MatrixType& bool) has been called before, and
175*bf2c3715SXin Li * \p computeEigenvectors was set to true (the default).
176*bf2c3715SXin Li *
177*bf2c3715SXin Li * \sa eigenvalues()
178*bf2c3715SXin Li */
eigenvectors()179*bf2c3715SXin Li EigenvectorsType eigenvectors() const {
180*bf2c3715SXin Li eigen_assert(m_vectorsOkay && "Eigenvectors for GeneralizedEigenSolver were not calculated.");
181*bf2c3715SXin Li return m_eivec;
182*bf2c3715SXin Li }
183*bf2c3715SXin Li
184*bf2c3715SXin Li /** \brief Returns an expression of the computed generalized eigenvalues.
185*bf2c3715SXin Li *
186*bf2c3715SXin Li * \returns An expression of the column vector containing the eigenvalues.
187*bf2c3715SXin Li *
188*bf2c3715SXin Li * It is a shortcut for \code this->alphas().cwiseQuotient(this->betas()); \endcode
189*bf2c3715SXin Li * Not that betas might contain zeros. It is therefore not recommended to use this function,
190*bf2c3715SXin Li * but rather directly deal with the alphas and betas vectors.
191*bf2c3715SXin Li *
192*bf2c3715SXin Li * \pre Either the constructor
193*bf2c3715SXin Li * GeneralizedEigenSolver(const MatrixType&,const MatrixType&,bool) or the member function
194*bf2c3715SXin Li * compute(const MatrixType&,const MatrixType&,bool) has been called before.
195*bf2c3715SXin Li *
196*bf2c3715SXin Li * The eigenvalues are repeated according to their algebraic multiplicity,
197*bf2c3715SXin Li * so there are as many eigenvalues as rows in the matrix. The eigenvalues
198*bf2c3715SXin Li * are not sorted in any particular order.
199*bf2c3715SXin Li *
200*bf2c3715SXin Li * \sa alphas(), betas(), eigenvectors()
201*bf2c3715SXin Li */
eigenvalues()202*bf2c3715SXin Li EigenvalueType eigenvalues() const
203*bf2c3715SXin Li {
204*bf2c3715SXin Li eigen_assert(m_valuesOkay && "GeneralizedEigenSolver is not initialized.");
205*bf2c3715SXin Li return EigenvalueType(m_alphas,m_betas);
206*bf2c3715SXin Li }
207*bf2c3715SXin Li
208*bf2c3715SXin Li /** \returns A const reference to the vectors containing the alpha values
209*bf2c3715SXin Li *
210*bf2c3715SXin Li * This vector permits to reconstruct the j-th eigenvalues as alphas(i)/betas(j).
211*bf2c3715SXin Li *
212*bf2c3715SXin Li * \sa betas(), eigenvalues() */
alphas()213*bf2c3715SXin Li ComplexVectorType alphas() const
214*bf2c3715SXin Li {
215*bf2c3715SXin Li eigen_assert(m_valuesOkay && "GeneralizedEigenSolver is not initialized.");
216*bf2c3715SXin Li return m_alphas;
217*bf2c3715SXin Li }
218*bf2c3715SXin Li
219*bf2c3715SXin Li /** \returns A const reference to the vectors containing the beta values
220*bf2c3715SXin Li *
221*bf2c3715SXin Li * This vector permits to reconstruct the j-th eigenvalues as alphas(i)/betas(j).
222*bf2c3715SXin Li *
223*bf2c3715SXin Li * \sa alphas(), eigenvalues() */
betas()224*bf2c3715SXin Li VectorType betas() const
225*bf2c3715SXin Li {
226*bf2c3715SXin Li eigen_assert(m_valuesOkay && "GeneralizedEigenSolver is not initialized.");
227*bf2c3715SXin Li return m_betas;
228*bf2c3715SXin Li }
229*bf2c3715SXin Li
230*bf2c3715SXin Li /** \brief Computes generalized eigendecomposition of given matrix.
231*bf2c3715SXin Li *
232*bf2c3715SXin Li * \param[in] A Square matrix whose eigendecomposition is to be computed.
233*bf2c3715SXin Li * \param[in] B Square matrix whose eigendecomposition is to be computed.
234*bf2c3715SXin Li * \param[in] computeEigenvectors If true, both the eigenvectors and the
235*bf2c3715SXin Li * eigenvalues are computed; if false, only the eigenvalues are
236*bf2c3715SXin Li * computed.
237*bf2c3715SXin Li * \returns Reference to \c *this
238*bf2c3715SXin Li *
239*bf2c3715SXin Li * This function computes the eigenvalues of the real matrix \p matrix.
240*bf2c3715SXin Li * The eigenvalues() function can be used to retrieve them. If
241*bf2c3715SXin Li * \p computeEigenvectors is true, then the eigenvectors are also computed
242*bf2c3715SXin Li * and can be retrieved by calling eigenvectors().
243*bf2c3715SXin Li *
244*bf2c3715SXin Li * The matrix is first reduced to real generalized Schur form using the RealQZ
245*bf2c3715SXin Li * class. The generalized Schur decomposition is then used to compute the eigenvalues
246*bf2c3715SXin Li * and eigenvectors.
247*bf2c3715SXin Li *
248*bf2c3715SXin Li * The cost of the computation is dominated by the cost of the
249*bf2c3715SXin Li * generalized Schur decomposition.
250*bf2c3715SXin Li *
251*bf2c3715SXin Li * This method reuses of the allocated data in the GeneralizedEigenSolver object.
252*bf2c3715SXin Li */
253*bf2c3715SXin Li GeneralizedEigenSolver& compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true);
254*bf2c3715SXin Li
info()255*bf2c3715SXin Li ComputationInfo info() const
256*bf2c3715SXin Li {
257*bf2c3715SXin Li eigen_assert(m_valuesOkay && "EigenSolver is not initialized.");
258*bf2c3715SXin Li return m_realQZ.info();
259*bf2c3715SXin Li }
260*bf2c3715SXin Li
261*bf2c3715SXin Li /** Sets the maximal number of iterations allowed.
262*bf2c3715SXin Li */
setMaxIterations(Index maxIters)263*bf2c3715SXin Li GeneralizedEigenSolver& setMaxIterations(Index maxIters)
264*bf2c3715SXin Li {
265*bf2c3715SXin Li m_realQZ.setMaxIterations(maxIters);
266*bf2c3715SXin Li return *this;
267*bf2c3715SXin Li }
268*bf2c3715SXin Li
269*bf2c3715SXin Li protected:
270*bf2c3715SXin Li
check_template_parameters()271*bf2c3715SXin Li static void check_template_parameters()
272*bf2c3715SXin Li {
273*bf2c3715SXin Li EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
274*bf2c3715SXin Li EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL);
275*bf2c3715SXin Li }
276*bf2c3715SXin Li
277*bf2c3715SXin Li EigenvectorsType m_eivec;
278*bf2c3715SXin Li ComplexVectorType m_alphas;
279*bf2c3715SXin Li VectorType m_betas;
280*bf2c3715SXin Li bool m_valuesOkay, m_vectorsOkay;
281*bf2c3715SXin Li RealQZ<MatrixType> m_realQZ;
282*bf2c3715SXin Li ComplexVectorType m_tmp;
283*bf2c3715SXin Li };
284*bf2c3715SXin Li
285*bf2c3715SXin Li template<typename MatrixType>
286*bf2c3715SXin Li GeneralizedEigenSolver<MatrixType>&
compute(const MatrixType & A,const MatrixType & B,bool computeEigenvectors)287*bf2c3715SXin Li GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors)
288*bf2c3715SXin Li {
289*bf2c3715SXin Li check_template_parameters();
290*bf2c3715SXin Li
291*bf2c3715SXin Li using std::sqrt;
292*bf2c3715SXin Li using std::abs;
293*bf2c3715SXin Li eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows());
294*bf2c3715SXin Li Index size = A.cols();
295*bf2c3715SXin Li m_valuesOkay = false;
296*bf2c3715SXin Li m_vectorsOkay = false;
297*bf2c3715SXin Li // Reduce to generalized real Schur form:
298*bf2c3715SXin Li // A = Q S Z and B = Q T Z
299*bf2c3715SXin Li m_realQZ.compute(A, B, computeEigenvectors);
300*bf2c3715SXin Li if (m_realQZ.info() == Success)
301*bf2c3715SXin Li {
302*bf2c3715SXin Li // Resize storage
303*bf2c3715SXin Li m_alphas.resize(size);
304*bf2c3715SXin Li m_betas.resize(size);
305*bf2c3715SXin Li if (computeEigenvectors)
306*bf2c3715SXin Li {
307*bf2c3715SXin Li m_eivec.resize(size,size);
308*bf2c3715SXin Li m_tmp.resize(size);
309*bf2c3715SXin Li }
310*bf2c3715SXin Li
311*bf2c3715SXin Li // Aliases:
312*bf2c3715SXin Li Map<VectorType> v(reinterpret_cast<Scalar*>(m_tmp.data()), size);
313*bf2c3715SXin Li ComplexVectorType &cv = m_tmp;
314*bf2c3715SXin Li const MatrixType &mS = m_realQZ.matrixS();
315*bf2c3715SXin Li const MatrixType &mT = m_realQZ.matrixT();
316*bf2c3715SXin Li
317*bf2c3715SXin Li Index i = 0;
318*bf2c3715SXin Li while (i < size)
319*bf2c3715SXin Li {
320*bf2c3715SXin Li if (i == size - 1 || mS.coeff(i+1, i) == Scalar(0))
321*bf2c3715SXin Li {
322*bf2c3715SXin Li // Real eigenvalue
323*bf2c3715SXin Li m_alphas.coeffRef(i) = mS.diagonal().coeff(i);
324*bf2c3715SXin Li m_betas.coeffRef(i) = mT.diagonal().coeff(i);
325*bf2c3715SXin Li if (computeEigenvectors)
326*bf2c3715SXin Li {
327*bf2c3715SXin Li v.setConstant(Scalar(0.0));
328*bf2c3715SXin Li v.coeffRef(i) = Scalar(1.0);
329*bf2c3715SXin Li // For singular eigenvalues do nothing more
330*bf2c3715SXin Li if(abs(m_betas.coeffRef(i)) >= (std::numeric_limits<RealScalar>::min)())
331*bf2c3715SXin Li {
332*bf2c3715SXin Li // Non-singular eigenvalue
333*bf2c3715SXin Li const Scalar alpha = real(m_alphas.coeffRef(i));
334*bf2c3715SXin Li const Scalar beta = m_betas.coeffRef(i);
335*bf2c3715SXin Li for (Index j = i-1; j >= 0; j--)
336*bf2c3715SXin Li {
337*bf2c3715SXin Li const Index st = j+1;
338*bf2c3715SXin Li const Index sz = i-j;
339*bf2c3715SXin Li if (j > 0 && mS.coeff(j, j-1) != Scalar(0))
340*bf2c3715SXin Li {
341*bf2c3715SXin Li // 2x2 block
342*bf2c3715SXin Li Matrix<Scalar, 2, 1> rhs = (alpha*mT.template block<2,Dynamic>(j-1,st,2,sz) - beta*mS.template block<2,Dynamic>(j-1,st,2,sz)) .lazyProduct( v.segment(st,sz) );
343*bf2c3715SXin Li Matrix<Scalar, 2, 2> lhs = beta * mS.template block<2,2>(j-1,j-1) - alpha * mT.template block<2,2>(j-1,j-1);
344*bf2c3715SXin Li v.template segment<2>(j-1) = lhs.partialPivLu().solve(rhs);
345*bf2c3715SXin Li j--;
346*bf2c3715SXin Li }
347*bf2c3715SXin Li else
348*bf2c3715SXin Li {
349*bf2c3715SXin Li v.coeffRef(j) = -v.segment(st,sz).transpose().cwiseProduct(beta*mS.block(j,st,1,sz) - alpha*mT.block(j,st,1,sz)).sum() / (beta*mS.coeffRef(j,j) - alpha*mT.coeffRef(j,j));
350*bf2c3715SXin Li }
351*bf2c3715SXin Li }
352*bf2c3715SXin Li }
353*bf2c3715SXin Li m_eivec.col(i).real().noalias() = m_realQZ.matrixZ().transpose() * v;
354*bf2c3715SXin Li m_eivec.col(i).real().normalize();
355*bf2c3715SXin Li m_eivec.col(i).imag().setConstant(0);
356*bf2c3715SXin Li }
357*bf2c3715SXin Li ++i;
358*bf2c3715SXin Li }
359*bf2c3715SXin Li else
360*bf2c3715SXin Li {
361*bf2c3715SXin Li // We need to extract the generalized eigenvalues of the pair of a general 2x2 block S and a positive diagonal 2x2 block T
362*bf2c3715SXin Li // Then taking beta=T_00*T_11, we can avoid any division, and alpha is the eigenvalues of A = (U^-1 * S * U) * diag(T_11,T_00):
363*bf2c3715SXin Li
364*bf2c3715SXin Li // T = [a 0]
365*bf2c3715SXin Li // [0 b]
366*bf2c3715SXin Li RealScalar a = mT.diagonal().coeff(i),
367*bf2c3715SXin Li b = mT.diagonal().coeff(i+1);
368*bf2c3715SXin Li const RealScalar beta = m_betas.coeffRef(i) = m_betas.coeffRef(i+1) = a*b;
369*bf2c3715SXin Li
370*bf2c3715SXin Li // ^^ NOTE: using diagonal()(i) instead of coeff(i,i) workarounds a MSVC bug.
371*bf2c3715SXin Li Matrix<RealScalar,2,2> S2 = mS.template block<2,2>(i,i) * Matrix<Scalar,2,1>(b,a).asDiagonal();
372*bf2c3715SXin Li
373*bf2c3715SXin Li Scalar p = Scalar(0.5) * (S2.coeff(0,0) - S2.coeff(1,1));
374*bf2c3715SXin Li Scalar z = sqrt(abs(p * p + S2.coeff(1,0) * S2.coeff(0,1)));
375*bf2c3715SXin Li const ComplexScalar alpha = ComplexScalar(S2.coeff(1,1) + p, (beta > 0) ? z : -z);
376*bf2c3715SXin Li m_alphas.coeffRef(i) = conj(alpha);
377*bf2c3715SXin Li m_alphas.coeffRef(i+1) = alpha;
378*bf2c3715SXin Li
379*bf2c3715SXin Li if (computeEigenvectors) {
380*bf2c3715SXin Li // Compute eigenvector in position (i+1) and then position (i) is just the conjugate
381*bf2c3715SXin Li cv.setZero();
382*bf2c3715SXin Li cv.coeffRef(i+1) = Scalar(1.0);
383*bf2c3715SXin Li // here, the "static_cast" workaound expression template issues.
384*bf2c3715SXin Li cv.coeffRef(i) = -(static_cast<Scalar>(beta*mS.coeffRef(i,i+1)) - alpha*mT.coeffRef(i,i+1))
385*bf2c3715SXin Li / (static_cast<Scalar>(beta*mS.coeffRef(i,i)) - alpha*mT.coeffRef(i,i));
386*bf2c3715SXin Li for (Index j = i-1; j >= 0; j--)
387*bf2c3715SXin Li {
388*bf2c3715SXin Li const Index st = j+1;
389*bf2c3715SXin Li const Index sz = i+1-j;
390*bf2c3715SXin Li if (j > 0 && mS.coeff(j, j-1) != Scalar(0))
391*bf2c3715SXin Li {
392*bf2c3715SXin Li // 2x2 block
393*bf2c3715SXin Li Matrix<ComplexScalar, 2, 1> rhs = (alpha*mT.template block<2,Dynamic>(j-1,st,2,sz) - beta*mS.template block<2,Dynamic>(j-1,st,2,sz)) .lazyProduct( cv.segment(st,sz) );
394*bf2c3715SXin Li Matrix<ComplexScalar, 2, 2> lhs = beta * mS.template block<2,2>(j-1,j-1) - alpha * mT.template block<2,2>(j-1,j-1);
395*bf2c3715SXin Li cv.template segment<2>(j-1) = lhs.partialPivLu().solve(rhs);
396*bf2c3715SXin Li j--;
397*bf2c3715SXin Li } else {
398*bf2c3715SXin Li cv.coeffRef(j) = cv.segment(st,sz).transpose().cwiseProduct(beta*mS.block(j,st,1,sz) - alpha*mT.block(j,st,1,sz)).sum()
399*bf2c3715SXin Li / (alpha*mT.coeffRef(j,j) - static_cast<Scalar>(beta*mS.coeffRef(j,j)));
400*bf2c3715SXin Li }
401*bf2c3715SXin Li }
402*bf2c3715SXin Li m_eivec.col(i+1).noalias() = (m_realQZ.matrixZ().transpose() * cv);
403*bf2c3715SXin Li m_eivec.col(i+1).normalize();
404*bf2c3715SXin Li m_eivec.col(i) = m_eivec.col(i+1).conjugate();
405*bf2c3715SXin Li }
406*bf2c3715SXin Li i += 2;
407*bf2c3715SXin Li }
408*bf2c3715SXin Li }
409*bf2c3715SXin Li
410*bf2c3715SXin Li m_valuesOkay = true;
411*bf2c3715SXin Li m_vectorsOkay = computeEigenvectors;
412*bf2c3715SXin Li }
413*bf2c3715SXin Li return *this;
414*bf2c3715SXin Li }
415*bf2c3715SXin Li
416*bf2c3715SXin Li } // end namespace Eigen
417*bf2c3715SXin Li
418*bf2c3715SXin Li #endif // EIGEN_GENERALIZEDEIGENSOLVER_H
419