$darkmode
Eigen  5.0.1-dev
SelfAdjointEigenSolver.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2010 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 
11 #ifndef EIGEN_SELFADJOINTEIGENSOLVER_H
12 #define EIGEN_SELFADJOINTEIGENSOLVER_H
13 
14 #include "./Tridiagonalization.h"
15 
16 // IWYU pragma: private
17 #include "./InternalHeaderCheck.h"
18 
19 namespace Eigen {
20 
21 template <typename MatrixType_>
22 class GeneralizedSelfAdjointEigenSolver;
23 
24 namespace internal {
25 template <typename SolverType, int Size, bool IsComplex>
26 struct direct_selfadjoint_eigenvalues;
27 
28 template <typename MatrixType, typename DiagType, typename SubDiagType>
29 EIGEN_DEVICE_FUNC ComputationInfo computeFromTridiagonal_impl(DiagType& diag, SubDiagType& subdiag,
30  const Index maxIterations, bool computeEigenvectors,
31  MatrixType& eivec);
32 } // namespace internal
33 
81 template <typename MatrixType_>
83  public:
84  typedef MatrixType_ MatrixType;
85  enum {
86  Size = MatrixType::RowsAtCompileTime,
87  ColsAtCompileTime = MatrixType::ColsAtCompileTime,
88  Options = internal::traits<MatrixType>::Options,
89  MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
90  };
91 
93  typedef typename MatrixType::Scalar Scalar;
94  typedef Eigen::Index Index;
95 
97 
105 
106  friend struct internal::direct_selfadjoint_eigenvalues<SelfAdjointEigenSolver, Size, NumTraits<Scalar>::IsComplex>;
107 
113  typedef typename internal::plain_col_type<MatrixType, Scalar>::type VectorType;
114  typedef typename internal::plain_col_type<MatrixType, RealScalar>::type RealVectorType;
115  typedef Tridiagonalization<MatrixType> TridiagonalizationType;
117 
128  EIGEN_DEVICE_FUNC SelfAdjointEigenSolver()
129  : m_eivec(),
130  m_workspace(),
131  m_eivalues(),
132  m_subdiag(),
133  m_hcoeffs(),
134  m_info(InvalidInput),
135  m_isInitialized(false),
136  m_eigenvectorsOk(false) {}
137 
150  EIGEN_DEVICE_FUNC explicit SelfAdjointEigenSolver(Index size)
151  : m_eivec(size, size),
152  m_workspace(size),
153  m_eivalues(size),
154  m_subdiag(size > 1 ? size - 1 : 1),
155  m_hcoeffs(size > 1 ? size - 1 : 1),
156  m_isInitialized(false),
157  m_eigenvectorsOk(false) {}
158 
174  template <typename InputType>
175  EIGEN_DEVICE_FUNC explicit SelfAdjointEigenSolver(const EigenBase<InputType>& matrix,
176  int options = ComputeEigenvectors)
177  : m_eivec(matrix.rows(), matrix.cols()),
178  m_workspace(matrix.cols()),
179  m_eivalues(matrix.cols()),
180  m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1),
181  m_hcoeffs(matrix.cols() > 1 ? matrix.cols() - 1 : 1),
182  m_isInitialized(false),
183  m_eigenvectorsOk(false) {
184  compute(matrix.derived(), options);
185  }
186 
217  template <typename InputType>
218  EIGEN_DEVICE_FUNC SelfAdjointEigenSolver& compute(const EigenBase<InputType>& matrix,
219  int options = ComputeEigenvectors);
220 
239  EIGEN_DEVICE_FUNC SelfAdjointEigenSolver& computeDirect(const MatrixType& matrix, int options = ComputeEigenvectors);
240 
253  SelfAdjointEigenSolver& computeFromTridiagonal(const RealVectorType& diag, const SubDiagonalType& subdiag,
254  int options = ComputeEigenvectors);
255 
279  EIGEN_DEVICE_FUNC const EigenvectorsType& eigenvectors() const {
280  eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
281  eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
282  return m_eivec;
283  }
284 
300  EIGEN_DEVICE_FUNC const RealVectorType& eigenvalues() const {
301  eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
302  return m_eivalues;
303  }
304 
322  EIGEN_DEVICE_FUNC MatrixType operatorSqrt() const {
323  eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
324  eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
325  return m_eivec * m_eivalues.cwiseSqrt().asDiagonal() * m_eivec.adjoint();
326  }
327 
346  EIGEN_DEVICE_FUNC MatrixType operatorInverseSqrt() const {
347  eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
348  eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
349  return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint();
350  }
351 
356  EIGEN_DEVICE_FUNC ComputationInfo info() const {
357  eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
358  return m_info;
359  }
360 
366  static const int m_maxIterations = 30;
367 
368  protected:
369  EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
370 
371  EigenvectorsType m_eivec;
372  VectorType m_workspace;
373  RealVectorType m_eivalues;
374  typename TridiagonalizationType::SubDiagonalType m_subdiag;
375  typename TridiagonalizationType::CoeffVectorType m_hcoeffs;
376  ComputationInfo m_info;
377  bool m_isInitialized;
378  bool m_eigenvectorsOk;
379 };
380 
381 namespace internal {
402 template <int StorageOrder, typename RealScalar, typename Scalar, typename Index>
403 EIGEN_DEVICE_FUNC static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end,
404  Scalar* matrixQ, Index n);
405 } // namespace internal
406 
407 template <typename MatrixType>
408 template <typename InputType>
409 EIGEN_DEVICE_FUNC SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::compute(
410  const EigenBase<InputType>& a_matrix, int options) {
411  const InputType& matrix(a_matrix.derived());
412 
413  EIGEN_USING_STD(abs);
414  eigen_assert(matrix.cols() == matrix.rows());
415  eigen_assert((options & ~(EigVecMask | GenEigMask)) == 0 && (options & EigVecMask) != EigVecMask &&
416  "invalid option parameter");
417  bool computeEigenvectors = (options & ComputeEigenvectors) == ComputeEigenvectors;
418  Index n = matrix.cols();
419  m_eivalues.resize(n, 1);
420 
421  if (n == 1) {
422  m_eivec = matrix;
423  m_eivalues.coeffRef(0, 0) = numext::real(m_eivec.coeff(0, 0));
424  if (computeEigenvectors) m_eivec.setOnes(n, n);
425  m_info = Success;
426  m_isInitialized = true;
427  m_eigenvectorsOk = computeEigenvectors;
428  return *this;
429  }
430 
431  // declare some aliases
432  RealVectorType& diag = m_eivalues;
433  EigenvectorsType& mat = m_eivec;
434 
435  // map the matrix coefficients to [-1:1] to avoid over- and underflow.
436  mat = matrix.template triangularView<Lower>();
437  RealScalar scale = mat.cwiseAbs().maxCoeff();
438  if (numext::is_exactly_zero(scale)) scale = RealScalar(1);
439  mat.template triangularView<Lower>() /= scale;
440  m_subdiag.resize(n - 1);
441  m_hcoeffs.resize(n - 1);
442  internal::tridiagonalization_inplace(mat, diag, m_subdiag, m_hcoeffs, m_workspace, computeEigenvectors);
443 
444  m_info = internal::computeFromTridiagonal_impl(diag, m_subdiag, m_maxIterations, computeEigenvectors, m_eivec);
445 
446  // scale back the eigen values
447  m_eivalues *= scale;
448 
449  m_isInitialized = true;
450  m_eigenvectorsOk = computeEigenvectors;
451  return *this;
452 }
453 
454 template <typename MatrixType>
456  const RealVectorType& diag, const SubDiagonalType& subdiag, int options) {
457  // TODO : Add an option to scale the values beforehand
458  bool computeEigenvectors = (options & ComputeEigenvectors) == ComputeEigenvectors;
459 
460  m_eivalues = diag;
461  m_subdiag = subdiag;
462  if (computeEigenvectors) {
463  m_eivec.setIdentity(diag.size(), diag.size());
464  }
465  m_info = internal::computeFromTridiagonal_impl(m_eivalues, m_subdiag, m_maxIterations, computeEigenvectors, m_eivec);
466 
467  m_isInitialized = true;
468  m_eigenvectorsOk = computeEigenvectors;
469  return *this;
470 }
471 
472 namespace internal {
484 template <typename MatrixType, typename DiagType, typename SubDiagType>
485 EIGEN_DEVICE_FUNC ComputationInfo computeFromTridiagonal_impl(DiagType& diag, SubDiagType& subdiag,
486  const Index maxIterations, bool computeEigenvectors,
487  MatrixType& eivec) {
488  ComputationInfo info;
489  typedef typename MatrixType::Scalar Scalar;
490 
491  Index n = diag.size();
492  Index end = n - 1;
493  Index start = 0;
494  Index iter = 0; // total number of iterations
495 
496  typedef typename DiagType::RealScalar RealScalar;
497  const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
498  const RealScalar precision_inv = RealScalar(1) / NumTraits<RealScalar>::epsilon();
499  while (end > 0) {
500  for (Index i = start; i < end; ++i) {
501  if (numext::abs(subdiag[i]) < considerAsZero) {
502  subdiag[i] = RealScalar(0);
503  } else {
504  // abs(subdiag[i]) <= epsilon * sqrt(abs(diag[i]) + abs(diag[i+1]))
505  // Scaled to prevent underflows.
506  const RealScalar scaled_subdiag = precision_inv * subdiag[i];
507  if (scaled_subdiag * scaled_subdiag <= (numext::abs(diag[i]) + numext::abs(diag[i + 1]))) {
508  subdiag[i] = RealScalar(0);
509  }
510  }
511  }
512 
513  // find the largest unreduced block at the end of the matrix.
514  while (end > 0 && numext::is_exactly_zero(subdiag[end - 1])) {
515  end--;
516  }
517  if (end <= 0) break;
518 
519  // if we spent too many iterations, we give up
520  iter++;
521  if (iter > maxIterations * n) break;
522 
523  start = end - 1;
524  while (start > 0 && !numext::is_exactly_zero(subdiag[start - 1])) start--;
525 
526  internal::tridiagonal_qr_step<MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor>(
527  diag.data(), subdiag.data(), start, end, computeEigenvectors ? eivec.data() : (Scalar*)0, n);
528  }
529  if (iter <= maxIterations * n)
530  info = Success;
531  else
532  info = NoConvergence;
533 
534  // Sort eigenvalues and corresponding vectors.
535  // TODO make the sort optional ?
536  // TODO use a better sort algorithm !!
537  if (info == Success) {
538  for (Index i = 0; i < n - 1; ++i) {
539  Index k;
540  diag.segment(i, n - i).minCoeff(&k);
541  if (k > 0) {
542  numext::swap(diag[i], diag[k + i]);
543  if (computeEigenvectors) eivec.col(i).swap(eivec.col(k + i));
544  }
545  }
546  }
547  return info;
548 }
549 
550 template <typename SolverType, int Size, bool IsComplex>
551 struct direct_selfadjoint_eigenvalues {
552  EIGEN_DEVICE_FUNC static inline void run(SolverType& eig, const typename SolverType::MatrixType& A, int options) {
553  eig.compute(A, options);
554  }
555 };
556 
557 template <typename SolverType>
558 struct direct_selfadjoint_eigenvalues<SolverType, 3, false> {
559  typedef typename SolverType::MatrixType MatrixType;
560  typedef typename SolverType::RealVectorType VectorType;
561  typedef typename SolverType::Scalar Scalar;
562  typedef typename SolverType::EigenvectorsType EigenvectorsType;
563 
568  EIGEN_DEVICE_FUNC static inline void computeRoots(const MatrixType& m, VectorType& roots) {
569  EIGEN_USING_STD(sqrt)
570  EIGEN_USING_STD(atan2)
571  EIGEN_USING_STD(cos)
572  EIGEN_USING_STD(sin)
573  const Scalar s_inv3 = Scalar(1) / Scalar(3);
574  const Scalar s_sqrt3 = sqrt(Scalar(3));
575 
576  // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The
577  // eigenvalues are the roots to this equation, all guaranteed to be
578  // real-valued, because the matrix is symmetric.
579  Scalar c0 = m(0, 0) * m(1, 1) * m(2, 2) + Scalar(2) * m(1, 0) * m(2, 0) * m(2, 1) - m(0, 0) * m(2, 1) * m(2, 1) -
580  m(1, 1) * m(2, 0) * m(2, 0) - m(2, 2) * m(1, 0) * m(1, 0);
581  Scalar c1 = m(0, 0) * m(1, 1) - m(1, 0) * m(1, 0) + m(0, 0) * m(2, 2) - m(2, 0) * m(2, 0) + m(1, 1) * m(2, 2) -
582  m(2, 1) * m(2, 1);
583  Scalar c2 = m(0, 0) + m(1, 1) + m(2, 2);
584 
585  // Construct the parameters used in classifying the roots of the equation
586  // and in solving the equation for the roots in closed form.
587  Scalar c2_over_3 = c2 * s_inv3;
588  Scalar a_over_3 = (c2 * c2_over_3 - c1) * s_inv3;
589  a_over_3 = numext::maxi(a_over_3, Scalar(0));
590 
591  Scalar half_b = Scalar(0.5) * (c0 + c2_over_3 * (Scalar(2) * c2_over_3 * c2_over_3 - c1));
592 
593  Scalar q = a_over_3 * a_over_3 * a_over_3 - half_b * half_b;
594  q = numext::maxi(q, Scalar(0));
595 
596  // Compute the eigenvalues by solving for the roots of the polynomial.
597  Scalar rho = sqrt(a_over_3);
598  Scalar theta = atan2(sqrt(q), half_b) * s_inv3; // since sqrt(q) > 0, atan2 is in [0, pi] and theta is in [0, pi/3]
599  Scalar cos_theta = cos(theta);
600  Scalar sin_theta = sin(theta);
601  // roots are already sorted, since cos is monotonically decreasing on [0, pi]
602  roots(0) = c2_over_3 - rho * (cos_theta + s_sqrt3 * sin_theta); // == 2*rho*cos(theta+2pi/3)
603  roots(1) = c2_over_3 - rho * (cos_theta - s_sqrt3 * sin_theta); // == 2*rho*cos(theta+ pi/3)
604  roots(2) = c2_over_3 + Scalar(2) * rho * cos_theta;
605  }
606 
607  EIGEN_DEVICE_FUNC static inline bool extract_kernel(MatrixType& mat, Ref<VectorType> res,
608  Ref<VectorType> representative) {
609  EIGEN_USING_STD(abs);
610  EIGEN_USING_STD(sqrt);
611  Index i0;
612  // Find non-zero column i0 (by construction, there must exist a non zero coefficient on the diagonal):
613  mat.diagonal().cwiseAbs().maxCoeff(&i0);
614  // mat.col(i0) is a good candidate for an orthogonal vector to the current eigenvector,
615  // so let's save it:
616  representative = mat.col(i0);
617  Scalar n0, n1;
618  VectorType c0, c1;
619  n0 = (c0 = representative.cross(mat.col((i0 + 1) % 3))).squaredNorm();
620  n1 = (c1 = representative.cross(mat.col((i0 + 2) % 3))).squaredNorm();
621  if (n0 > n1)
622  res = c0 / sqrt(n0);
623  else
624  res = c1 / sqrt(n1);
625 
626  return true;
627  }
628 
629  EIGEN_DEVICE_FUNC static inline void run(SolverType& solver, const MatrixType& mat, int options) {
630  eigen_assert(mat.cols() == 3 && mat.cols() == mat.rows());
631  eigen_assert((options & ~(EigVecMask | GenEigMask)) == 0 && (options & EigVecMask) != EigVecMask &&
632  "invalid option parameter");
633  bool computeEigenvectors = (options & ComputeEigenvectors) == ComputeEigenvectors;
634 
635  EigenvectorsType& eivecs = solver.m_eivec;
636  VectorType& eivals = solver.m_eivalues;
637 
638  // Shift the matrix to the mean eigenvalue and map the matrix coefficients to [-1:1] to avoid over- and underflow.
639  Scalar shift = mat.trace() / Scalar(3);
640  // TODO Avoid this copy. Currently it is necessary to suppress bogus values when determining maxCoeff and for
641  // computing the eigenvectors later
642  MatrixType scaledMat = mat.template selfadjointView<Lower>();
643  scaledMat.diagonal().array() -= shift;
644  Scalar scale = scaledMat.cwiseAbs().maxCoeff();
645  if (scale > 0) scaledMat /= scale; // TODO for scale==0 we could save the remaining operations
646 
647  // compute the eigenvalues
648  computeRoots(scaledMat, eivals);
649 
650  // compute the eigenvectors
651  if (computeEigenvectors) {
652  if ((eivals(2) - eivals(0)) <= Eigen::NumTraits<Scalar>::epsilon()) {
653  // All three eigenvalues are numerically the same
654  eivecs.setIdentity();
655  } else {
656  MatrixType tmp;
657  tmp = scaledMat;
658 
659  // Compute the eigenvector of the most distinct eigenvalue
660  Scalar d0 = eivals(2) - eivals(1);
661  Scalar d1 = eivals(1) - eivals(0);
662  Index k(0), l(2);
663  if (d0 > d1) {
664  numext::swap(k, l);
665  d0 = d1;
666  }
667 
668  // Compute the eigenvector of index k
669  {
670  tmp.diagonal().array() -= eivals(k);
671  // By construction, 'tmp' is of rank 2, and its kernel corresponds to the respective eigenvector.
672  extract_kernel(tmp, eivecs.col(k), eivecs.col(l));
673  }
674 
675  // Compute eigenvector of index l
676  if (d0 <= 2 * Eigen::NumTraits<Scalar>::epsilon() * d1) {
677  // If d0 is too small, then the two other eigenvalues are numerically the same,
678  // and thus we only have to ortho-normalize the near orthogonal vector we saved above.
679  eivecs.col(l) -= eivecs.col(k).dot(eivecs.col(l)) * eivecs.col(l);
680  eivecs.col(l).normalize();
681  } else {
682  tmp = scaledMat;
683  tmp.diagonal().array() -= eivals(l);
684 
685  VectorType dummy;
686  extract_kernel(tmp, eivecs.col(l), dummy);
687  }
688 
689  // Compute last eigenvector from the other two
690  eivecs.col(1) = eivecs.col(2).cross(eivecs.col(0)).normalized();
691  }
692  }
693 
694  // Rescale back to the original size.
695  eivals *= scale;
696  eivals.array() += shift;
697 
698  solver.m_info = Success;
699  solver.m_isInitialized = true;
700  solver.m_eigenvectorsOk = computeEigenvectors;
701  }
702 };
703 
704 // 2x2 direct eigenvalues decomposition, code from Hauke Heibel
705 template <typename SolverType>
706 struct direct_selfadjoint_eigenvalues<SolverType, 2, false> {
707  typedef typename SolverType::MatrixType MatrixType;
708  typedef typename SolverType::RealVectorType VectorType;
709  typedef typename SolverType::Scalar Scalar;
710  typedef typename SolverType::EigenvectorsType EigenvectorsType;
711 
712  EIGEN_DEVICE_FUNC static inline void computeRoots(const MatrixType& m, VectorType& roots) {
713  EIGEN_USING_STD(sqrt);
714  const Scalar t0 = Scalar(0.5) * sqrt(numext::abs2(m(0, 0) - m(1, 1)) + Scalar(4) * numext::abs2(m(1, 0)));
715  const Scalar t1 = Scalar(0.5) * (m(0, 0) + m(1, 1));
716  roots(0) = t1 - t0;
717  roots(1) = t1 + t0;
718  }
719 
720  EIGEN_DEVICE_FUNC static inline void run(SolverType& solver, const MatrixType& mat, int options) {
721  EIGEN_USING_STD(sqrt);
722  EIGEN_USING_STD(abs);
723 
724  eigen_assert(mat.cols() == 2 && mat.cols() == mat.rows());
725  eigen_assert((options & ~(EigVecMask | GenEigMask)) == 0 && (options & EigVecMask) != EigVecMask &&
726  "invalid option parameter");
727  bool computeEigenvectors = (options & ComputeEigenvectors) == ComputeEigenvectors;
728 
729  EigenvectorsType& eivecs = solver.m_eivec;
730  VectorType& eivals = solver.m_eivalues;
731 
732  // Shift the matrix to the mean eigenvalue and map the matrix coefficients to [-1:1] to avoid over- and underflow.
733  Scalar shift = mat.trace() / Scalar(2);
734  MatrixType scaledMat = mat;
735  scaledMat.coeffRef(0, 1) = mat.coeff(1, 0);
736  scaledMat.diagonal().array() -= shift;
737  Scalar scale = scaledMat.cwiseAbs().maxCoeff();
738  if (scale > Scalar(0)) scaledMat /= scale;
739 
740  // Compute the eigenvalues
741  computeRoots(scaledMat, eivals);
742 
743  // compute the eigen vectors
744  if (computeEigenvectors) {
745  if ((eivals(1) - eivals(0)) <= abs(eivals(1)) * Eigen::NumTraits<Scalar>::epsilon()) {
746  eivecs.setIdentity();
747  } else {
748  scaledMat.diagonal().array() -= eivals(1);
749  Scalar a2 = numext::abs2(scaledMat(0, 0));
750  Scalar c2 = numext::abs2(scaledMat(1, 1));
751  Scalar b2 = numext::abs2(scaledMat(1, 0));
752  if (a2 > c2) {
753  eivecs.col(1) << -scaledMat(1, 0), scaledMat(0, 0);
754  eivecs.col(1) /= sqrt(a2 + b2);
755  } else {
756  eivecs.col(1) << -scaledMat(1, 1), scaledMat(1, 0);
757  eivecs.col(1) /= sqrt(c2 + b2);
758  }
759 
760  eivecs.col(0) << eivecs.col(1).unitOrthogonal();
761  }
762  }
763 
764  // Rescale back to the original size.
765  eivals *= scale;
766  eivals.array() += shift;
767 
768  solver.m_info = Success;
769  solver.m_isInitialized = true;
770  solver.m_eigenvectorsOk = computeEigenvectors;
771  }
772 };
773 
774 } // namespace internal
775 
776 template <typename MatrixType>
778  const MatrixType& matrix, int options) {
779  internal::direct_selfadjoint_eigenvalues<SelfAdjointEigenSolver, Size, NumTraits<Scalar>::IsComplex>::run(
780  *this, matrix, options);
781  return *this;
782 }
783 
784 namespace internal {
785 
786 // Francis implicit QR step.
787 template <int StorageOrder, typename RealScalar, typename Scalar, typename Index>
788 EIGEN_DEVICE_FUNC static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end,
789  Scalar* matrixQ, Index n) {
790  // Wilkinson Shift.
791  RealScalar td = (diag[end - 1] - diag[end]) * RealScalar(0.5);
792  RealScalar e = subdiag[end - 1];
793  // Note that thanks to scaling, e^2 or td^2 cannot overflow, however they can still
794  // underflow thus leading to inf/NaN values when using the following commented code:
795  // RealScalar e2 = numext::abs2(subdiag[end-1]);
796  // RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * sqrt(td*td + e2));
797  // This explain the following, somewhat more complicated, version:
798  RealScalar mu = diag[end];
799  if (numext::is_exactly_zero(td)) {
800  mu -= numext::abs(e);
801  } else if (!numext::is_exactly_zero(e)) {
802  const RealScalar e2 = numext::abs2(e);
803  const RealScalar h = numext::hypot(td, e);
804  if (numext::is_exactly_zero(e2)) {
805  mu -= e / ((td + (td > RealScalar(0) ? h : -h)) / e);
806  } else {
807  mu -= e2 / (td + (td > RealScalar(0) ? h : -h));
808  }
809  }
810 
811  RealScalar x = diag[start] - mu;
812  RealScalar z = subdiag[start];
813  // If z ever becomes zero, the Givens rotation will be the identity and
814  // z will stay zero for all future iterations.
815  for (Index k = start; k < end && !numext::is_exactly_zero(z); ++k) {
816  JacobiRotation<RealScalar> rot;
817  rot.makeGivens(x, z);
818 
819  // do T = G' T G
820  RealScalar sdk = rot.s() * diag[k] + rot.c() * subdiag[k];
821  RealScalar dkp1 = rot.s() * subdiag[k] + rot.c() * diag[k + 1];
822 
823  diag[k] =
824  rot.c() * (rot.c() * diag[k] - rot.s() * subdiag[k]) - rot.s() * (rot.c() * subdiag[k] - rot.s() * diag[k + 1]);
825  diag[k + 1] = rot.s() * sdk + rot.c() * dkp1;
826  subdiag[k] = rot.c() * sdk - rot.s() * dkp1;
827 
828  if (k > start) subdiag[k - 1] = rot.c() * subdiag[k - 1] - rot.s() * z;
829 
830  // "Chasing the bulge" to return to triangular form.
831  x = subdiag[k];
832  if (k < end - 1) {
833  z = -rot.s() * subdiag[k + 1];
834  subdiag[k + 1] = rot.c() * subdiag[k + 1];
835  }
836 
837  // apply the givens rotation to the unit matrix Q = Q * G
838  if (matrixQ) {
839  // FIXME if StorageOrder == RowMajor this operation is not very efficient
840  Map<Matrix<Scalar, Dynamic, Dynamic, StorageOrder> > q(matrixQ, n, n);
841  q.applyOnTheRight(k, k + 1, rot);
842  }
843  }
844 }
845 
846 } // end namespace internal
847 
848 } // end namespace Eigen
849 
850 #endif // EIGEN_SELFADJOINTEIGENSOLVER_H
static constexpr lastp1_t end
Definition: IndexedViewHelper.h:79
SelfAdjointEigenSolver(Index size)
Constructor, pre-allocates memory for dynamic-size matrices.
Definition: SelfAdjointEigenSolver.h:150
const EigenvectorsType & eigenvectors() const
Returns the eigenvectors of given matrix.
Definition: SelfAdjointEigenSolver.h:279
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
Computes eigenvalues and eigenvectors of selfadjoint matrices.
Definition: SelfAdjointEigenSolver.h:82
static const int m_maxIterations
Maximum number of iterations.
Definition: SelfAdjointEigenSolver.h:366
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1
Holds information about the various numeric (i.e. scalar) types allowed by Eigen. ...
Definition: NumTraits.h:232
Tridiagonal decomposition of a selfadjoint matrix.
Definition: Tridiagonalization.h:66
MatrixType operatorInverseSqrt() const
Computes the inverse square root of the matrix.
Definition: SelfAdjointEigenSolver.h:346
Definition: EigenBase.h:33
const RealVectorType & eigenvalues() const
Returns the eigenvalues of given matrix.
Definition: SelfAdjointEigenSolver.h:300
Definition: Constants.h:401
Eigen::Index Index
Definition: SelfAdjointEigenSolver.h:94
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_cos_op< typename Derived::Scalar >, const Derived > cos(const Eigen::ArrayBase< Derived > &x)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
MatrixType::Scalar Scalar
Scalar type for matrices of type MatrixType_.
Definition: SelfAdjointEigenSolver.h:93
SelfAdjointEigenSolver & computeFromTridiagonal(const RealVectorType &diag, const SubDiagonalType &subdiag, int options=ComputeEigenvectors)
Computes the eigen decomposition from a tridiagonal symmetric matrix.
Definition: SelfAdjointEigenSolver.h:455
NumTraits< Scalar >::Real RealScalar
Real scalar type for MatrixType_.
Definition: SelfAdjointEigenSolver.h:104
SelfAdjointEigenSolver & compute(const EigenBase< InputType > &matrix, int options=ComputeEigenvectors)
Computes eigendecomposition of given matrix.
Definition: Constants.h:440
constexpr Derived & derived()
Definition: EigenBase.h:49
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
MatrixType operatorSqrt() const
Computes the positive-definite square root of the matrix.
Definition: SelfAdjointEigenSolver.h:322
SelfAdjointEigenSolver & computeDirect(const MatrixType &matrix, int options=ComputeEigenvectors)
Computes eigendecomposition of given matrix using a closed-form algorithm.
Definition: SelfAdjointEigenSolver.h:777
SelfAdjointEigenSolver(const EigenBase< InputType > &matrix, int options=ComputeEigenvectors)
Constructor; computes eigendecomposition of given matrix.
Definition: SelfAdjointEigenSolver.h:175
ComputationInfo
Definition: Constants.h:438
Definition: Constants.h:444
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sin_op< typename Derived::Scalar >, const Derived > sin(const Eigen::ArrayBase< Derived > &x)
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: SelfAdjointEigenSolver.h:356
internal::plain_col_type< MatrixType, Scalar >::type VectorType
Type for vector of eigenvalues as returned by eigenvalues().
Definition: SelfAdjointEigenSolver.h:113