Warning, file /include/eigen3/Eigen/src/Eigenvalues/EigenSolver.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef EIGEN_EIGENSOLVER_H
0012 #define EIGEN_EIGENSOLVER_H
0013
0014 #include "./RealSchur.h"
0015
0016 namespace Eigen {
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 template<typename _MatrixType> class EigenSolver
0065 {
0066 public:
0067
0068
0069 typedef _MatrixType MatrixType;
0070
0071 enum {
0072 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
0073 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
0074 Options = MatrixType::Options,
0075 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
0076 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
0077 };
0078
0079
0080 typedef typename MatrixType::Scalar Scalar;
0081 typedef typename NumTraits<Scalar>::Real RealScalar;
0082 typedef Eigen::Index Index;
0083
0084
0085
0086
0087
0088
0089
0090 typedef std::complex<RealScalar> ComplexScalar;
0091
0092
0093
0094
0095
0096
0097 typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType;
0098
0099
0100
0101
0102
0103
0104 typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime> EigenvectorsType;
0105
0106
0107
0108
0109
0110
0111
0112
0113 EigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false), m_eigenvectorsOk(false), m_realSchur(), m_matT(), m_tmp() {}
0114
0115
0116
0117
0118
0119
0120
0121 explicit EigenSolver(Index size)
0122 : m_eivec(size, size),
0123 m_eivalues(size),
0124 m_isInitialized(false),
0125 m_eigenvectorsOk(false),
0126 m_realSchur(size),
0127 m_matT(size, size),
0128 m_tmp(size)
0129 {}
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 template<typename InputType>
0147 explicit EigenSolver(const EigenBase<InputType>& matrix, bool computeEigenvectors = true)
0148 : m_eivec(matrix.rows(), matrix.cols()),
0149 m_eivalues(matrix.cols()),
0150 m_isInitialized(false),
0151 m_eigenvectorsOk(false),
0152 m_realSchur(matrix.cols()),
0153 m_matT(matrix.rows(), matrix.cols()),
0154 m_tmp(matrix.cols())
0155 {
0156 compute(matrix.derived(), computeEigenvectors);
0157 }
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179 EigenvectorsType eigenvectors() const;
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 const MatrixType& pseudoEigenvectors() const
0200 {
0201 eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
0202 eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
0203 return m_eivec;
0204 }
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 MatrixType pseudoEigenvalueMatrix() const;
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 const EigenvalueType& eigenvalues() const
0245 {
0246 eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
0247 return m_eivalues;
0248 }
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 template<typename InputType>
0278 EigenSolver& compute(const EigenBase<InputType>& matrix, bool computeEigenvectors = true);
0279
0280
0281 ComputationInfo info() const
0282 {
0283 eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
0284 return m_info;
0285 }
0286
0287
0288 EigenSolver& setMaxIterations(Index maxIters)
0289 {
0290 m_realSchur.setMaxIterations(maxIters);
0291 return *this;
0292 }
0293
0294
0295 Index getMaxIterations()
0296 {
0297 return m_realSchur.getMaxIterations();
0298 }
0299
0300 private:
0301 void doComputeEigenvectors();
0302
0303 protected:
0304
0305 static void check_template_parameters()
0306 {
0307 EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
0308 EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL);
0309 }
0310
0311 MatrixType m_eivec;
0312 EigenvalueType m_eivalues;
0313 bool m_isInitialized;
0314 bool m_eigenvectorsOk;
0315 ComputationInfo m_info;
0316 RealSchur<MatrixType> m_realSchur;
0317 MatrixType m_matT;
0318
0319 typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType;
0320 ColumnVectorType m_tmp;
0321 };
0322
0323 template<typename MatrixType>
0324 MatrixType EigenSolver<MatrixType>::pseudoEigenvalueMatrix() const
0325 {
0326 eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
0327 const RealScalar precision = RealScalar(2)*NumTraits<RealScalar>::epsilon();
0328 Index n = m_eivalues.rows();
0329 MatrixType matD = MatrixType::Zero(n,n);
0330 for (Index i=0; i<n; ++i)
0331 {
0332 if (internal::isMuchSmallerThan(numext::imag(m_eivalues.coeff(i)), numext::real(m_eivalues.coeff(i)), precision))
0333 matD.coeffRef(i,i) = numext::real(m_eivalues.coeff(i));
0334 else
0335 {
0336 matD.template block<2,2>(i,i) << numext::real(m_eivalues.coeff(i)), numext::imag(m_eivalues.coeff(i)),
0337 -numext::imag(m_eivalues.coeff(i)), numext::real(m_eivalues.coeff(i));
0338 ++i;
0339 }
0340 }
0341 return matD;
0342 }
0343
0344 template<typename MatrixType>
0345 typename EigenSolver<MatrixType>::EigenvectorsType EigenSolver<MatrixType>::eigenvectors() const
0346 {
0347 eigen_assert(m_isInitialized && "EigenSolver is not initialized.");
0348 eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
0349 const RealScalar precision = RealScalar(2)*NumTraits<RealScalar>::epsilon();
0350 Index n = m_eivec.cols();
0351 EigenvectorsType matV(n,n);
0352 for (Index j=0; j<n; ++j)
0353 {
0354 if (internal::isMuchSmallerThan(numext::imag(m_eivalues.coeff(j)), numext::real(m_eivalues.coeff(j)), precision) || j+1==n)
0355 {
0356
0357 matV.col(j) = m_eivec.col(j).template cast<ComplexScalar>();
0358 matV.col(j).normalize();
0359 }
0360 else
0361 {
0362
0363 for (Index i=0; i<n; ++i)
0364 {
0365 matV.coeffRef(i,j) = ComplexScalar(m_eivec.coeff(i,j), m_eivec.coeff(i,j+1));
0366 matV.coeffRef(i,j+1) = ComplexScalar(m_eivec.coeff(i,j), -m_eivec.coeff(i,j+1));
0367 }
0368 matV.col(j).normalize();
0369 matV.col(j+1).normalize();
0370 ++j;
0371 }
0372 }
0373 return matV;
0374 }
0375
0376 template<typename MatrixType>
0377 template<typename InputType>
0378 EigenSolver<MatrixType>&
0379 EigenSolver<MatrixType>::compute(const EigenBase<InputType>& matrix, bool computeEigenvectors)
0380 {
0381 check_template_parameters();
0382
0383 using std::sqrt;
0384 using std::abs;
0385 using numext::isfinite;
0386 eigen_assert(matrix.cols() == matrix.rows());
0387
0388
0389 m_realSchur.compute(matrix.derived(), computeEigenvectors);
0390
0391 m_info = m_realSchur.info();
0392
0393 if (m_info == Success)
0394 {
0395 m_matT = m_realSchur.matrixT();
0396 if (computeEigenvectors)
0397 m_eivec = m_realSchur.matrixU();
0398
0399
0400 m_eivalues.resize(matrix.cols());
0401 Index i = 0;
0402 while (i < matrix.cols())
0403 {
0404 if (i == matrix.cols() - 1 || m_matT.coeff(i+1, i) == Scalar(0))
0405 {
0406 m_eivalues.coeffRef(i) = m_matT.coeff(i, i);
0407 if(!(isfinite)(m_eivalues.coeffRef(i)))
0408 {
0409 m_isInitialized = true;
0410 m_eigenvectorsOk = false;
0411 m_info = NumericalIssue;
0412 return *this;
0413 }
0414 ++i;
0415 }
0416 else
0417 {
0418 Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1));
0419 Scalar z;
0420
0421
0422 {
0423 Scalar t0 = m_matT.coeff(i+1, i);
0424 Scalar t1 = m_matT.coeff(i, i+1);
0425 Scalar maxval = numext::maxi<Scalar>(abs(p),numext::maxi<Scalar>(abs(t0),abs(t1)));
0426 t0 /= maxval;
0427 t1 /= maxval;
0428 Scalar p0 = p/maxval;
0429 z = maxval * sqrt(abs(p0 * p0 + t0 * t1));
0430 }
0431
0432 m_eivalues.coeffRef(i) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, z);
0433 m_eivalues.coeffRef(i+1) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, -z);
0434 if(!((isfinite)(m_eivalues.coeffRef(i)) && (isfinite)(m_eivalues.coeffRef(i+1))))
0435 {
0436 m_isInitialized = true;
0437 m_eigenvectorsOk = false;
0438 m_info = NumericalIssue;
0439 return *this;
0440 }
0441 i += 2;
0442 }
0443 }
0444
0445
0446 if (computeEigenvectors)
0447 doComputeEigenvectors();
0448 }
0449
0450 m_isInitialized = true;
0451 m_eigenvectorsOk = computeEigenvectors;
0452
0453 return *this;
0454 }
0455
0456
0457 template<typename MatrixType>
0458 void EigenSolver<MatrixType>::doComputeEigenvectors()
0459 {
0460 using std::abs;
0461 const Index size = m_eivec.cols();
0462 const Scalar eps = NumTraits<Scalar>::epsilon();
0463
0464
0465 Scalar norm(0);
0466 for (Index j = 0; j < size; ++j)
0467 {
0468 norm += m_matT.row(j).segment((std::max)(j-1,Index(0)), size-(std::max)(j-1,Index(0))).cwiseAbs().sum();
0469 }
0470
0471
0472 if (norm == Scalar(0))
0473 {
0474 return;
0475 }
0476
0477 for (Index n = size-1; n >= 0; n--)
0478 {
0479 Scalar p = m_eivalues.coeff(n).real();
0480 Scalar q = m_eivalues.coeff(n).imag();
0481
0482
0483 if (q == Scalar(0))
0484 {
0485 Scalar lastr(0), lastw(0);
0486 Index l = n;
0487
0488 m_matT.coeffRef(n,n) = Scalar(1);
0489 for (Index i = n-1; i >= 0; i--)
0490 {
0491 Scalar w = m_matT.coeff(i,i) - p;
0492 Scalar r = m_matT.row(i).segment(l,n-l+1).dot(m_matT.col(n).segment(l, n-l+1));
0493
0494 if (m_eivalues.coeff(i).imag() < Scalar(0))
0495 {
0496 lastw = w;
0497 lastr = r;
0498 }
0499 else
0500 {
0501 l = i;
0502 if (m_eivalues.coeff(i).imag() == Scalar(0))
0503 {
0504 if (w != Scalar(0))
0505 m_matT.coeffRef(i,n) = -r / w;
0506 else
0507 m_matT.coeffRef(i,n) = -r / (eps * norm);
0508 }
0509 else
0510 {
0511 Scalar x = m_matT.coeff(i,i+1);
0512 Scalar y = m_matT.coeff(i+1,i);
0513 Scalar denom = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag();
0514 Scalar t = (x * lastr - lastw * r) / denom;
0515 m_matT.coeffRef(i,n) = t;
0516 if (abs(x) > abs(lastw))
0517 m_matT.coeffRef(i+1,n) = (-r - w * t) / x;
0518 else
0519 m_matT.coeffRef(i+1,n) = (-lastr - y * t) / lastw;
0520 }
0521
0522
0523 Scalar t = abs(m_matT.coeff(i,n));
0524 if ((eps * t) * t > Scalar(1))
0525 m_matT.col(n).tail(size-i) /= t;
0526 }
0527 }
0528 }
0529 else if (q < Scalar(0) && n > 0)
0530 {
0531 Scalar lastra(0), lastsa(0), lastw(0);
0532 Index l = n-1;
0533
0534
0535 if (abs(m_matT.coeff(n,n-1)) > abs(m_matT.coeff(n-1,n)))
0536 {
0537 m_matT.coeffRef(n-1,n-1) = q / m_matT.coeff(n,n-1);
0538 m_matT.coeffRef(n-1,n) = -(m_matT.coeff(n,n) - p) / m_matT.coeff(n,n-1);
0539 }
0540 else
0541 {
0542 ComplexScalar cc = ComplexScalar(Scalar(0),-m_matT.coeff(n-1,n)) / ComplexScalar(m_matT.coeff(n-1,n-1)-p,q);
0543 m_matT.coeffRef(n-1,n-1) = numext::real(cc);
0544 m_matT.coeffRef(n-1,n) = numext::imag(cc);
0545 }
0546 m_matT.coeffRef(n,n-1) = Scalar(0);
0547 m_matT.coeffRef(n,n) = Scalar(1);
0548 for (Index i = n-2; i >= 0; i--)
0549 {
0550 Scalar ra = m_matT.row(i).segment(l, n-l+1).dot(m_matT.col(n-1).segment(l, n-l+1));
0551 Scalar sa = m_matT.row(i).segment(l, n-l+1).dot(m_matT.col(n).segment(l, n-l+1));
0552 Scalar w = m_matT.coeff(i,i) - p;
0553
0554 if (m_eivalues.coeff(i).imag() < Scalar(0))
0555 {
0556 lastw = w;
0557 lastra = ra;
0558 lastsa = sa;
0559 }
0560 else
0561 {
0562 l = i;
0563 if (m_eivalues.coeff(i).imag() == RealScalar(0))
0564 {
0565 ComplexScalar cc = ComplexScalar(-ra,-sa) / ComplexScalar(w,q);
0566 m_matT.coeffRef(i,n-1) = numext::real(cc);
0567 m_matT.coeffRef(i,n) = numext::imag(cc);
0568 }
0569 else
0570 {
0571
0572 Scalar x = m_matT.coeff(i,i+1);
0573 Scalar y = m_matT.coeff(i+1,i);
0574 Scalar vr = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag() - q * q;
0575 Scalar vi = (m_eivalues.coeff(i).real() - p) * Scalar(2) * q;
0576 if ((vr == Scalar(0)) && (vi == Scalar(0)))
0577 vr = eps * norm * (abs(w) + abs(q) + abs(x) + abs(y) + abs(lastw));
0578
0579 ComplexScalar cc = ComplexScalar(x*lastra-lastw*ra+q*sa,x*lastsa-lastw*sa-q*ra) / ComplexScalar(vr,vi);
0580 m_matT.coeffRef(i,n-1) = numext::real(cc);
0581 m_matT.coeffRef(i,n) = numext::imag(cc);
0582 if (abs(x) > (abs(lastw) + abs(q)))
0583 {
0584 m_matT.coeffRef(i+1,n-1) = (-ra - w * m_matT.coeff(i,n-1) + q * m_matT.coeff(i,n)) / x;
0585 m_matT.coeffRef(i+1,n) = (-sa - w * m_matT.coeff(i,n) - q * m_matT.coeff(i,n-1)) / x;
0586 }
0587 else
0588 {
0589 cc = ComplexScalar(-lastra-y*m_matT.coeff(i,n-1),-lastsa-y*m_matT.coeff(i,n)) / ComplexScalar(lastw,q);
0590 m_matT.coeffRef(i+1,n-1) = numext::real(cc);
0591 m_matT.coeffRef(i+1,n) = numext::imag(cc);
0592 }
0593 }
0594
0595
0596 Scalar t = numext::maxi<Scalar>(abs(m_matT.coeff(i,n-1)),abs(m_matT.coeff(i,n)));
0597 if ((eps * t) * t > Scalar(1))
0598 m_matT.block(i, n-1, size-i, 2) /= t;
0599
0600 }
0601 }
0602
0603
0604 n--;
0605 }
0606 else
0607 {
0608 eigen_assert(0 && "Internal bug in EigenSolver (INF or NaN has not been detected)");
0609 }
0610 }
0611
0612
0613 for (Index j = size-1; j >= 0; j--)
0614 {
0615 m_tmp.noalias() = m_eivec.leftCols(j+1) * m_matT.col(j).segment(0, j+1);
0616 m_eivec.col(j) = m_tmp;
0617 }
0618 }
0619
0620 }
0621
0622 #endif