Eigen  5.0.1
 
Loading...
Searching...
No Matches
RealSchur.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5// Copyright (C) 2010,2012 Jitse Niesen <jitse@maths.leeds.ac.uk>
6//
7// This Source Code Form is subject to the terms of the Mozilla
8// Public License v. 2.0. If a copy of the MPL was not distributed
9// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10// SPDX-License-Identifier: MPL-2.0
11
12#ifndef EIGEN_REAL_SCHUR_H
13#define EIGEN_REAL_SCHUR_H
14
15#include "./HessenbergDecomposition.h"
16
17// IWYU pragma: private
18#include "./InternalHeaderCheck.h"
19
20namespace Eigen {
21
22template <typename MatrixType_>
23class EigenSolver;
24
61template <typename MatrixType_>
62class RealSchur {
63 public:
64 using MatrixType = MatrixType_;
65 enum {
66 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
67 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
68 Options = internal::plain_object_options<MatrixType>::value,
69 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
70 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
71 };
72 using Scalar = typename MatrixType::Scalar;
73 using ComplexScalar = internal::make_complex_t<Scalar>;
74 using Index = Eigen::Index;
75
78
83
95 explicit RealSchur(Index size = RowsAtCompileTime == Dynamic ? 1 : RowsAtCompileTime)
96 : m_matT(size, size),
97 m_matU(size, size),
98 m_workspaceVector(size),
99 m_isInitialized(false),
100 m_matUisUptodate(false),
101 m_maxIters(-1) {
102 if (size > 1) m_hCoeffs.resize(size - 1);
103 }
104
115 template <typename InputType>
116 explicit RealSchur(const EigenBase<InputType>& matrix, bool computeU = true)
117 : m_matT(matrix.rows(), matrix.cols()),
118 m_matU(matrix.rows(), matrix.cols()),
119 m_workspaceVector(matrix.rows()),
120 m_isInitialized(false),
121 m_matUisUptodate(false),
122 m_maxIters(-1) {
123 compute(matrix.derived(), computeU);
124 }
125
143 template <typename InputType, bool IsRef = internal::is_ref<MatrixType>::value, std::enable_if_t<IsRef, int> = 0>
144 explicit RealSchur(EigenBase<InputType>& matrix, bool computeU = true)
145 : m_matT(matrix.derived()),
146 m_matU(matrix.rows(), matrix.cols()),
147 m_workspaceVector(matrix.rows()),
148 m_isInitialized(false),
149 m_matUisUptodate(false),
150 m_maxIters(-1) {
151 compute(m_matT, computeU);
152 }
153
165 const MatrixUType& matrixU() const {
166 eigen_assert(m_isInitialized && "RealSchur is not initialized.");
167 eigen_assert(m_matUisUptodate && "The matrix U has not been computed during the RealSchur decomposition.");
168 return m_matU;
169 }
170
181 const MatrixType& matrixT() const {
182 eigen_assert(m_isInitialized && "RealSchur is not initialized.");
183 return m_matT;
184 }
185
210 template <typename InputType>
211 RealSchur& compute(const EigenBase<InputType>& matrix, bool computeU = true);
212
235 template <typename HessMatrixType, typename OrthMatrixType>
236 RealSchur& computeFromHessenberg(const HessMatrixType& matrixH, const OrthMatrixType& matrixQ, bool computeU);
242 eigen_assert(m_isInitialized && "RealSchur is not initialized.");
243 return m_info;
244 }
245
252 m_maxIters = maxIters;
253 return *this;
254 }
255
257 Index getMaxIterations() const { return m_maxIters; }
258
264 static const int m_maxIterationsPerRow = 40;
265
266 private:
267 // EigenSolver computes the eigenvectors of T and back-transforms U within this storage.
268 friend class EigenSolver<MatrixType>;
269
270 using CoeffVectorType =
271 Matrix<Scalar, RowsAtCompileTime == Dynamic ? Dynamic : RowsAtCompileTime - 1, 1, Options & ~RowMajor,
272 MaxRowsAtCompileTime == Dynamic ? Dynamic : MaxRowsAtCompileTime - 1, 1>;
273
274 MatrixType m_matT;
275 MatrixUType m_matU;
276 ColumnVectorType m_workspaceVector;
277 CoeffVectorType m_hCoeffs;
278 ComputationInfo m_info;
279 bool m_isInitialized;
280 bool m_matUisUptodate;
281 Index m_maxIters;
282
283 template <typename TMatrix>
284 EIGEN_DONT_INLINE RealSchur& computeFromHessenbergInPlace(TMatrix& matT, bool computeU);
285 using Vector3s = Matrix<Scalar, 3, 1>;
286
288
289 bool usePaddedWorkspace(Index size) const;
290 template <typename TMatrix>
291 RealSchur& computeInPlace(TMatrix& matT, bool computeU);
292 template <typename TMatrix>
293 Scalar computeNormOfT(TMatrix& matT);
294 template <typename TMatrix>
295 Index findSmallSubdiagEntry(TMatrix& matT, Index iu, const Scalar& considerAsZero);
296 template <typename TMatrix>
297 void splitOffTwoRows(TMatrix& matT, Index iu, bool computeU, const Scalar& exshift);
298 template <typename TMatrix>
299 void computeShift(TMatrix& matT, Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo);
300 template <typename TMatrix>
301 void initFrancisQRStep(TMatrix& matT, Index il, Index iu, const Vector3s& shiftInfo, Index& im,
302 Vector3s& firstHouseholderVector);
303 template <typename TMatrix>
304 void performFrancisQRStep(TMatrix& matT, Index il, Index im, Index iu, bool computeU,
305 const Vector3s& firstHouseholderVector, Scalar* workspace);
306};
307
308template <typename MatrixType>
309template <typename InputType>
311 eigen_assert(matrix.cols() == matrix.rows());
312 const Index size = matrix.rows();
313 if (usePaddedWorkspace(size)) {
314 WorkspaceMatrix storage(size + (MatrixType::IsRowMajor ? 0 : 1), size + (MatrixType::IsRowMajor ? 1 : 0));
315 auto matT = storage.topLeftCorner(size, size);
316 matT = matrix.derived();
317 computeInPlace(matT, computeU);
318 } else {
319 if (!internal::is_same_dense(m_matT, matrix.derived())) m_matT = matrix.derived();
320 computeInPlace(m_matT, computeU);
321 }
322 return *this;
323}
324
325template <typename MatrixType>
326bool RealSchur<MatrixType>::usePaddedWorkspace(Index size) const {
327 // Short reflectors traverse the outer dimension. Strides divisible by 1 KiB concentrate those accesses in
328 // very few cache sets. A Ref may already have a suitable stride; owning matrices resize to size-by-size.
329 const Index stride = internal::is_ref<MatrixType>::value ? m_matT.outerStride() : size;
330 bool usePadding = size >= 128 && (stride * sizeof(Scalar)) % 1024 == 0;
331#ifdef EIGEN_NO_MALLOC
332 usePadding = false;
333#elif defined(EIGEN_RUNTIME_NO_MALLOC)
334 usePadding = usePadding && internal::is_malloc_allowed() && internal::is_free_allowed();
335#endif
336 return usePadding;
337}
338
340template <typename MatrixType>
341template <typename TMatrix>
342RealSchur<MatrixType>& RealSchur<MatrixType>::computeInPlace(TMatrix& matT, bool computeU) {
343 const Scalar considerAsZero = (std::numeric_limits<Scalar>::min)();
344 const Index n = matT.rows();
345 eigen_assert(matT.cols() == n);
346
347 const Scalar maxCoeff = n == 0 ? Scalar(0) : matT.cwiseAbs().template maxCoeff<PropagateNaN>();
348 if (!(numext::isfinite)(maxCoeff)) {
349 if (!internal::is_same_dense(m_matT, matT)) m_matT = matT;
350 m_info = NoConvergence;
351 m_isInitialized = true;
352 m_matUisUptodate = false;
353 return *this;
354 }
355 if (maxCoeff < considerAsZero) {
356 // Ref has no setZero(rows, cols) overload.
357 m_matT.resize(n, n);
358 m_matT.setZero();
359 if (computeU) m_matU.setIdentity(n, n);
360 m_info = Success;
361 m_isInitialized = true;
362 m_matUisUptodate = computeU;
363 return *this;
364 }
365 const auto factors = internal::safe_scaling<Scalar>::scale_in_place(matT, maxCoeff);
366
367 // Step 1. Reduce to Hessenberg form
368 internal::hessenberg_decomposition_inplace(matT, m_hCoeffs, m_workspaceVector, m_matU, computeU);
369
370 // Step 2. Reduce to real Schur form
371 computeFromHessenbergInPlace(matT, computeU);
372
373 // Keep aliasing explicit for the compiler on the in-place path.
374 if (internal::is_same_dense(m_matT, matT))
375 internal::safe_scaling<Scalar>::unscale_in_place(matT, maxCoeff, factors);
376 else
377 internal::safe_scaling<Scalar>::unscale_to(m_matT, matT, maxCoeff, factors);
378
379 return *this;
380}
381template <typename MatrixType>
382template <typename HessMatrixType, typename OrthMatrixType>
384 const OrthMatrixType& matrixQ, bool computeU) {
385 const Index size = matrixH.rows();
386 m_workspaceVector.resize(size);
387 if (usePaddedWorkspace(size)) {
388 WorkspaceMatrix storage(size + (MatrixType::IsRowMajor ? 0 : 1), size + (MatrixType::IsRowMajor ? 1 : 0));
389 auto matT = storage.topLeftCorner(size, size);
390 matT = matrixH;
391 if (computeU && !internal::is_same_dense(m_matU, matrixQ)) m_matU = matrixQ;
392 computeFromHessenbergInPlace(matT, computeU);
393 m_matT = matT;
394 } else {
395 if (!internal::is_same_dense(m_matT, matrixH)) m_matT = matrixH;
396 if (computeU && !internal::is_same_dense(m_matU, matrixQ)) m_matU = matrixQ;
397 computeFromHessenbergInPlace(m_matT, computeU);
398 }
399 return *this;
400}
401
402template <typename MatrixType>
403template <typename TMatrix>
404RealSchur<MatrixType>& RealSchur<MatrixType>::computeFromHessenbergInPlace(TMatrix& matT, bool computeU) {
405 Index maxIters = m_maxIters;
406 if (maxIters == -1) maxIters = m_maxIterationsPerRow * matT.rows();
407 Scalar* workspace = &m_workspaceVector.coeffRef(0);
408
409 // The matrix matT is divided in three parts.
410 // Rows 0,...,il-1 are decoupled from the rest because matT(il,il-1) is zero.
411 // Rows il,...,iu is the part we are working on (the active window).
412 // Rows iu+1,...,end are already brought in triangular form.
413 Index iu = matT.cols() - 1;
414 Index iter = 0; // iteration count for current eigenvalue
415 Index totalIter = 0; // iteration count for whole matrix
416 Scalar exshift(0); // sum of exceptional shifts
417 Scalar norm = computeNormOfT(matT);
418 // sub-diagonal entries smaller than considerAsZero will be treated as zero.
419 // We use eps^2 to enable more precision in small eigenvalues.
420 Scalar considerAsZero =
421 numext::maxi<Scalar>(norm * numext::abs2(NumTraits<Scalar>::epsilon()), (std::numeric_limits<Scalar>::min)());
422
423 if (!numext::is_exactly_zero(norm)) {
424 while (iu >= 0) {
425 Index il = findSmallSubdiagEntry(matT, iu, considerAsZero);
426
427 // Check for convergence
428 if (il == iu) // One root found
429 {
430 matT.coeffRef(iu, iu) = matT.coeff(iu, iu) + exshift;
431 if (iu > 0) matT.coeffRef(iu, iu - 1) = Scalar(0);
432 iu--;
433 iter = 0;
434 } else if (il == iu - 1) // Two roots found
435 {
436 splitOffTwoRows(matT, iu, computeU, exshift);
437 iu -= 2;
438 iter = 0;
439 } else // No convergence yet
440 {
441 // The firstHouseholderVector vector has to be initialized to something to get rid of a silly GCC warning (-O1
442 // -Wall -DNDEBUG )
443 Vector3s firstHouseholderVector = Vector3s::Zero(), shiftInfo;
444 computeShift(matT, iu, iter, exshift, shiftInfo);
445 iter = iter + 1;
446 totalIter = totalIter + 1;
447 if (totalIter > maxIters) break;
448 Index im;
449 initFrancisQRStep(matT, il, iu, shiftInfo, im, firstHouseholderVector);
450 performFrancisQRStep(matT, il, im, iu, computeU, firstHouseholderVector, workspace);
451 }
452 }
453 }
454 if (totalIter <= maxIters)
455 m_info = Success;
456 else
457 m_info = NoConvergence;
458
459 m_isInitialized = true;
460 m_matUisUptodate = computeU;
461 return *this;
462}
463
465template <typename MatrixType>
466template <typename TMatrix>
467inline typename MatrixType::Scalar RealSchur<MatrixType>::computeNormOfT(TMatrix& matT) {
468 return internal::hessenberg_abs_sum<Upper>(matT);
469}
470
472template <typename MatrixType>
473template <typename TMatrix>
474inline Index RealSchur<MatrixType>::findSmallSubdiagEntry(TMatrix& matT, Index iu, const Scalar& considerAsZero) {
475 using std::abs;
476 Index res = iu;
477 while (res > 0) {
478 Scalar s = abs(matT.coeff(res - 1, res - 1)) + abs(matT.coeff(res, res));
479
480 s = numext::maxi<Scalar>(s * NumTraits<Scalar>::epsilon(), considerAsZero);
481
482 if (abs(matT.coeff(res, res - 1)) <= s) break;
483 res--;
484 }
485 return res;
486}
487
489template <typename MatrixType>
490template <typename TMatrix>
491inline void RealSchur<MatrixType>::splitOffTwoRows(TMatrix& matT, Index iu, bool computeU, const Scalar& exshift) {
492 using std::abs;
493 using std::sqrt;
494 const Index size = matT.cols();
495
496 // The eigenvalues of the 2x2 matrix [a b; c d] are
497 // trace +/- sqrt(discr/4) where discr = tr^2 - 4*det, tr = a + d, det = ad - bc
498 Scalar p = Scalar(0.5) * (matT.coeff(iu - 1, iu - 1) - matT.coeff(iu, iu));
499 Scalar q = p * p + matT.coeff(iu, iu - 1) * matT.coeff(iu - 1, iu); // q = tr^2 / 4 - det = discr/4
500 matT.coeffRef(iu, iu) += exshift;
501 matT.coeffRef(iu - 1, iu - 1) += exshift;
502
503 if (q >= Scalar(0)) // Two real eigenvalues
504 {
505 Scalar z = sqrt(abs(q));
507 if (p >= Scalar(0))
508 rot.makeGivens(p + z, matT.coeff(iu, iu - 1));
509 else
510 rot.makeGivens(p - z, matT.coeff(iu, iu - 1));
511
512 matT.rightCols(size - iu + 1).applyOnTheLeft(iu - 1, iu, rot.adjoint());
513 matT.topRows(iu + 1).applyOnTheRight(iu - 1, iu, rot);
514 matT.coeffRef(iu, iu - 1) = Scalar(0);
515 if (computeU) m_matU.applyOnTheRight(iu - 1, iu, rot);
516 }
517
518 if (iu > 1) matT.coeffRef(iu - 1, iu - 2) = Scalar(0);
519}
520
522template <typename MatrixType>
523template <typename TMatrix>
524inline void RealSchur<MatrixType>::computeShift(TMatrix& matT, Index iu, Index iter, Scalar& exshift,
525 Vector3s& shiftInfo) {
526 using std::abs;
527 using std::sqrt;
528 shiftInfo.coeffRef(0) = matT.coeff(iu, iu);
529 shiftInfo.coeffRef(1) = matT.coeff(iu - 1, iu - 1);
530 shiftInfo.coeffRef(2) = matT.coeff(iu, iu - 1) * matT.coeff(iu - 1, iu);
531
532 // Alternate exceptional shifting strategy every 16 iterations.
533 if (iter > 0 && iter % 16 == 0) {
534 // Wilkinson's original ad hoc shift
535 if (iter % 32 != 0) {
536 exshift += shiftInfo.coeff(0);
537 matT.diagonal().head(iu + 1).array() -= shiftInfo.coeff(0);
538 Scalar s = abs(matT.coeff(iu, iu - 1)) + abs(matT.coeff(iu - 1, iu - 2));
539 shiftInfo.coeffRef(0) = Scalar(0.75) * s;
540 shiftInfo.coeffRef(1) = Scalar(0.75) * s;
541 shiftInfo.coeffRef(2) = Scalar(-0.4375) * s * s;
542 } else {
543 // MATLAB's new ad hoc shift
544 Scalar s = (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
545 s = s * s + shiftInfo.coeff(2);
546 if (s > Scalar(0)) {
547 s = sqrt(s);
548 if (shiftInfo.coeff(1) < shiftInfo.coeff(0)) s = -s;
549 s = s + (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
550 s = shiftInfo.coeff(0) - shiftInfo.coeff(2) / s;
551 exshift += s;
552 matT.diagonal().head(iu + 1).array() -= s;
553 shiftInfo.setConstant(Scalar(0.964));
554 }
555 }
556 }
557}
558
560template <typename MatrixType>
561template <typename TMatrix>
562inline void RealSchur<MatrixType>::initFrancisQRStep(TMatrix& matT, Index il, Index iu, const Vector3s& shiftInfo,
563 Index& im, Vector3s& firstHouseholderVector) {
564 using std::abs;
565 Vector3s& v = firstHouseholderVector; // alias to save typing
566
567 for (im = iu - 2; im >= il; --im) {
568 const Scalar Tmm = matT.coeff(im, im);
569 const Scalar r = shiftInfo.coeff(0) - Tmm;
570 const Scalar s = shiftInfo.coeff(1) - Tmm;
571 v.coeffRef(0) = (r * s - shiftInfo.coeff(2)) / matT.coeff(im + 1, im) + matT.coeff(im, im + 1);
572 v.coeffRef(1) = matT.coeff(im + 1, im + 1) - Tmm - r - s;
573 v.coeffRef(2) = matT.coeff(im + 2, im + 1);
574 if (im == il) {
575 break;
576 }
577 const Scalar lhs = matT.coeff(im, im - 1) * (abs(v.coeff(1)) + abs(v.coeff(2)));
578 const Scalar rhs = v.coeff(0) * (abs(matT.coeff(im - 1, im - 1)) + abs(Tmm) + abs(matT.coeff(im + 1, im + 1)));
579 if (abs(lhs) < NumTraits<Scalar>::epsilon() * rhs) break;
580 }
581}
582
584template <typename MatrixType>
585template <typename TMatrix>
586inline void RealSchur<MatrixType>::performFrancisQRStep(TMatrix& matT, Index il, Index im, Index iu, bool computeU,
587 const Vector3s& firstHouseholderVector, Scalar* workspace) {
588 eigen_assert(im >= il);
589 eigen_assert(im <= iu - 2);
590
591 const Index size = matT.cols();
592
593 // Reflectors are chased in windows k0 <= k < k1 of at most WindowSize. Reflector k reads column k - 1 and its
594 // right-hand update reaches column k + 2, so only columns < k1 + 2 feed later reflectors of the window. The left
595 // updates of the columns beyond are deferred to the window's end and applied column by column in the original
596 // order: the same arithmetic, on contiguous segments instead of one strided three-row pass per reflector.
597 constexpr Index WindowSize = 32;
598 constexpr bool deferLeft = !TMatrix::IsRowMajor && int(TMatrix::InnerStrideAtCompileTime) == 1;
599 Index windowK[WindowSize];
600 Scalar windowTau[WindowSize];
601 Matrix<Scalar, 2, 1> windowEss[WindowSize];
602
603 for (Index k0 = im; k0 <= iu - 2; k0 += WindowSize) {
604 const Index k1 = (std::min)(k0 + WindowSize, iu - 1);
605 const Index nearEnd = deferLeft ? (std::min)(size, k1 + 2) : size;
606 Index numDeferred = 0;
607 for (Index k = k0; k < k1; ++k) {
608 bool firstIteration = (k == im);
609
610 Vector3s v;
611 if (firstIteration)
612 v = firstHouseholderVector;
613 else
614 v = matT.template block<3, 1>(k, k - 1);
615
616 Scalar tau, beta;
618 v.makeHouseholder(ess, tau, beta);
619
620 if (!numext::is_exactly_zero(beta)) // if v is not zero
621 {
622 if (firstIteration && k > il)
623 matT.coeffRef(k, k - 1) = -matT.coeff(k, k - 1);
624 else if (!firstIteration)
625 matT.coeffRef(k, k - 1) = beta;
626
627 // These Householder transformations form the O(n^3) part of the algorithm
628 matT.block(k, k, 3, nearEnd - k).applyHouseholderOnTheLeft(ess, tau, workspace);
629 matT.block(0, k, (std::min)(iu, k + 3) + 1, 3).applyHouseholderOnTheRight(ess, tau, workspace);
630 if (computeU) m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace);
631 // A zero tau is the identity, which the immediate path skips; applying it would turn -0 into +0 and Inf
632 // into NaN.
633 if (nearEnd < size && !numext::is_exactly_zero(tau)) {
634 windowK[numDeferred] = k;
635 windowTau[numDeferred] = tau;
636 windowEss[numDeferred] = ess;
637 ++numDeferred;
638 }
639 }
640 }
641 // Groups of columns give independent dependency chains: within one column, each update reads two entries the
642 // previous one wrote.
643 constexpr Index ColumnGroup = 16;
644 for (Index j0 = nearEnd; j0 < size && numDeferred > 0; j0 += ColumnGroup) {
645 const Index j1 = (std::min)(j0 + ColumnGroup, size);
646 for (Index r = 0; r < numDeferred; ++r) {
647 const Index k = windowK[r];
648 const Scalar e0 = windowEss[r].coeff(0), e1 = windowEss[r].coeff(1), tau = windowTau[r];
649 for (Index j = j0; j < j1; ++j) {
650 // Column-major with unit inner stride: rows k, k + 1, k + 2 of column j are consecutive.
651 Scalar* x = &matT.coeffRef(k, j);
652 const Scalar tmp = tau * ((e0 * x[1] + e1 * x[2]) + x[0]);
653 x[0] -= tmp;
654 x[1] -= e0 * tmp;
655 x[2] -= e1 * tmp;
656 }
657 }
658 }
659 }
660
661 Matrix<Scalar, 2, 1> v = matT.template block<2, 1>(iu - 1, iu - 2);
662 Scalar tau, beta;
664 v.makeHouseholder(ess, tau, beta);
665
666 if (!numext::is_exactly_zero(beta)) // if v is not zero
667 {
668 matT.coeffRef(iu - 1, iu - 2) = beta;
669 matT.block(iu - 1, iu - 1, 2, size - iu + 1).applyHouseholderOnTheLeft(ess, tau, workspace);
670 matT.block(0, iu - 1, iu + 1, 2).applyHouseholderOnTheRight(ess, tau, workspace);
671 if (computeU) m_matU.block(0, iu - 1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace);
672 }
673
674 // clean up pollution due to round-off errors
675 for (Index i = im + 2; i <= iu; ++i) {
676 matT.coeffRef(i, i - 2) = Scalar(0);
677 if (i > im + 2) matT.coeffRef(i, i - 3) = Scalar(0);
678 }
679}
680
681} // end namespace Eigen
682
683#endif // EIGEN_REAL_SCHUR_H
Computes eigenvalues and eigenvectors of general matrices.
Definition EigenSolver.h:69
Rotation given by a cosine-sine pair.
Definition Jacobi.h:39
void makeGivens(const Scalar &p, const Scalar &q, Scalar *r=0)
Definition Jacobi.h:165
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
Performs a real Schur decomposition of a square matrix.
Definition RealSchur.h:62
Matrix< Scalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime > MatrixUType
Type of the matrix returned by matrixU(): a plain matrix with the shape and storage options of Matrix...
Definition RealSchur.h:81
ComputationInfo info() const
Reports whether previous computation was successful.
Definition RealSchur.h:241
Eigen::Index Index
Definition RealSchur.h:74
RealSchur(Index size=RowsAtCompileTime==Dynamic ? 1 :RowsAtCompileTime)
Default constructor.
Definition RealSchur.h:95
RealSchur(EigenBase< InputType > &matrix, bool computeU=true)
Constructor for inplace decomposition .
Definition RealSchur.h:144
RealSchur(const EigenBase< InputType > &matrix, bool computeU=true)
Constructor; computes real Schur decomposition of given matrix.
Definition RealSchur.h:116
static const int m_maxIterationsPerRow
Maximum number of iterations per row.
Definition RealSchur.h:264
RealSchur & compute(const EigenBase< InputType > &matrix, bool computeU=true)
Computes Schur decomposition of given matrix.
Index getMaxIterations() const
Returns the maximum number of iterations.
Definition RealSchur.h:257
RealSchur & setMaxIterations(Index maxIters)
Sets the maximum number of iterations allowed.
Definition RealSchur.h:251
RealSchur & computeFromHessenberg(const HessMatrixType &matrixH, const OrthMatrixType &matrixQ, bool computeU)
Computes Schur decomposition of a Hessenberg matrix H = Z T Z^T.
const MatrixUType & matrixU() const
Returns the orthogonal matrix in the Schur decomposition.
Definition RealSchur.h:165
const MatrixType & matrixT() const
Returns the quasi-triangular matrix in the Schur decomposition.
Definition RealSchur.h:181
ComputationInfo
Definition Constants.h:455
@ PropagateNaN
Definition Constants.h:343
@ Success
Definition Constants.h:457
@ NoConvergence
Definition Constants.h:461
@ RowMajor
Definition Constants.h:321
Definition EigenBase.h:34
constexpr Index cols() const noexcept
Definition EigenBase.h:62
constexpr Derived & derived()
Definition EigenBase.h:50
constexpr Index rows() const noexcept
Definition EigenBase.h:60