Eigen::RealQZ< MatrixType_ > Class Template Reference

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

#include <RealQZ.h>

Public Types

enum  {
  RowsAtCompileTime = MatrixType::RowsAtCompileTime , ColsAtCompileTime = MatrixType::ColsAtCompileTime , Options = internal::traits<MatrixType>::Options , MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime ,
  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
}
 
typedef MatrixType_ MatrixType
 
typedef MatrixType::Scalar Scalar
 
typedef std::complex< typename NumTraits< Scalar >::RealComplexScalar
 
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. More...
 
 RealQZ (const MatrixType &A, const MatrixType &B, bool computeQZ=true)
 Constructor; computes real QZ decomposition of given matrices. More...
 
const MatrixTypematrixQ () const
 Returns matrix Q in the QZ decomposition. More...
 
const MatrixTypematrixZ () const
 Returns matrix Z in the QZ decomposition. More...
 
const MatrixTypematrixS () const
 Returns matrix S in the QZ decomposition. More...
 
const MatrixTypematrixT () const
 Returns matrix S in the QZ decomposition. More...
 
RealQZcompute (const MatrixType &A, const MatrixType &B, bool computeQZ=true)
 Computes QZ decomposition of given matrix. More...
 
ComputationInfo info () const
 Reports whether previous computation was successful. More...
 
Index iterations () const
 Returns number of performed QR-like iterations. More...
 
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
MatrixType_the 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:

MatrixXf A = MatrixXf::Random(4, 4);
MatrixXf B = MatrixXf::Random(4, 4);
RealQZ<MatrixXf> qz(4); // preallocate space for 4x4 matrices
qz.compute(A, B); // A = Q S Z, B = Q T Z
// print original matrices and result of decomposition
cout << "A:\n"
<< A << "\n"
<< "B:\n"
<< B << "\n";
cout << "S:\n"
<< qz.matrixS() << "\n"
<< "T:\n"
<< qz.matrixT() << "\n";
cout << "Q:\n"
<< qz.matrixQ() << "\n"
<< "Z:\n"
<< qz.matrixZ() << "\n";
// verify precision
cout << "\nErrors:"
<< "\n|A-QSZ|: " << (A - qz.matrixQ() * qz.matrixS() * qz.matrixZ()).norm()
<< ", |B-QTZ|: " << (B - qz.matrixQ() * qz.matrixT() * qz.matrixZ()).norm()
<< "\n|QQ* - I|: " << (qz.matrixQ() * qz.matrixQ().adjoint() - MatrixXf::Identity(4, 4)).norm()
<< ", |ZZ* - I|: " << (qz.matrixZ() * qz.matrixZ().adjoint() - MatrixXf::Identity(4, 4)).norm() << "\n";
RealQZ< MatrixXf > qz(4)
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
Definition: matrices.h:74

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
Deprecated:
since Eigen 3.3

◆ 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 
64  {
65  RowsAtCompileTime = MatrixType::RowsAtCompileTime,
66  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
67  Options = internal::traits<MatrixType>::Options,
68  MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
69  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
70  };
@ ColsAtCompileTime
Definition: RealQZ.h:66
@ Options
Definition: RealQZ.h:67
@ MaxRowsAtCompileTime
Definition: RealQZ.h:68
@ RowsAtCompileTime
Definition: RealQZ.h:65
@ MaxColsAtCompileTime
Definition: RealQZ.h:69

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.
90  : m_S(size, size),
91  m_T(size, size),
92  m_Q(size, size),
93  m_Z(size, size),
94  m_workspace(size * 2),
95  m_maxIters(400),
96  m_isInitialized(false),
97  m_computeQZ(true) {}
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
Matrix< Scalar, Dynamic, 1 > m_workspace
Definition: RealQZ.h:192
MatrixType m_Q
Definition: RealQZ.h:191
bool m_computeQZ
Definition: RealQZ.h:196
MatrixType m_S
Definition: RealQZ.h:191
MatrixType m_Z
Definition: RealQZ.h:191
MatrixType m_T
Definition: RealQZ.h:191
bool m_isInitialized
Definition: RealQZ.h:195
Index m_maxIters
Definition: RealQZ.h:194

◆ 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.

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

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

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
502  {
503  const Index dim = A_in.cols();
504 
505  eigen_assert(A_in.rows() == dim && A_in.cols() == dim && B_in.rows() == dim && B_in.cols() == dim &&
506  "Need square matrices of the same dimension");
507 
508  m_isInitialized = true;
509  m_computeQZ = computeQZ;
510  m_S = A_in;
511  m_T = B_in;
512  m_workspace.resize(dim * 2);
513  m_global_iter = 0;
514 
515  // entrance point: hessenberg triangular decomposition
517  // compute L1 vector norms of T, S into m_normOfS, m_normOfT
518  computeNorms();
519 
520  Index l = dim - 1, f, local_iter = 0;
521 
522  while (l > 0 && local_iter < m_maxIters) {
524  // now rows and columns f..l (including) decouple from the rest of the problem
525  if (f > 0) m_S.coeffRef(f, f - 1) = Scalar(0.0);
526  if (f == l) // One root found
527  {
528  l--;
529  local_iter = 0;
530  } else if (f == l - 1) // Two roots found
531  {
533  l -= 2;
534  local_iter = 0;
535  } else // No convergence yet
536  {
537  // if there's zero on diagonal of T, we can isolate an eigenvalue with Givens rotations
538  Index z = findSmallDiagEntry(f, l);
539  if (z >= f) {
540  // zero found
541  pushDownZero(z, f, l);
542  } else {
543  // We are sure now that S.block(f,f, l-f+1,l-f+1) is underuced upper-Hessenberg
544  // and T.block(f,f, l-f+1,l-f+1) is invertible uper-triangular, which allows to
545  // apply a QR-like iteration to rows and columns f..l.
546  step(f, l, local_iter);
547  local_iter++;
548  m_global_iter++;
549  }
550  }
551  }
552  // check if we converged before reaching iterations limit
553  m_info = (local_iter < m_maxIters) ? Success : NoConvergence;
554 
555  // For each non triangular 2x2 diagonal block of S,
556  // reduce the respective 2x2 diagonal block of T to positive diagonal form using 2x2 SVD.
557  // This step is not mandatory for QZ, but it does help further extraction of eigenvalues/eigenvectors,
558  // and is in par with Lapack/Matlab QZ.
559  if (m_info == Success) {
560  for (Index i = 0; i < dim - 1; ++i) {
561  if (!numext::is_exactly_zero(m_S.coeff(i + 1, i))) {
562  JacobiRotation<Scalar> j_left, j_right;
563  internal::real_2x2_jacobi_svd(m_T, i, i + 1, &j_left, &j_right);
564 
565  // Apply resulting Jacobi rotations
566  m_S.applyOnTheLeft(i, i + 1, j_left);
567  m_S.applyOnTheRight(i, i + 1, j_right);
568  m_T.applyOnTheLeft(i, i + 1, j_left);
569  m_T.applyOnTheRight(i, i + 1, j_right);
570  m_T(i + 1, i) = m_T(i, i + 1) = Scalar(0);
571 
572  if (m_computeQZ) {
573  m_Q.applyOnTheRight(i, i + 1, j_left.transpose());
574  m_Z.applyOnTheLeft(i, i + 1, j_right.transpose());
575  }
576 
577  i++;
578  }
579  }
580  }
581 
582  return *this;
583 } // end compute
int i
Definition: BiCGSTAB_step_by_step.cpp:9
#define eigen_assert(x)
Definition: Macros.h:910
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE void resize(Index rows, Index cols)
Definition: PlainObjectBase.h:294
void computeNorms()
Definition: RealQZ.h:257
Index m_global_iter
Definition: RealQZ.h:198
Index findSmallSubdiagEntry(Index iu)
Definition: RealQZ.h:269
void splitOffTwoRows(Index i)
Definition: RealQZ.h:295
MatrixType::Scalar Scalar
Definition: RealQZ.h:71
void step(Index f, Index l, Index iter)
Definition: RealQZ.h:371
void hessenbergTriangular()
Definition: RealQZ.h:217
Eigen::Index Index
Definition: RealQZ.h:73
ComputationInfo m_info
Definition: RealQZ.h:193
Index findSmallDiagEntry(Index f, Index l)
Definition: RealQZ.h:283
void pushDownZero(Index z, Index f, Index l)
Definition: RealQZ.h:338
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
@ Success
Definition: Constants.h:440
@ NoConvergence
Definition: Constants.h:444
void real_2x2_jacobi_svd(const MatrixType &matrix, Index p, Index q, JacobiRotation< RealScalar > *j_left, JacobiRotation< RealScalar > *j_right)
Definition: RealSvd2x2.h:22
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool is_exactly_zero(const X &x)
Definition: Meta.h:592

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

Referenced by Eigen::GeneralizedEigenSolver< MatrixType_ >::compute(), and Eigen::RealQZ< MatrixType_ >::RealQZ().

◆ computeNorms()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::computeNorms
inlineprivate

Computes vector L1 norms of S and T when in Hessenberg-Triangular form already

257  {
258  const Index size = m_S.cols();
259  m_normOfS = Scalar(0.0);
260  m_normOfT = Scalar(0.0);
261  for (Index j = 0; j < size; ++j) {
262  m_normOfS += m_S.col(j).segment(0, (std::min)(size, j + 2)).cwiseAbs().sum();
263  m_normOfT += m_T.row(j).segment(j, size - j).cwiseAbs().sum();
264  }
265 }
Scalar m_normOfS
Definition: RealQZ.h:197
Scalar m_normOfT
Definition: RealQZ.h:197
#define min(a, b)
Definition: datatypes.h:22
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References j, min, and size.

◆ findSmallDiagEntry()

template<typename MatrixType >
Index Eigen::RealQZ< MatrixType >::findSmallDiagEntry ( Index  f,
Index  l 
)
inlineprivate

Look for single small diagonal element T(res, res) for res between f and l, and return res (or f-1)

283  {
284  using std::abs;
285  Index res = l;
286  while (res >= f) {
287  if (abs(m_T.coeff(res, res)) <= NumTraits<Scalar>::epsilon() * m_normOfT) break;
288  res--;
289  }
290  return res;
291 }
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
Definition: PartialRedux_count.cpp:3
double epsilon
Definition: osc_ring_sarah_asymptotics.h:43

References abs(), f(), and res.

◆ findSmallSubdiagEntry()

template<typename MatrixType >
Index Eigen::RealQZ< MatrixType >::findSmallSubdiagEntry ( Index  iu)
inlineprivate

Look for single small sub-diagonal element S(res, res-1) and return res (or 0)

269  {
270  using std::abs;
271  Index res = iu;
272  while (res > 0) {
273  Scalar s = abs(m_S.coeff(res - 1, res - 1)) + abs(m_S.coeff(res, res));
275  if (abs(m_S.coeff(res, res - 1)) < NumTraits<Scalar>::epsilon() * s) break;
276  res--;
277  }
278  return res;
279 }
SCALAR Scalar
Definition: bench_gemm.cpp:45
RealScalar s
Definition: level1_cplx_impl.h:130

References abs(), Eigen::numext::is_exactly_zero(), res, and s.

◆ hessenbergTriangular()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::hessenbergTriangular
private

Reduces S and T to upper Hessenberg - triangular form

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

References G, Eigen::HouseholderQR< MatrixType_ >::householderQ(), i, Eigen::numext::is_exactly_zero(), j, and Eigen::HouseholderQR< MatrixType_ >::matrixQR().

◆ info()

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

Reports whether previous computation was successful.

Returns
Success if computation was successful, NoConvergence otherwise.
170  {
171  eigen_assert(m_isInitialized && "RealQZ is not initialized.");
172  return m_info;
173  }

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

Referenced by Eigen::GeneralizedEigenSolver< MatrixType_ >::compute(), and Eigen::GeneralizedEigenSolver< MatrixType_ >::info().

◆ iterations()

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

Returns number of performed QR-like iterations.

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

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.
123  {
124  eigen_assert(m_isInitialized && "RealQZ is not initialized.");
125  eigen_assert(m_computeQZ && "The matrices Q and Z have not been computed during the QZ decomposition.");
126  return m_Q;
127  }

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.
143  {
144  eigen_assert(m_isInitialized && "RealQZ is not initialized.");
145  return m_S;
146  }

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

Referenced by Eigen::GeneralizedEigenSolver< MatrixType_ >::compute().

◆ 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.
152  {
153  eigen_assert(m_isInitialized && "RealQZ is not initialized.");
154  return m_T;
155  }

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

Referenced by Eigen::GeneralizedEigenSolver< MatrixType_ >::compute().

◆ 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.
133  {
134  eigen_assert(m_isInitialized && "RealQZ is not initialized.");
135  eigen_assert(m_computeQZ && "The matrices Q and Z have not been computed during the QZ decomposition.");
136  return m_Z;
137  }

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

Referenced by Eigen::GeneralizedEigenSolver< MatrixType_ >::compute().

◆ pushDownZero()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::pushDownZero ( Index  z,
Index  f,
Index  l 
)
inlineprivate

use zero in T(z,z) to zero S(l,l-1), working in block f..l

338  {
339  JRs G;
340  const Index dim = m_S.cols();
341  for (Index zz = z; zz < l; zz++) {
342  // push 0 down
343  Index firstColS = zz > f ? (zz - 1) : zz;
344  G.makeGivens(m_T.coeff(zz, zz + 1), m_T.coeff(zz + 1, zz + 1));
345  m_S.rightCols(dim - firstColS).applyOnTheLeft(zz, zz + 1, G.adjoint());
346  m_T.rightCols(dim - zz).applyOnTheLeft(zz, zz + 1, G.adjoint());
347  m_T.coeffRef(zz + 1, zz + 1) = Scalar(0.0);
348  // update Q
349  if (m_computeQZ) m_Q.applyOnTheRight(zz, zz + 1, G);
350  // kill S(zz+1, zz-1)
351  if (zz > f) {
352  G.makeGivens(m_S.coeff(zz + 1, zz), m_S.coeff(zz + 1, zz - 1));
353  m_S.topRows(zz + 2).applyOnTheRight(zz, zz - 1, G);
354  m_T.topRows(zz + 1).applyOnTheRight(zz, zz - 1, G);
355  m_S.coeffRef(zz + 1, zz - 1) = Scalar(0.0);
356  // update Z
357  if (m_computeQZ) m_Z.applyOnTheLeft(zz, zz - 1, G.adjoint());
358  }
359  }
360  // finally kill S(l,l-1)
361  G.makeGivens(m_S.coeff(l, l), m_S.coeff(l, l - 1));
362  m_S.applyOnTheRight(l, l - 1, G);
363  m_T.applyOnTheRight(l, l - 1, G);
364  m_S.coeffRef(l, l - 1) = Scalar(0.0);
365  // update Z
366  if (m_computeQZ) m_Z.applyOnTheLeft(l, l - 1, G.adjoint());
367 }

References f(), and G.

◆ 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.

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

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

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

◆ splitOffTwoRows()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::splitOffTwoRows ( Index  i)
inlineprivate

decouple 2x2 diagonal block in rows i, i+1 if eigenvalues are real

295  {
296  using std::abs;
297  using std::sqrt;
298  const Index dim = m_S.cols();
299  if (numext::is_exactly_zero(abs(m_S.coeff(i + 1, i)))) return;
300  Index j = findSmallDiagEntry(i, i + 1);
301  if (j == i - 1) {
302  // block of (S T^{-1})
303  Matrix2s STi = m_T.template block<2, 2>(i, i).template triangularView<Upper>().template solve<OnTheRight>(
304  m_S.template block<2, 2>(i, i));
305  Scalar p = Scalar(0.5) * (STi(0, 0) - STi(1, 1));
306  Scalar q = p * p + STi(1, 0) * STi(0, 1);
307  if (q >= 0) {
308  Scalar z = sqrt(q);
309  // one QR-like iteration for ABi - lambda I
310  // is enough - when we know exact eigenvalue in advance,
311  // convergence is immediate
312  JRs G;
313  if (p >= 0)
314  G.makeGivens(p + z, STi(1, 0));
315  else
316  G.makeGivens(p - z, STi(1, 0));
317  m_S.rightCols(dim - i).applyOnTheLeft(i, i + 1, G.adjoint());
318  m_T.rightCols(dim - i).applyOnTheLeft(i, i + 1, G.adjoint());
319  // update Q
320  if (m_computeQZ) m_Q.applyOnTheRight(i, i + 1, G);
321 
322  G.makeGivens(m_T.coeff(i + 1, i + 1), m_T.coeff(i + 1, i));
323  m_S.topRows(i + 2).applyOnTheRight(i + 1, i, G);
324  m_T.topRows(i + 2).applyOnTheRight(i + 1, i, G);
325  // update Z
326  if (m_computeQZ) m_Z.applyOnTheLeft(i + 1, i, G.adjoint());
327 
328  m_S.coeffRef(i + 1, i) = Scalar(0.0);
329  m_T.coeffRef(i + 1, i) = Scalar(0.0);
330  }
331  } else {
332  pushDownZero(j, i, i + 1);
333  }
334 }
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
float * p
Definition: Tutorial_Map_using.cpp:9
Matrix< Scalar, 2, 2 > Matrix2s
Definition: RealQZ.h:202
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:2019

References abs(), G, i, Eigen::numext::is_exactly_zero(), j, p, Eigen::numext::q, and sqrt().

◆ step()

template<typename MatrixType >
void Eigen::RealQZ< MatrixType >::step ( Index  f,
Index  l,
Index  iter 
)
inlineprivate

QR-like iterative step for block f..l

371  {
372  using std::abs;
373  const Index dim = m_S.cols();
374 
375  // x, y, z
376  Scalar x, y, z;
377  if (iter == 10) {
378  // Wilkinson ad hoc shift
379  const Scalar a11 = m_S.coeff(f + 0, f + 0), a12 = m_S.coeff(f + 0, f + 1), a21 = m_S.coeff(f + 1, f + 0),
380  a22 = m_S.coeff(f + 1, f + 1), a32 = m_S.coeff(f + 2, f + 1), b12 = m_T.coeff(f + 0, f + 1),
381  b11i = Scalar(1.0) / m_T.coeff(f + 0, f + 0), b22i = Scalar(1.0) / m_T.coeff(f + 1, f + 1),
382  a87 = m_S.coeff(l - 1, l - 2), a98 = m_S.coeff(l - 0, l - 1),
383  b77i = Scalar(1.0) / m_T.coeff(l - 2, l - 2), b88i = Scalar(1.0) / m_T.coeff(l - 1, l - 1);
384  Scalar ss = abs(a87 * b77i) + abs(a98 * b88i), lpl = Scalar(1.5) * ss, ll = ss * ss;
385  x = ll + a11 * a11 * b11i * b11i - lpl * a11 * b11i + a12 * a21 * b11i * b22i -
386  a11 * a21 * b12 * b11i * b11i * b22i;
387  y = a11 * a21 * b11i * b11i - lpl * a21 * b11i + a21 * a22 * b11i * b22i - a21 * a21 * b12 * b11i * b11i * b22i;
388  z = a21 * a32 * b11i * b22i;
389  } else if (iter == 16) {
390  // another exceptional shift
391  x = m_S.coeff(f, f) / m_T.coeff(f, f) - m_S.coeff(l, l) / m_T.coeff(l, l) +
392  m_S.coeff(l, l - 1) * m_T.coeff(l - 1, l) / (m_T.coeff(l - 1, l - 1) * m_T.coeff(l, l));
393  y = m_S.coeff(f + 1, f) / m_T.coeff(f, f);
394  z = 0;
395  } else if (iter > 23 && !(iter % 8)) {
396  // extremely exceptional shift
397  x = internal::random<Scalar>(-1.0, 1.0);
398  y = internal::random<Scalar>(-1.0, 1.0);
399  z = internal::random<Scalar>(-1.0, 1.0);
400  } else {
401  // Compute the shifts: (x,y,z,0...) = (AB^-1 - l1 I) (AB^-1 - l2 I) e1
402  // where l1 and l2 are the eigenvalues of the 2x2 matrix C = U V^-1 where
403  // U and V are 2x2 bottom right sub matrices of A and B. Thus:
404  // = AB^-1AB^-1 + l1 l2 I - (l1+l2)(AB^-1)
405  // = AB^-1AB^-1 + det(M) - tr(M)(AB^-1)
406  // Since we are only interested in having x, y, z with a correct ratio, we have:
407  const Scalar a11 = m_S.coeff(f, f), a12 = m_S.coeff(f, f + 1), a21 = m_S.coeff(f + 1, f),
408  a22 = m_S.coeff(f + 1, f + 1), a32 = m_S.coeff(f + 2, f + 1),
409 
410  a88 = m_S.coeff(l - 1, l - 1), a89 = m_S.coeff(l - 1, l), a98 = m_S.coeff(l, l - 1),
411  a99 = m_S.coeff(l, l),
412 
413  b11 = m_T.coeff(f, f), b12 = m_T.coeff(f, f + 1), b22 = m_T.coeff(f + 1, f + 1),
414 
415  b88 = m_T.coeff(l - 1, l - 1), b89 = m_T.coeff(l - 1, l), b99 = m_T.coeff(l, l);
416 
417  x = ((a88 / b88 - a11 / b11) * (a99 / b99 - a11 / b11) - (a89 / b99) * (a98 / b88) +
418  (a98 / b88) * (b89 / b99) * (a11 / b11)) *
419  (b11 / a21) +
420  a12 / b22 - (a11 / b11) * (b12 / b22);
421  y = (a22 / b22 - a11 / b11) - (a21 / b11) * (b12 / b22) - (a88 / b88 - a11 / b11) - (a99 / b99 - a11 / b11) +
422  (a98 / b88) * (b89 / b99);
423  z = a32 / b22;
424  }
425 
426  JRs G;
427 
428  for (Index k = f; k <= l - 2; k++) {
429  // variables for Householder reflections
430  Vector2s essential2;
431  Scalar tau, beta;
432 
433  Vector3s hr(x, y, z);
434 
435  // Q_k to annihilate S(k+1,k-1) and S(k+2,k-1)
436  hr.makeHouseholderInPlace(tau, beta);
437  essential2 = hr.template bottomRows<2>();
438  Index fc = (std::max)(k - 1, Index(0)); // first col to update
439  m_S.template middleRows<3>(k).rightCols(dim - fc).applyHouseholderOnTheLeft(essential2, tau, m_workspace.data());
440  m_T.template middleRows<3>(k).rightCols(dim - fc).applyHouseholderOnTheLeft(essential2, tau, m_workspace.data());
441  if (m_computeQZ) m_Q.template middleCols<3>(k).applyHouseholderOnTheRight(essential2, tau, m_workspace.data());
442  if (k > f) m_S.coeffRef(k + 2, k - 1) = m_S.coeffRef(k + 1, k - 1) = Scalar(0.0);
443 
444  // Z_{k1} to annihilate T(k+2,k+1) and T(k+2,k)
445  hr << m_T.coeff(k + 2, k + 2), m_T.coeff(k + 2, k), m_T.coeff(k + 2, k + 1);
446  hr.makeHouseholderInPlace(tau, beta);
447  essential2 = hr.template bottomRows<2>();
448  {
449  Index lr = (std::min)(k + 4, dim); // last row to update
450  Map<Matrix<Scalar, Dynamic, 1> > tmp(m_workspace.data(), lr);
451  // S
452  tmp = m_S.template middleCols<2>(k).topRows(lr) * essential2;
453  tmp += m_S.col(k + 2).head(lr);
454  m_S.col(k + 2).head(lr) -= tau * tmp;
455  m_S.template middleCols<2>(k).topRows(lr) -= (tau * tmp) * essential2.adjoint();
456  // T
457  tmp = m_T.template middleCols<2>(k).topRows(lr) * essential2;
458  tmp += m_T.col(k + 2).head(lr);
459  m_T.col(k + 2).head(lr) -= tau * tmp;
460  m_T.template middleCols<2>(k).topRows(lr) -= (tau * tmp) * essential2.adjoint();
461  }
462  if (m_computeQZ) {
463  // Z
464  Map<Matrix<Scalar, 1, Dynamic> > tmp(m_workspace.data(), dim);
465  tmp = essential2.adjoint() * (m_Z.template middleRows<2>(k));
466  tmp += m_Z.row(k + 2);
467  m_Z.row(k + 2) -= tau * tmp;
468  m_Z.template middleRows<2>(k) -= essential2 * (tau * tmp);
469  }
470  m_T.coeffRef(k + 2, k) = m_T.coeffRef(k + 2, k + 1) = Scalar(0.0);
471 
472  // Z_{k2} to annihilate T(k+1,k)
473  G.makeGivens(m_T.coeff(k + 1, k + 1), m_T.coeff(k + 1, k));
474  m_S.applyOnTheRight(k + 1, k, G);
475  m_T.applyOnTheRight(k + 1, k, G);
476  // update Z
477  if (m_computeQZ) m_Z.applyOnTheLeft(k + 1, k, G.adjoint());
478  m_T.coeffRef(k + 1, k) = Scalar(0.0);
479 
480  // update x,y,z
481  x = m_S.coeff(k + 1, k);
482  y = m_S.coeff(k + 2, k);
483  if (k < l - 2) z = m_S.coeff(k + 3, k);
484  } // loop over k
485 
486  // Q_{n-1} to annihilate y = S(l,l-2)
487  G.makeGivens(x, y);
488  m_S.applyOnTheLeft(l - 1, l, G.adjoint());
489  m_T.applyOnTheLeft(l - 1, l, G.adjoint());
490  if (m_computeQZ) m_Q.applyOnTheRight(l - 1, l, G);
491  m_S.coeffRef(l, l - 2) = Scalar(0.0);
492 
493  // Z_{n-1} to annihilate T(l,l-1)
494  G.makeGivens(m_T.coeff(l, l), m_T.coeff(l, l - 1));
495  m_S.applyOnTheRight(l, l - 1, G);
496  m_T.applyOnTheRight(l, l - 1, G);
497  if (m_computeQZ) m_Z.applyOnTheLeft(l, l - 1, G.adjoint());
498  m_T.coeffRef(l, l - 1) = Scalar(0.0);
499 }
constexpr EIGEN_DEVICE_FUNC const Scalar * data() const
Definition: PlainObjectBase.h:273
Matrix< Scalar, 2, 1 > Vector2s
Definition: RealQZ.h:201
Matrix< Scalar, 3, 1 > Vector3s
Definition: RealQZ.h:200
#define max(a, b)
Definition: datatypes.h:23
Scalar * y
Definition: level1_cplx_impl.h:128
Scalar beta
Definition: level2_cplx_impl.h:36
char char char int int * k
Definition: level2_impl.h:374
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
list x
Definition: plotDoE.py:28

References abs(), beta, Eigen::PlainObjectBase< Derived >::coeff(), Eigen::Matrix< Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_ >::coeffRef(), Eigen::PlainObjectBase< Derived >::data(), f(), G, k, max, min, tmp, plotDoE::x, and y.

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: