15#ifndef EIGEN_COMPLEX_QZ_H_
16#define EIGEN_COMPLEX_QZ_H_
19#include "./InternalHeaderCheck.h"
51template <
typename MatrixType_>
54 using MatrixType = MatrixType_;
55 using Scalar =
typename MatrixType_::Scalar;
56 using RealScalar =
typename MatrixType_::RealScalar;
59 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
60 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
61 Options = internal::plain_object_options<MatrixType>::value,
62 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
63 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
68 using PlainMatrixType =
69 Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime>;
71 using Vec = Matrix<Scalar, Dynamic, 1>;
72 using Vec2 = Matrix<Scalar, 2, 1>;
73 using Vec3 = Matrix<Scalar, 3, 1>;
74 using Row2 = Matrix<Scalar, 1, 2>;
75 using Mat2 = Matrix<Scalar, 2, 2>;
81 const PlainMatrixType& matrixQ()
const {
82 eigen_assert(m_isInitialized &&
"ComplexQZ is not initialized.");
83 eigen_assert(m_computeQZ &&
"The matrices Q and Z have not been computed during the QZ decomposition.");
91 const PlainMatrixType& matrixZ()
const {
92 eigen_assert(m_isInitialized &&
"ComplexQZ is not initialized.");
93 eigen_assert(m_computeQZ &&
"The matrices Q and Z have not been computed during the QZ decomposition.");
101 const MatrixType& matrixS()
const {
102 eigen_assert(m_isInitialized &&
"ComplexQZ is not initialized.");
110 const MatrixType& matrixT()
const {
111 eigen_assert(m_isInitialized &&
"ComplexQZ is not initialized.");
123 ComplexQZ(Index n,
bool computeQZ =
true,
unsigned int maxIters = 400)
125 m_maxIters(maxIters),
126 m_computeQZ(computeQZ),
129 m_Q(computeQZ ? n : (MatrixType::RowsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::RowsAtCompileTime),
130 computeQZ ? n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)),
131 m_Z(computeQZ ? n : (MatrixType::RowsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::RowsAtCompileTime),
132 computeQZ ? n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)),
147 template <
typename InputTypeA,
typename InputTypeB>
148 ComplexQZ(
const EigenBase<InputTypeA>& A,
const EigenBase<InputTypeB>& B,
bool computeQZ =
true,
149 unsigned int maxIters = 400)
151 m_maxIters(maxIters),
152 m_computeQZ(computeQZ),
155 m_Q(computeQZ ? m_n : (MatrixType::RowsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::RowsAtCompileTime),
156 computeQZ ? m_n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)),
157 m_Z(computeQZ ? m_n : (MatrixType::RowsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::RowsAtCompileTime),
158 computeQZ ? m_n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)),
161 computeInPlace(computeQZ);
175 template <
typename InputTypeA,
typename InputTypeB>
176 ComplexQZ(EigenBase<InputTypeA>& A, EigenBase<InputTypeB>& B,
bool computeQZ =
true,
unsigned int maxIters = 400)
178 m_maxIters(maxIters),
179 m_computeQZ(computeQZ),
182 m_Q(computeQZ ? m_n : (MatrixType::RowsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::RowsAtCompileTime),
183 computeQZ ? m_n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)),
184 m_Z(computeQZ ? m_n : (MatrixType::RowsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::RowsAtCompileTime),
185 computeQZ ? m_n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)),
188 computeInPlace(computeQZ);
197 template <
typename InputTypeA,
typename InputTypeB>
198 void compute(
const EigenBase<InputTypeA>& A,
const EigenBase<InputTypeB>& B,
bool computeQZ =
true);
208 template <
typename SparseMatrixType_>
209 void computeSparse(
const SparseMatrixType_& A,
const SparseMatrixType_& B,
bool computeQZ =
true);
215 ComputationInfo info()
const {
216 eigen_assert(m_isInitialized &&
"ComplexQZ is not initialized.");
222 unsigned int iterations()
const {
223 eigen_assert(m_isInitialized &&
"ComplexQZ is not initialized.");
224 return m_global_iter;
229 const unsigned int m_maxIters;
230 unsigned int m_global_iter = 0;
231 bool m_isInitialized =
false;
235 PlainMatrixType m_Q, m_Z;
236 RealScalar m_normOfT, m_normOfS;
241 static bool is_negligible(
const Scalar x,
const RealScalar tol = NumTraits<RealScalar>::epsilon()) {
242 return numext::abs(x) <= tol;
245 void do_QZ_step(Index p, Index q,
unsigned int iter);
247 JacobiRotation<Scalar> computeZk2(
const Row2& b);
249 void computeInPlace(
bool computeQZ);
252 void hessenbergTriangular();
256 void reduceHessenbergTriangular();
259 template <
typename SparseMatrixType_>
260 void hessenbergTriangularSparse(
const SparseMatrixType_& A,
const SparseMatrixType_& B);
264 Index findSmallSubdiagEntry(Index l);
265 Index findSmallDiagEntry(Index f, Index l);
267 void push_down_zero_ST(Index k, Index l);
269 void reduceDiagonal2x2block(Index i);
272template <
typename MatrixType_>
273template <
typename InputTypeA,
typename InputTypeB>
275 eigen_assert(A.rows() == A.cols() &&
"A is not a square matrix");
276 eigen_assert(A.rows() == B.rows() && A.rows() == B.cols() &&
277 "B is not a square matrix or B is not of the same size as A");
281 computeInPlace(computeQZ);
285template <
typename MatrixType_>
287 m_computeQZ = computeQZ;
290 eigen_assert(m_n == m_S.cols() &&
"A is not a square matrix");
291 eigen_assert(m_n == m_T.rows() && m_n == m_T.cols() &&
"B is not a square matrix or B is not of the same size as A");
293 m_isInitialized =
true;
298 hessenbergTriangular();
302 reduceHessenbergTriangular();
306template <
typename MatrixType_>
309 m_ws.resize(2 * m_n);
310 m_hCoeffs.resize(m_n);
311 internal::householder_qr_inplace_blocked<MatrixType, Vec>::run(m_T, m_hCoeffs, 48, m_ws.data());
312 Map<Vec> workspace(m_ws.data(), m_n);
314 if (m_computeQZ) householderQ.evalTo(m_Q, workspace);
317 householderQ.adjoint().applyThisOnTheLeft(m_S, workspace);
319 m_T.template triangularView<StrictlyLower>().setZero();
321 if (m_computeQZ) m_Z = PlainMatrixType::Identity(m_n, m_n);
324 for (Index j = 0; j <= m_n - 3; j++) {
325 for (Index i = m_n - 1; i >= j + 2; i--) {
326 JacobiRotation<Scalar> G;
328 if (!numext::is_exactly_zero(m_S.coeff(i, j))) {
329 G.makeGivens(m_S.coeff(i - 1, j), m_S.coeff(i, j), &m_S.coeffRef(i - 1, j));
330 m_S.coeffRef(i, j) = Scalar(0);
331 m_T.rightCols(m_n - i + 1).applyOnTheLeft(i - 1, i, G.adjoint());
332 m_S.rightCols(m_n - j - 1).applyOnTheLeft(i - 1, i, G.adjoint());
334 if (!is_negligible(m_S(i, j)))
337 m_S(i, j) = Scalar(0);
339 if (m_computeQZ) m_Q.applyOnTheRight(i - 1, i, G);
342 if (!numext::is_exactly_zero(m_T.coeff(i, i - 1))) {
344 G.makeGivens(m_T.coeff(i, i), m_T.coeff(i, i - 1), &m_T.coeffRef(i, i));
345 m_T.topRows(i).applyOnTheRight(i - 1, i, G.adjoint());
346 m_T.coeffRef(i, i - 1) = Scalar(0);
348 m_S.applyOnTheRight(i - 1, i, G.adjoint());
350 if (m_computeQZ) m_Z.applyOnTheLeft(i - 1, i, G);
356template <
typename MatrixType>
357template <
typename SparseMatrixType_>
361 SparseQR<SparseMatrix<Scalar, ColMajor>, NaturalOrdering<Index>> sparseQR;
363 eigen_assert(B.isCompressed() &&
364 "SparseQR requires a sparse matrix in compressed mode."
365 "Call .makeCompressed() before passing it to SparseQR");
368 sparseQR.setPivotThreshold(RealScalar(0));
371 m_T = sparseQR.matrixR();
372 m_T.template triangularView<StrictlyLower>().setZero();
374 if (m_computeQZ) m_Q = sparseQR.matrixQ();
377 m_S = sparseQR.matrixQ().adjoint() * m_S;
379 if (m_computeQZ) m_Z = MatrixType::Identity(m_n, m_n);
382 for (Index j = 0; j <= m_n - 3; j++) {
383 for (Index i = m_n - 1; i >= j + 2; i--) {
384 JacobiRotation<Scalar> G;
386 if (m_S.coeff(i, j) != Scalar(0)) {
388 G.makeGivens(m_S.coeff(i - 1, j), m_S.coeff(i, j), &m_S.coeffRef(i - 1, j));
389 m_S.coeffRef(i, j) = Scalar(0);
390 m_T.rightCols(m_n - i + 1).applyOnTheLeft(i - 1, i, G.adjoint());
391 m_S.rightCols(m_n - j - 1).applyOnTheLeft(i - 1, i, G.adjoint());
393 if (!is_negligible(m_S(i, j))) {
396 m_S(i, j) = Scalar(0);
398 if (m_computeQZ) m_Q.applyOnTheRight(i - 1, i, G);
401 if (!numext::is_exactly_zero(m_T.coeff(i, i - 1))) {
403 G.makeGivens(m_T.coeff(i, i), m_T.coeff(i, i - 1), &m_T.coeffRef(i, i));
404 m_T.topRows(i).applyOnTheRight(i - 1, i, G.adjoint());
405 m_T.coeffRef(i, i - 1) = Scalar(0);
407 m_S.applyOnTheRight(i - 1, i, G.adjoint());
409 if (m_computeQZ) m_Z.applyOnTheLeft(i - 1, i, G);
415template <
typename MatrixType>
416template <
typename SparseMatrixType_>
418 m_computeQZ = computeQZ;
420 eigen_assert(m_n == A.cols() &&
"A is not a square matrix");
421 eigen_assert(m_n == B.rows() && m_n == B.cols() &&
"B is not a square matrix or B is not of the same size as A");
422 m_isInitialized =
true;
425 hessenbergTriangularSparse(A, B);
429 reduceHessenbergTriangular();
432template <
typename MatrixType_>
434 m_ws.resize(2 * m_n);
435 Index l = m_n - 1, f;
436 unsigned int local_iter = 0;
439 while (l > 0 && local_iter < m_maxIters) {
440 f = findSmallSubdiagEntry(l);
444 m_S.coeffRef(f, f - 1) = Scalar(0);
449 }
else if (f == l - 1) {
451 reduceDiagonal2x2block(f);
455 Index z = findSmallDiagEntry(f, l);
457 push_down_zero_ST(z, l);
459 do_QZ_step(f, m_n - l - 1, local_iter);
472template <
typename MatrixType_>
474 JacobiRotation<Scalar> J;
475 J.makeGivens(numext::conj(b(1)), numext::conj(b(0)));
477 return J.transpose();
480template <
typename MatrixType_>
484 const auto a = [p,
this](Index i, Index j) {
return m_S(p + i - 1, p + j - 1); };
485 const auto b = [p,
this](Index i, Index j) {
return m_T(p + i - 1, p + j - 1); };
486 const Index m = m_n - p - q;
488 if (iter > 0 && iter % 10 == 0) {
490 const RealScalar displacement =
491 numext::abs(a(m, m - 1) / b(m - 1, m - 1)) + numext::abs(a(m - 1, m - 2) / b(m - 2, m - 2));
492 const Scalar shift = a(m, m) / b(m, m) + displacement;
494 x = a(1, 1) / b(1, 1) - shift;
495 y = a(2, 1) / b(1, 1);
498 Scalar W1 = a(m - 1, m - 1) / b(m - 1, m - 1) - a(1, 1) / b(1, 1), W2 = a(m, m) / b(m, m) - a(1, 1) / b(1, 1),
499 W3 = a(m, m - 1) / b(m - 1, m - 1);
501 x = (W1 * W2 - a(m - 1, m) / b(m, m) * W3 + W3 * b(m - 1, m) / b(m, m) * a(1, 1) / b(1, 1)) * b(1, 1) / a(2, 1) +
502 a(1, 2) / b(2, 2) - a(1, 1) / b(1, 1) * b(1, 2) / b(2, 2);
503 y = (a(2, 2) / b(2, 2) - a(1, 1) / b(1, 1)) - a(2, 1) / b(1, 1) * b(1, 2) / b(2, 2) - W1 - W2 +
504 W3 * (b(m - 1, m) / b(m, m));
505 z = a(3, 2) / b(2, 2);
508 const PermutationMatrix<3, 3, int> S3(
Vector3i(2, 0, 1));
509 for (Index k = p; k < p + m - 2; k++) {
514 X.makeHouseholder(ess, tau, beta);
518 m_S.template middleRows<3>(k)
519 .rightCols((std::min)(m_n, m_n - k + 1))
520 .applyHouseholderOnTheLeft(ess, tau, m_ws.data());
521 m_T.template middleRows<3>(k).rightCols(m_n - k).applyHouseholderOnTheLeft(ess, tau, m_ws.data());
522 if (m_computeQZ) m_Q.template middleCols<3>(k).applyHouseholderOnTheRight(ess, numext::conj(tau), m_ws.data());
525 Vec3 bprime = (m_T.template block<1, 3>(k + 2, k) * S3).adjoint();
526 bprime.makeHouseholder(ess, tau, beta);
527 auto Sk = m_S.template middleCols<3>(k).topRows((std::min)(k + 4, m_n));
528 auto Tk = m_T.template middleCols<3>(k).topRows((std::min)(k + 3, m_n));
530 Sk.col(0).swap(Sk.col(2));
531 Sk.col(1).swap(Sk.col(2));
532 Sk.applyHouseholderOnTheRight(ess, numext::conj(tau), m_ws.data());
533 Sk.col(1).swap(Sk.col(2));
534 Sk.col(0).swap(Sk.col(2));
535 Tk.col(0).swap(Tk.col(2));
536 Tk.col(1).swap(Tk.col(2));
537 Tk.applyHouseholderOnTheRight(ess, numext::conj(tau), m_ws.data());
538 Tk.col(1).swap(Tk.col(2));
539 Tk.col(0).swap(Tk.col(2));
541 auto Zk = m_Z.template middleRows<3>(k);
542 Zk.row(0).swap(Zk.row(2));
543 Zk.row(1).swap(Zk.row(2));
544 Zk.applyHouseholderOnTheLeft(ess, tau, m_ws.data());
545 Zk.row(1).swap(Zk.row(2));
546 Zk.row(0).swap(Zk.row(2));
548 const JacobiRotation<Scalar> Zk2 = computeZk2(m_T.template block<1, 2>(k + 1, k));
549 m_S.template middleCols<2>(k).topRows((std::min)(k + 4, m_n)).applyOnTheRight(0, 1, Zk2);
550 m_T.template middleCols<2>(k).topRows((std::min)(k + 3, m_n)).applyOnTheRight(0, 1, Zk2);
552 if (m_computeQZ) m_Z.template middleRows<2>(k).applyOnTheLeft(0, 1, Zk2.adjoint());
562 JacobiRotation<Scalar> J;
564 m_S.template middleRows<2>(p + m - 2).applyOnTheLeft(0, 1, J.adjoint());
565 m_T.template middleRows<2>(p + m - 2).applyOnTheLeft(0, 1, J.adjoint());
567 if (m_computeQZ) m_Q.template middleCols<2>(p + m - 2).applyOnTheRight(0, 1, J);
570 const JacobiRotation<Scalar> Zn1 = computeZk2(m_T.template block<1, 2>(p + m - 1, p + m - 2));
571 m_S.template middleCols<2>(p + m - 2).applyOnTheRight(0, 1, Zn1);
572 m_T.template middleCols<2>(p + m - 2).applyOnTheRight(0, 1, Zn1);
574 if (m_computeQZ) m_Z.template middleRows<2>(p + m - 2).applyOnTheLeft(0, 1, Zn1.adjoint());
578template <
typename MatrixType_>
581 Mat2 Si = m_S.template block<2, 2>(i, i), Ti = m_T.template block<2, 2>(i, i);
582 const RealScalar tolT = m_normOfT * NumTraits<RealScalar>::epsilon();
583 if (is_negligible(Ti(0, 0), tolT)) {
586 m_S.applyOnTheLeft(i, i + 1, G.
adjoint());
587 m_T.applyOnTheLeft(i, i + 1, G.
adjoint());
589 if (m_computeQZ) m_Q.applyOnTheRight(i, i + 1, G);
591 }
else if (is_negligible(Ti(1, 1), tolT)) {
593 G.
makeGivens(m_S(i + 1, i + 1), m_S(i + 1, i));
594 m_S.applyOnTheRight(i, i + 1, G.
adjoint());
595 m_T.applyOnTheRight(i, i + 1, G.
adjoint());
596 if (m_computeQZ) m_Z.applyOnTheLeft(i, i + 1, G);
598 Scalar mu = Si(0, 0) / Ti(0, 0);
599 Scalar a12_bar = Si(0, 1) - mu * Ti(0, 1);
600 Scalar a22_bar = Si(1, 1) - mu * Ti(1, 1);
601 Scalar p = Scalar(0.5) * (a22_bar / Ti(1, 1) - Ti(0, 1) * Si(1, 0) / (Ti(0, 0) * Ti(1, 1)));
602 RealScalar sgn_p = p.real() >= RealScalar(0) ? RealScalar(1) : RealScalar(-1);
603 Scalar q = Si(1, 0) * a12_bar / (Ti(0, 0) * Ti(1, 1));
604 Scalar r = p * p + q;
605 Scalar lambda = mu + p + sgn_p * numext::sqrt(r);
606 Mat2 E = Si - lambda * Ti;
608 E.rowwise().norm().maxCoeff(&l);
609 JacobiRotation<Scalar> G;
610 G.makeGivens(E(l, 1), E(l, 0));
611 m_S.applyOnTheRight(i, i + 1, G.adjoint());
612 m_T.applyOnTheRight(i, i + 1, G.adjoint());
614 if (m_computeQZ) m_Z.applyOnTheLeft(i, i + 1, G);
616 Mat2 tildeSi = m_S.template block<2, 2>(i, i), tildeTi = m_T.template block<2, 2>(i, i);
617 Mat2 C = tildeSi.norm() < (lambda * tildeTi).norm() ? tildeSi : lambda * tildeTi;
618 G.makeGivens(C(0, 0), C(1, 0));
619 m_S.applyOnTheLeft(i, i + 1, G.adjoint());
620 m_T.applyOnTheLeft(i, i + 1, G.adjoint());
622 if (m_computeQZ) m_Q.applyOnTheRight(i, i + 1, G);
625 if (!is_negligible(m_S(i + 1, i), m_normOfS * NumTraits<RealScalar>::epsilon())) {
628 m_S(i + 1, i) = Scalar(0);
633template <
typename MatrixType_>
635 JacobiRotation<Scalar> J;
636 for (Index j = k + 1; j <= l; j++) {
638 J.makeGivens(m_T(j - 1, j), m_T(j, j), &m_T.coeffRef(j - 1, j));
639 if (m_n - j - 1 > 0) {
640 m_T.rightCols(m_n - j - 1).applyOnTheLeft(j - 1, j, J.adjoint());
642 m_T.coeffRef(j, j) = Scalar(0);
644 m_S.applyOnTheLeft(j - 1, j, J.adjoint());
646 if (m_computeQZ) m_Q.applyOnTheRight(j - 1, j, J);
650 J.makeGivens(numext::conj(m_S(j, j - 1)), numext::conj(m_S(j, j - 2)));
651 m_S.applyOnTheRight(j - 1, j - 2, J);
652 m_S(j, j - 2) = Scalar(0);
653 m_T.applyOnTheRight(j - 1, j - 2, J);
654 if (m_computeQZ) m_Z.applyOnTheLeft(j - 1, j - 2, J.adjoint());
660 J.makeGivens(numext::conj(m_S(l, l)), numext::conj(m_S(l, l - 1)));
661 m_S.topRows(l + 1).applyOnTheRight(l, l - 1, J);
663 if (!is_negligible(m_S(l, l - 1), m_normOfS * NumTraits<Scalar>::epsilon())) {
666 m_S(l, l - 1) = Scalar(0);
668 m_T.topRows(l + 1).applyOnTheRight(l, l - 1, J);
670 if (m_computeQZ) m_Z.applyOnTheLeft(l, l - 1, J.adjoint());
673 if (!is_negligible(m_T(l, l)) || !is_negligible(m_S(l, l - 1))) {
676 m_T(l, l) = Scalar(0);
677 m_S(l, l - 1) = Scalar(0);
682template <
typename MatrixType_>
684 m_normOfS = internal::hessenberg_abs_sum<Upper>(m_S);
685 m_normOfT = internal::triangular_abs_sum<Upper>(m_T);
690template <
typename MatrixType_>
694 RealScalar s = numext::abs(m_S.coeff(res - 1, res - 1)) + numext::abs(m_S.coeff(res, res));
695 if (s == Scalar(0)) s = m_normOfS;
696 if (numext::abs(m_S.coeff(res, res - 1)) < NumTraits<RealScalar>::epsilon() * s)
break;
704template <
typename MatrixType_>
708 if (numext::abs(m_T.coeff(res, res)) <= NumTraits<RealScalar>::epsilon() * m_normOfT)
break;
Performs a QZ decomposition of a pair of matrices A, B.
Rotation given by a cosine-sine pair.
Definition Jacobi.h:39
JacobiRotation adjoint() const
Definition Jacobi.h:68
void makeGivens(const Scalar &p, const Scalar &q, Scalar *r=0)
Definition Jacobi.h:165
HouseholderSequence< VectorsType, CoeffsType > householderSequence(const VectorsType &v, const CoeffsType &h)
Convenience function for constructing a Householder sequence.
Definition HouseholderSequence.h:673
@ NumericalIssue
Definition Constants.h:459
@ InvalidInput
Definition Constants.h:464
@ Success
Definition Constants.h:457
@ NoConvergence
Definition Constants.h:461
Matrix< int, 3, 1 > Vector3i
3×1 vector of type int.
Definition Matrix.h:487