Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Eigen::RealQZ< _MatrixType > Class Template Reference

Performs a real QZ decomposition of a pair of square matrices. More...

#include <src/eigen/Eigen/src/Eigenvalues/RealQZ.h>

+ Inheritance diagram for Eigen::RealQZ< _MatrixType >:
+ Collaboration diagram for Eigen::RealQZ< _MatrixType >:

Public Types

enum  {
  RowsAtCompileTime = MatrixType::RowsAtCompileTime , ColsAtCompileTime = MatrixType::ColsAtCompileTime , Options = MatrixType::Options , MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime ,
  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
}
 
typedef _MatrixType MatrixType
 
typedef MatrixType::Scalar Scalar
 
typedef std::complex< typename NumTraits< Scalar >::Real > ComplexScalar
 
typedef Eigen::Index Index
 
typedef Matrix< ComplexScalar, ColsAtCompileTime, 1, Options &~RowMajor, MaxColsAtCompileTime, 1 > EigenvalueType
 
typedef Matrix< Scalar, ColsAtCompileTime, 1, Options &~RowMajor, MaxColsAtCompileTime, 1 > ColumnVectorType
 

Public Member Functions

 RealQZ (Index size=RowsAtCompileTime==Dynamic ? 1 :RowsAtCompileTime)
 Default constructor.
 
 RealQZ (const MatrixType &A, const MatrixType &B, bool computeQZ=true)
 Constructor; computes real QZ decomposition of given matrices.
 
const MatrixTypematrixQ () const
 Returns matrix Q in the QZ decomposition.
 
const MatrixTypematrixZ () const
 Returns matrix Z in the QZ decomposition.
 
const MatrixTypematrixS () const
 Returns matrix S in the QZ decomposition.
 
const MatrixTypematrixT () const
 Returns matrix S in the QZ decomposition.
 
RealQZcompute (const MatrixType &A, const MatrixType &B, bool computeQZ=true)
 Computes QZ decomposition of given matrix.
 
ComputationInfo info () const
 Reports whether previous computation was successful.
 
Index iterations () const
 Returns number of performed QR-like iterations.
 
RealQZsetMaxIterations (Index maxIters)
 

Private Types

typedef Matrix< Scalar, 3, 1 > Vector3s
 
typedef Matrix< Scalar, 2, 1 > Vector2s
 
typedef Matrix< Scalar, 2, 2 > Matrix2s
 
typedef JacobiRotation< ScalarJRs
 

Private Member Functions

void hessenbergTriangular ()
 
void computeNorms ()
 
Index findSmallSubdiagEntry (Index iu)
 
Index findSmallDiagEntry (Index f, Index l)
 
void splitOffTwoRows (Index i)
 
void pushDownZero (Index z, Index f, Index l)
 
void step (Index f, Index l, Index iter)
 

Private Attributes

MatrixType m_S
 
MatrixType m_T
 
MatrixType m_Q
 
MatrixType m_Z
 
Matrix< Scalar, Dynamic, 1 > m_workspace
 
ComputationInfo m_info
 
Index m_maxIters
 
bool m_isInitialized
 
bool m_computeQZ
 
Scalar m_normOfT
 
Scalar m_normOfS
 
Index m_global_iter
 

Detailed Description

template<typename _MatrixType>
class Eigen::RealQZ< _MatrixType >

Performs a real QZ decomposition of a pair of square matrices.

\eigenvalues_module

Template Parameters
_MatrixTypethe type of the matrix of which we are computing the real QZ decomposition; this is expected to be an instantiation of the Matrix class template.

Given a real square matrices A and B, this class computes the real QZ decomposition: $ A = Q S Z $, $ B = Q T Z $ where Q and Z are real orthogonal matrixes, T is upper-triangular matrix, and S is upper quasi-triangular matrix. An orthogonal matrix is a matrix whose inverse is equal to its transpose, $ U^{-1} = U^T $. A quasi-triangular matrix is a block-triangular matrix whose diagonal consists of 1-by-1 blocks and 2-by-2 blocks where further reduction is impossible due to complex eigenvalues.

The eigenvalues of the pencil $ A - z B $ can be obtained from 1x1 and 2x2 blocks on the diagonals of S and T.

Call the function compute() to compute the real QZ decomposition of a given pair of matrices. Alternatively, you can use the RealQZ(const MatrixType& B, const MatrixType& B, bool computeQZ) constructor which computes the real QZ decomposition at construction time. Once the decomposition is computed, you can use the matrixS(), matrixT(), matrixQ() and matrixZ() functions to retrieve the matrices S, T, Q and Z in the decomposition. If computeQZ==false, some time is saved by not computing matrices Q and Z.

Example:

Output:

Note
The implementation is based on the algorithm in "Matrix Computations" by Gene H. Golub and Charles F. Van Loan, and a paper "An algorithm for generalized eigenvalue problems" by C.B.Moler and G.W.Stewart.
See also
class RealSchur, class ComplexSchur, class EigenSolver, class ComplexEigenSolver

Member Typedef Documentation

◆ ColumnVectorType

template<typename _MatrixType >
typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> Eigen::RealQZ< _MatrixType >::ColumnVectorType

◆ ComplexScalar

template<typename _MatrixType >
typedef std::complex<typename NumTraits<Scalar>::Real> Eigen::RealQZ< _MatrixType >::ComplexScalar

◆ EigenvalueType

template<typename _MatrixType >
typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> Eigen::RealQZ< _MatrixType >::EigenvalueType

◆ Index

template<typename _MatrixType >
typedef Eigen::Index Eigen::RealQZ< _MatrixType >::Index

◆ JRs

template<typename _MatrixType >
typedef JacobiRotation<Scalar> Eigen::RealQZ< _MatrixType >::JRs
private

◆ Matrix2s

template<typename _MatrixType >
typedef Matrix<Scalar,2,2> Eigen::RealQZ< _MatrixType >::Matrix2s
private

◆ MatrixType

template<typename _MatrixType >
typedef _MatrixType Eigen::RealQZ< _MatrixType >::MatrixType

◆ Scalar

template<typename _MatrixType >
typedef MatrixType::Scalar Eigen::RealQZ< _MatrixType >::Scalar

◆ Vector2s

template<typename _MatrixType >
typedef Matrix<Scalar,2,1> Eigen::RealQZ< _MatrixType >::Vector2s
private

◆ Vector3s

template<typename _MatrixType >
typedef Matrix<Scalar,3,1> Eigen::RealQZ< _MatrixType >::Vector3s
private

Member Enumeration Documentation

◆ anonymous enum

template<typename _MatrixType >
anonymous enum
Enumerator
RowsAtCompileTime 
ColsAtCompileTime 
Options 
MaxRowsAtCompileTime 
MaxColsAtCompileTime 
61 {
62 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
63 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
64 Options = MatrixType::Options,
65 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
66 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
67 };
@ Options
Definition RealQZ.h:64
@ MaxColsAtCompileTime
Definition RealQZ.h:66
@ ColsAtCompileTime
Definition RealQZ.h:63
@ MaxRowsAtCompileTime
Definition RealQZ.h:65
@ RowsAtCompileTime
Definition RealQZ.h:62

Constructor & Destructor Documentation

◆ RealQZ() [1/2]

template<typename _MatrixType >
Eigen::RealQZ< _MatrixType >::RealQZ ( Index  size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime)
inlineexplicit

Default constructor.

Parameters
[in]sizePositive integer, size of the matrix whose QZ decomposition will be computed.

The default constructor is useful in cases in which the user intends to perform decompositions via compute(). The size parameter is only used as a hint. It is not an error to give a wrong size, but it may impair performance.

See also
compute() for an example.
87 m_S(size, size),
88 m_T(size, size),
89 m_Q(size, size),
90 m_Z(size, size),
92 m_maxIters(400),
93 m_isInitialized(false)
94 { }
MatrixType m_Z
Definition RealQZ.h:191
Index m_maxIters
Definition RealQZ.h:194
bool m_isInitialized
Definition RealQZ.h:195
MatrixType m_T
Definition RealQZ.h:191
MatrixType m_S
Definition RealQZ.h:191
MatrixType m_Q
Definition RealQZ.h:191
Matrix< Scalar, Dynamic, 1 > m_workspace
Definition RealQZ.h:192
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183

◆ RealQZ() [2/2]

template<typename _MatrixType >
Eigen::RealQZ< _MatrixType >::RealQZ ( const MatrixType A,
const MatrixType B,
bool  computeQZ = true 
)
inline

Constructor; computes real QZ decomposition of given matrices.

Parameters
[in]AMatrix A.
[in]BMatrix B.
[in]computeQZIf false, A and Z are not computed.

This constructor calls compute() to compute the QZ decomposition.

104 :
105 m_S(A.rows(),A.cols()),
106 m_T(A.rows(),A.cols()),
107 m_Q(A.rows(),A.cols()),
108 m_Z(A.rows(),A.cols()),
109 m_workspace(A.rows()*2),
110 m_maxIters(400),
111 m_isInitialized(false) {
112 compute(A, B, computeQZ);
113 }
RealQZ & compute(const MatrixType &A, const MatrixType &B, bool computeQZ=true)
Computes QZ decomposition of given matrix.
Definition RealQZ.h:556

References Eigen::RealQZ< _MatrixType >::compute().

+ Here is the call graph for this function:

Member Function Documentation

◆ compute()

template<typename MatrixType >
RealQZ< MatrixType > & Eigen::RealQZ< MatrixType >::compute ( const MatrixType A,
const MatrixType B,
bool  computeQZ = true 
)

Computes QZ decomposition of given matrix.

Parameters
[in]AMatrix A.
[in]BMatrix B.
[in]computeQZIf false, A and Z are not computed.
Returns
Reference to *this
557 {
558
559 const Index dim = A_in.cols();
560
561 eigen_assert (A_in.rows()==dim && A_in.cols()==dim
562 && B_in.rows()==dim && B_in.cols()==dim
563 && "Need square matrices of the same dimension");
564
565 m_isInitialized = true;
566 m_computeQZ = computeQZ;
567 m_S = A_in; m_T = B_in;
568 m_workspace.resize(dim*2);
569 m_global_iter = 0;
570
571 // entrance point: hessenberg triangular decomposition
573 // compute L1 vector norms of T, S into m_normOfS, m_normOfT
574 computeNorms();
575
576 Index l = dim-1,
577 f,
578 local_iter = 0;
579
580 while (l>0 && local_iter<m_maxIters)
581 {
583 // now rows and columns f..l (including) decouple from the rest of the problem
584 if (f>0) m_S.coeffRef(f,f-1) = Scalar(0.0);
585 if (f == l) // One root found
586 {
587 l--;
588 local_iter = 0;
589 }
590 else if (f == l-1) // Two roots found
591 {
593 l -= 2;
594 local_iter = 0;
595 }
596 else // No convergence yet
597 {
598 // if there's zero on diagonal of T, we can isolate an eigenvalue with Givens rotations
599 Index z = findSmallDiagEntry(f,l);
600 if (z>=f)
601 {
602 // zero found
603 pushDownZero(z,f,l);
604 }
605 else
606 {
607 // We are sure now that S.block(f,f, l-f+1,l-f+1) is underuced upper-Hessenberg
608 // and T.block(f,f, l-f+1,l-f+1) is invertible uper-triangular, which allows to
609 // apply a QR-like iteration to rows and columns f..l.
610 step(f,l, local_iter);
611 local_iter++;
613 }
614 }
615 }
616 // check if we converged before reaching iterations limit
617 m_info = (local_iter<m_maxIters) ? Success : NoConvergence;
618
619 // For each non triangular 2x2 diagonal block of S,
620 // reduce the respective 2x2 diagonal block of T to positive diagonal form using 2x2 SVD.
621 // This step is not mandatory for QZ, but it does help further extraction of eigenvalues/eigenvectors,
622 // and is in par with Lapack/Matlab QZ.
623 if(m_info==Success)
624 {
625 for(Index i=0; i<dim-1; ++i)
626 {
627 if(m_S.coeff(i+1, i) != Scalar(0))
628 {
629 JacobiRotation<Scalar> j_left, j_right;
630 internal::real_2x2_jacobi_svd(m_T, i, i+1, &j_left, &j_right);
631
632 // Apply resulting Jacobi rotations
633 m_S.applyOnTheLeft(i,i+1,j_left);
634 m_S.applyOnTheRight(i,i+1,j_right);
635 m_T.applyOnTheLeft(i,i+1,j_left);
636 m_T.applyOnTheRight(i,i+1,j_right);
637 m_T(i+1,i) = m_T(i,i+1) = Scalar(0);
638
639 if(m_computeQZ) {
640 m_Q.applyOnTheRight(i,i+1,j_left.transpose());
641 m_Z.applyOnTheLeft(i,i+1,j_right.transpose());
642 }
643
644 i++;
645 }
646 }
647 }
648
649 return *this;
650 } // end compute
#define eigen_assert(x)
Definition Macros.h:579
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index rows, Index cols)
Definition PlainObjectBase.h:279
MatrixType::Scalar Scalar
Definition RealQZ.h:68
void computeNorms()
Definition RealQZ.h:264
Index findSmallSubdiagEntry(Index iu)
Definition RealQZ.h:279
Eigen::Index Index
Definition RealQZ.h:70
void splitOffTwoRows(Index i)
Definition RealQZ.h:311
ComputationInfo m_info
Definition RealQZ.h:193
void step(Index f, Index l, Index iter)
Definition RealQZ.h:400
void hessenbergTriangular()
Definition RealQZ.h:217
bool m_computeQZ
Definition RealQZ.h:196
Index m_global_iter
Definition RealQZ.h:198
Index findSmallDiagEntry(Index f, Index l)
Definition RealQZ.h:297
void pushDownZero(Index z, Index f, Index l)
Definition RealQZ.h:361
@ Success
Definition Constants.h:432
@ NoConvergence
Definition Constants.h:436
void real_2x2_jacobi_svd(const MatrixType &matrix, Index p, Index q, JacobiRotation< RealScalar > *j_left, JacobiRotation< RealScalar > *j_right)
Definition RealSvd2x2.h:19

References eigen_assert, Eigen::NoConvergence, Eigen::internal::real_2x2_jacobi_svd(), Eigen::Success, and Eigen::JacobiRotation< Scalar >::transpose().

Referenced by Eigen::RealQZ< _MatrixType >::RealQZ().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ computeNorms()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::computeNorms
inlineprivate
265 {
266 const Index size = m_S.cols();
267 m_normOfS = Scalar(0.0);
268 m_normOfT = Scalar(0.0);
269 for (Index j = 0; j < size; ++j)
270 {
271 m_normOfS += m_S.col(j).segment(0, (std::min)(size,j+2)).cwiseAbs().sum();
272 m_normOfT += m_T.row(j).segment(j, size - j).cwiseAbs().sum();
273 }
274 }
Scalar m_normOfT
Definition RealQZ.h:197
Scalar m_normOfS
Definition RealQZ.h:197

◆ findSmallDiagEntry()

template<typename MatrixType >
Index Eigen::RealQZ< MatrixType >::findSmallDiagEntry ( Index  f,
Index  l 
)
inlineprivate
298 {
299 using std::abs;
300 Index res = l;
301 while (res >= f) {
302 if (abs(m_T.coeff(res,res)) <= NumTraits<Scalar>::epsilon() * m_normOfT)
303 break;
304 res--;
305 }
306 return res;
307 }
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half abs(const half &a)
Definition Half.h:445

◆ findSmallSubdiagEntry()

template<typename MatrixType >
Index Eigen::RealQZ< MatrixType >::findSmallSubdiagEntry ( Index  iu)
inlineprivate
280 {
281 using std::abs;
282 Index res = iu;
283 while (res > 0)
284 {
285 Scalar s = abs(m_S.coeff(res-1,res-1)) + abs(m_S.coeff(res,res));
286 if (s == Scalar(0.0))
287 s = m_normOfS;
288 if (abs(m_S.coeff(res,res-1)) < NumTraits<Scalar>::epsilon() * s)
289 break;
290 res--;
291 }
292 return res;
293 }

◆ hessenbergTriangular()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::hessenbergTriangular
private
218 {
219
220 const Index dim = m_S.cols();
221
222 // perform QR decomposition of T, overwrite T with R, save Q
223 HouseholderQR<MatrixType> qrT(m_T);
224 m_T = qrT.matrixQR();
225 m_T.template triangularView<StrictlyLower>().setZero();
226 m_Q = qrT.householderQ();
227 // overwrite S with Q* S
228 m_S.applyOnTheLeft(m_Q.adjoint());
229 // init Z as Identity
230 if (m_computeQZ)
231 m_Z = MatrixType::Identity(dim,dim);
232 // reduce S to upper Hessenberg with Givens rotations
233 for (Index j=0; j<=dim-3; j++) {
234 for (Index i=dim-1; i>=j+2; i--) {
235 JRs G;
236 // kill S(i,j)
237 if(m_S.coeff(i,j) != 0)
238 {
239 G.makeGivens(m_S.coeff(i-1,j), m_S.coeff(i,j), &m_S.coeffRef(i-1, j));
240 m_S.coeffRef(i,j) = Scalar(0.0);
241 m_S.rightCols(dim-j-1).applyOnTheLeft(i-1,i,G.adjoint());
242 m_T.rightCols(dim-i+1).applyOnTheLeft(i-1,i,G.adjoint());
243 // update Q
244 if (m_computeQZ)
245 m_Q.applyOnTheRight(i-1,i,G);
246 }
247 // kill T(i,i-1)
248 if(m_T.coeff(i,i-1)!=Scalar(0))
249 {
250 G.makeGivens(m_T.coeff(i,i), m_T.coeff(i,i-1), &m_T.coeffRef(i,i));
251 m_T.coeffRef(i,i-1) = Scalar(0.0);
252 m_S.applyOnTheRight(i,i-1,G);
253 m_T.topRows(i).applyOnTheRight(i,i-1,G);
254 // update Z
255 if (m_computeQZ)
256 m_Z.applyOnTheLeft(i,i-1,G.adjoint());
257 }
258 }
259 }
260 }
JacobiRotation< Scalar > JRs
Definition RealQZ.h:203

References Eigen::JacobiRotation< Scalar >::adjoint(), Eigen::HouseholderQR< _MatrixType >::householderQ(), Eigen::JacobiRotation< Scalar >::makeGivens(), and Eigen::HouseholderQR< _MatrixType >::matrixQR().

+ Here is the call graph for this function:

◆ info()

template<typename _MatrixType >
ComputationInfo Eigen::RealQZ< _MatrixType >::info ( ) const
inline

Reports whether previous computation was successful.

Returns
Success if computation was succesful, NoConvergence otherwise.
167 {
168 eigen_assert(m_isInitialized && "RealQZ is not initialized.");
169 return m_info;
170 }

References eigen_assert, Eigen::RealQZ< _MatrixType >::m_info, and Eigen::RealQZ< _MatrixType >::m_isInitialized.

Referenced by Eigen::GeneralizedEigenSolver< _MatrixType >::info().

+ Here is the caller graph for this function:

◆ iterations()

template<typename _MatrixType >
Index Eigen::RealQZ< _MatrixType >::iterations ( ) const
inline

Returns number of performed QR-like iterations.

175 {
176 eigen_assert(m_isInitialized && "RealQZ is not initialized.");
177 return m_global_iter;
178 }

References eigen_assert, Eigen::RealQZ< _MatrixType >::m_global_iter, and Eigen::RealQZ< _MatrixType >::m_isInitialized.

◆ matrixQ()

template<typename _MatrixType >
const MatrixType & Eigen::RealQZ< _MatrixType >::matrixQ ( ) const
inline

Returns matrix Q in the QZ decomposition.

Returns
A const reference to the matrix Q.
119 {
120 eigen_assert(m_isInitialized && "RealQZ is not initialized.");
121 eigen_assert(m_computeQZ && "The matrices Q and Z have not been computed during the QZ decomposition.");
122 return m_Q;
123 }

References eigen_assert, Eigen::RealQZ< _MatrixType >::m_computeQZ, Eigen::RealQZ< _MatrixType >::m_isInitialized, and Eigen::RealQZ< _MatrixType >::m_Q.

◆ matrixS()

template<typename _MatrixType >
const MatrixType & Eigen::RealQZ< _MatrixType >::matrixS ( ) const
inline

Returns matrix S in the QZ decomposition.

Returns
A const reference to the matrix S.
139 {
140 eigen_assert(m_isInitialized && "RealQZ is not initialized.");
141 return m_S;
142 }

References eigen_assert, Eigen::RealQZ< _MatrixType >::m_isInitialized, and Eigen::RealQZ< _MatrixType >::m_S.

◆ matrixT()

template<typename _MatrixType >
const MatrixType & Eigen::RealQZ< _MatrixType >::matrixT ( ) const
inline

Returns matrix S in the QZ decomposition.

Returns
A const reference to the matrix S.
148 {
149 eigen_assert(m_isInitialized && "RealQZ is not initialized.");
150 return m_T;
151 }

References eigen_assert, Eigen::RealQZ< _MatrixType >::m_isInitialized, and Eigen::RealQZ< _MatrixType >::m_T.

◆ matrixZ()

template<typename _MatrixType >
const MatrixType & Eigen::RealQZ< _MatrixType >::matrixZ ( ) const
inline

Returns matrix Z in the QZ decomposition.

Returns
A const reference to the matrix Z.
129 {
130 eigen_assert(m_isInitialized && "RealQZ is not initialized.");
131 eigen_assert(m_computeQZ && "The matrices Q and Z have not been computed during the QZ decomposition.");
132 return m_Z;
133 }

References eigen_assert, Eigen::RealQZ< _MatrixType >::m_computeQZ, Eigen::RealQZ< _MatrixType >::m_isInitialized, and Eigen::RealQZ< _MatrixType >::m_Z.

◆ pushDownZero()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::pushDownZero ( Index  z,
Index  f,
Index  l 
)
inlineprivate
362 {
363 JRs G;
364 const Index dim = m_S.cols();
365 for (Index zz=z; zz<l; zz++)
366 {
367 // push 0 down
368 Index firstColS = zz>f ? (zz-1) : zz;
369 G.makeGivens(m_T.coeff(zz, zz+1), m_T.coeff(zz+1, zz+1));
370 m_S.rightCols(dim-firstColS).applyOnTheLeft(zz,zz+1,G.adjoint());
371 m_T.rightCols(dim-zz).applyOnTheLeft(zz,zz+1,G.adjoint());
372 m_T.coeffRef(zz+1,zz+1) = Scalar(0.0);
373 // update Q
374 if (m_computeQZ)
375 m_Q.applyOnTheRight(zz,zz+1,G);
376 // kill S(zz+1, zz-1)
377 if (zz>f)
378 {
379 G.makeGivens(m_S.coeff(zz+1, zz), m_S.coeff(zz+1,zz-1));
380 m_S.topRows(zz+2).applyOnTheRight(zz, zz-1,G);
381 m_T.topRows(zz+1).applyOnTheRight(zz, zz-1,G);
382 m_S.coeffRef(zz+1,zz-1) = Scalar(0.0);
383 // update Z
384 if (m_computeQZ)
385 m_Z.applyOnTheLeft(zz,zz-1,G.adjoint());
386 }
387 }
388 // finally kill S(l,l-1)
389 G.makeGivens(m_S.coeff(l,l), m_S.coeff(l,l-1));
390 m_S.applyOnTheRight(l,l-1,G);
391 m_T.applyOnTheRight(l,l-1,G);
392 m_S.coeffRef(l,l-1)=Scalar(0.0);
393 // update Z
394 if (m_computeQZ)
395 m_Z.applyOnTheLeft(l,l-1,G.adjoint());
396 }

References Eigen::JacobiRotation< Scalar >::adjoint(), and Eigen::JacobiRotation< Scalar >::makeGivens().

+ Here is the call graph for this function:

◆ setMaxIterations()

template<typename _MatrixType >
RealQZ & Eigen::RealQZ< _MatrixType >::setMaxIterations ( Index  maxIters)
inline

Sets the maximal number of iterations allowed to converge to one eigenvalue or decouple the problem.

184 {
185 m_maxIters = maxIters;
186 return *this;
187 }

References Eigen::RealQZ< _MatrixType >::m_maxIters.

Referenced by Eigen::GeneralizedEigenSolver< _MatrixType >::setMaxIterations().

+ Here is the caller graph for this function:

◆ splitOffTwoRows()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::splitOffTwoRows ( Index  i)
inlineprivate
312 {
313 using std::abs;
314 using std::sqrt;
315 const Index dim=m_S.cols();
316 if (abs(m_S.coeff(i+1,i))==Scalar(0))
317 return;
318 Index j = findSmallDiagEntry(i,i+1);
319 if (j==i-1)
320 {
321 // block of (S T^{-1})
322 Matrix2s STi = m_T.template block<2,2>(i,i).template triangularView<Upper>().
323 template solve<OnTheRight>(m_S.template block<2,2>(i,i));
324 Scalar p = Scalar(0.5)*(STi(0,0)-STi(1,1));
325 Scalar q = p*p + STi(1,0)*STi(0,1);
326 if (q>=0) {
327 Scalar z = sqrt(q);
328 // one QR-like iteration for ABi - lambda I
329 // is enough - when we know exact eigenvalue in advance,
330 // convergence is immediate
331 JRs G;
332 if (p>=0)
333 G.makeGivens(p + z, STi(1,0));
334 else
335 G.makeGivens(p - z, STi(1,0));
336 m_S.rightCols(dim-i).applyOnTheLeft(i,i+1,G.adjoint());
337 m_T.rightCols(dim-i).applyOnTheLeft(i,i+1,G.adjoint());
338 // update Q
339 if (m_computeQZ)
340 m_Q.applyOnTheRight(i,i+1,G);
341
342 G.makeGivens(m_T.coeff(i+1,i+1), m_T.coeff(i+1,i));
343 m_S.topRows(i+2).applyOnTheRight(i+1,i,G);
344 m_T.topRows(i+2).applyOnTheRight(i+1,i,G);
345 // update Z
346 if (m_computeQZ)
347 m_Z.applyOnTheLeft(i+1,i,G.adjoint());
348
349 m_S.coeffRef(i+1,i) = Scalar(0.0);
350 m_T.coeffRef(i+1,i) = Scalar(0.0);
351 }
352 }
353 else
354 {
355 pushDownZero(j,i,i+1);
356 }
357 }
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
Definition ArrayCwiseUnaryOps.h:152
Matrix< Scalar, 2, 2 > Matrix2s
Definition RealQZ.h:202

References Eigen::JacobiRotation< Scalar >::adjoint(), Eigen::JacobiRotation< Scalar >::makeGivens(), and sqrt().

+ Here is the call graph for this function:

◆ step()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::step ( Index  f,
Index  l,
Index  iter 
)
inlineprivate
401 {
402 using std::abs;
403 const Index dim = m_S.cols();
404
405 // x, y, z
406 Scalar x, y, z;
407 if (iter==10)
408 {
409 // Wilkinson ad hoc shift
410 const Scalar
411 a11=m_S.coeff(f+0,f+0), a12=m_S.coeff(f+0,f+1),
412 a21=m_S.coeff(f+1,f+0), a22=m_S.coeff(f+1,f+1), a32=m_S.coeff(f+2,f+1),
413 b12=m_T.coeff(f+0,f+1),
414 b11i=Scalar(1.0)/m_T.coeff(f+0,f+0),
415 b22i=Scalar(1.0)/m_T.coeff(f+1,f+1),
416 a87=m_S.coeff(l-1,l-2),
417 a98=m_S.coeff(l-0,l-1),
418 b77i=Scalar(1.0)/m_T.coeff(l-2,l-2),
419 b88i=Scalar(1.0)/m_T.coeff(l-1,l-1);
420 Scalar ss = abs(a87*b77i) + abs(a98*b88i),
421 lpl = Scalar(1.5)*ss,
422 ll = ss*ss;
423 x = ll + a11*a11*b11i*b11i - lpl*a11*b11i + a12*a21*b11i*b22i
424 - a11*a21*b12*b11i*b11i*b22i;
425 y = a11*a21*b11i*b11i - lpl*a21*b11i + a21*a22*b11i*b22i
426 - a21*a21*b12*b11i*b11i*b22i;
427 z = a21*a32*b11i*b22i;
428 }
429 else if (iter==16)
430 {
431 // another exceptional shift
432 x = m_S.coeff(f,f)/m_T.coeff(f,f)-m_S.coeff(l,l)/m_T.coeff(l,l) + m_S.coeff(l,l-1)*m_T.coeff(l-1,l) /
433 (m_T.coeff(l-1,l-1)*m_T.coeff(l,l));
434 y = m_S.coeff(f+1,f)/m_T.coeff(f,f);
435 z = 0;
436 }
437 else if (iter>23 && !(iter%8))
438 {
439 // extremely exceptional shift
440 x = internal::random<Scalar>(-1.0,1.0);
441 y = internal::random<Scalar>(-1.0,1.0);
442 z = internal::random<Scalar>(-1.0,1.0);
443 }
444 else
445 {
446 // Compute the shifts: (x,y,z,0...) = (AB^-1 - l1 I) (AB^-1 - l2 I) e1
447 // where l1 and l2 are the eigenvalues of the 2x2 matrix C = U V^-1 where
448 // U and V are 2x2 bottom right sub matrices of A and B. Thus:
449 // = AB^-1AB^-1 + l1 l2 I - (l1+l2)(AB^-1)
450 // = AB^-1AB^-1 + det(M) - tr(M)(AB^-1)
451 // Since we are only interested in having x, y, z with a correct ratio, we have:
452 const Scalar
453 a11 = m_S.coeff(f,f), a12 = m_S.coeff(f,f+1),
454 a21 = m_S.coeff(f+1,f), a22 = m_S.coeff(f+1,f+1),
455 a32 = m_S.coeff(f+2,f+1),
456
457 a88 = m_S.coeff(l-1,l-1), a89 = m_S.coeff(l-1,l),
458 a98 = m_S.coeff(l,l-1), a99 = m_S.coeff(l,l),
459
460 b11 = m_T.coeff(f,f), b12 = m_T.coeff(f,f+1),
461 b22 = m_T.coeff(f+1,f+1),
462
463 b88 = m_T.coeff(l-1,l-1), b89 = m_T.coeff(l-1,l),
464 b99 = m_T.coeff(l,l);
465
466 x = ( (a88/b88 - a11/b11)*(a99/b99 - a11/b11) - (a89/b99)*(a98/b88) + (a98/b88)*(b89/b99)*(a11/b11) ) * (b11/a21)
467 + a12/b22 - (a11/b11)*(b12/b22);
468 y = (a22/b22-a11/b11) - (a21/b11)*(b12/b22) - (a88/b88-a11/b11) - (a99/b99-a11/b11) + (a98/b88)*(b89/b99);
469 z = a32/b22;
470 }
471
472 JRs G;
473
474 for (Index k=f; k<=l-2; k++)
475 {
476 // variables for Householder reflections
477 Vector2s essential2;
478 Scalar tau, beta;
479
480 Vector3s hr(x,y,z);
481
482 // Q_k to annihilate S(k+1,k-1) and S(k+2,k-1)
483 hr.makeHouseholderInPlace(tau, beta);
484 essential2 = hr.template bottomRows<2>();
485 Index fc=(std::max)(k-1,Index(0)); // first col to update
486 m_S.template middleRows<3>(k).rightCols(dim-fc).applyHouseholderOnTheLeft(essential2, tau, m_workspace.data());
487 m_T.template middleRows<3>(k).rightCols(dim-fc).applyHouseholderOnTheLeft(essential2, tau, m_workspace.data());
488 if (m_computeQZ)
489 m_Q.template middleCols<3>(k).applyHouseholderOnTheRight(essential2, tau, m_workspace.data());
490 if (k>f)
491 m_S.coeffRef(k+2,k-1) = m_S.coeffRef(k+1,k-1) = Scalar(0.0);
492
493 // Z_{k1} to annihilate T(k+2,k+1) and T(k+2,k)
494 hr << m_T.coeff(k+2,k+2),m_T.coeff(k+2,k),m_T.coeff(k+2,k+1);
495 hr.makeHouseholderInPlace(tau, beta);
496 essential2 = hr.template bottomRows<2>();
497 {
498 Index lr = (std::min)(k+4,dim); // last row to update
499 Map<Matrix<Scalar,Dynamic,1> > tmp(m_workspace.data(),lr);
500 // S
501 tmp = m_S.template middleCols<2>(k).topRows(lr) * essential2;
502 tmp += m_S.col(k+2).head(lr);
503 m_S.col(k+2).head(lr) -= tau*tmp;
504 m_S.template middleCols<2>(k).topRows(lr) -= (tau*tmp) * essential2.adjoint();
505 // T
506 tmp = m_T.template middleCols<2>(k).topRows(lr) * essential2;
507 tmp += m_T.col(k+2).head(lr);
508 m_T.col(k+2).head(lr) -= tau*tmp;
509 m_T.template middleCols<2>(k).topRows(lr) -= (tau*tmp) * essential2.adjoint();
510 }
511 if (m_computeQZ)
512 {
513 // Z
514 Map<Matrix<Scalar,1,Dynamic> > tmp(m_workspace.data(),dim);
515 tmp = essential2.adjoint()*(m_Z.template middleRows<2>(k));
516 tmp += m_Z.row(k+2);
517 m_Z.row(k+2) -= tau*tmp;
518 m_Z.template middleRows<2>(k) -= essential2 * (tau*tmp);
519 }
520 m_T.coeffRef(k+2,k) = m_T.coeffRef(k+2,k+1) = Scalar(0.0);
521
522 // Z_{k2} to annihilate T(k+1,k)
523 G.makeGivens(m_T.coeff(k+1,k+1), m_T.coeff(k+1,k));
524 m_S.applyOnTheRight(k+1,k,G);
525 m_T.applyOnTheRight(k+1,k,G);
526 // update Z
527 if (m_computeQZ)
528 m_Z.applyOnTheLeft(k+1,k,G.adjoint());
529 m_T.coeffRef(k+1,k) = Scalar(0.0);
530
531 // update x,y,z
532 x = m_S.coeff(k+1,k);
533 y = m_S.coeff(k+2,k);
534 if (k < l-2)
535 z = m_S.coeff(k+3,k);
536 } // loop over k
537
538 // Q_{n-1} to annihilate y = S(l,l-2)
539 G.makeGivens(x,y);
540 m_S.applyOnTheLeft(l-1,l,G.adjoint());
541 m_T.applyOnTheLeft(l-1,l,G.adjoint());
542 if (m_computeQZ)
543 m_Q.applyOnTheRight(l-1,l,G);
544 m_S.coeffRef(l,l-2) = Scalar(0.0);
545
546 // Z_{n-1} to annihilate T(l,l-1)
547 G.makeGivens(m_T.coeff(l,l),m_T.coeff(l,l-1));
548 m_S.applyOnTheRight(l,l-1,G);
549 m_T.applyOnTheRight(l,l-1,G);
550 if (m_computeQZ)
551 m_Z.applyOnTheLeft(l,l-1,G.adjoint());
552 m_T.coeffRef(l,l-1) = Scalar(0.0);
553 }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar * data() const
Definition PlainObjectBase.h:255
Matrix< Scalar, 3, 1 > Vector3s
Definition RealQZ.h:200
Matrix< Scalar, 2, 1 > Vector2s
Definition RealQZ.h:201
const Scalar & y
Definition MathFunctions.h:552
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297

References Eigen::JacobiRotation< Scalar >::adjoint(), Eigen::PlainObjectBase< Derived >::coeff(), Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols >::coeffRef(), Eigen::PlainObjectBase< Derived >::data(), and Eigen::JacobiRotation< Scalar >::makeGivens().

+ Here is the call graph for this function:

Member Data Documentation

◆ m_computeQZ

template<typename _MatrixType >
bool Eigen::RealQZ< _MatrixType >::m_computeQZ
private

◆ m_global_iter

template<typename _MatrixType >
Index Eigen::RealQZ< _MatrixType >::m_global_iter
private

◆ m_info

template<typename _MatrixType >
ComputationInfo Eigen::RealQZ< _MatrixType >::m_info
private

◆ m_isInitialized

◆ m_maxIters

template<typename _MatrixType >
Index Eigen::RealQZ< _MatrixType >::m_maxIters
private

◆ m_normOfS

template<typename _MatrixType >
Scalar Eigen::RealQZ< _MatrixType >::m_normOfS
private

◆ m_normOfT

template<typename _MatrixType >
Scalar Eigen::RealQZ< _MatrixType >::m_normOfT
private

◆ m_Q

template<typename _MatrixType >
MatrixType Eigen::RealQZ< _MatrixType >::m_Q
private

◆ m_S

template<typename _MatrixType >
MatrixType Eigen::RealQZ< _MatrixType >::m_S
private

◆ m_T

template<typename _MatrixType >
MatrixType Eigen::RealQZ< _MatrixType >::m_T
private

◆ m_workspace

template<typename _MatrixType >
Matrix<Scalar,Dynamic,1> Eigen::RealQZ< _MatrixType >::m_workspace
private

◆ m_Z

template<typename _MatrixType >
MatrixType Eigen::RealQZ< _MatrixType >::m_Z
private

The documentation for this class was generated from the following file: