00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef EIGEN_REAL_SCHUR_H
00012 #define EIGEN_REAL_SCHUR_H
00013
00014 #include "./HessenbergDecomposition.h"
00015
00016 namespace Eigen {
00017
00054 template<typename _MatrixType> class RealSchur
00055 {
00056 public:
00057 typedef _MatrixType MatrixType;
00058 enum {
00059 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
00060 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
00061 Options = MatrixType::Options,
00062 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
00063 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
00064 };
00065 typedef typename MatrixType::Scalar Scalar;
00066 typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
00067 typedef typename MatrixType::Index Index;
00068
00069 typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType;
00070 typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType;
00071
00083 RealSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime)
00084 : m_matT(size, size),
00085 m_matU(size, size),
00086 m_workspaceVector(size),
00087 m_hess(size),
00088 m_isInitialized(false),
00089 m_matUisUptodate(false)
00090 { }
00091
00102 RealSchur(const MatrixType& matrix, bool computeU = true)
00103 : m_matT(matrix.rows(),matrix.cols()),
00104 m_matU(matrix.rows(),matrix.cols()),
00105 m_workspaceVector(matrix.rows()),
00106 m_hess(matrix.rows()),
00107 m_isInitialized(false),
00108 m_matUisUptodate(false)
00109 {
00110 compute(matrix, computeU);
00111 }
00112
00124 const MatrixType& matrixU() const
00125 {
00126 eigen_assert(m_isInitialized && "RealSchur is not initialized.");
00127 eigen_assert(m_matUisUptodate && "The matrix U has not been computed during the RealSchur decomposition.");
00128 return m_matU;
00129 }
00130
00141 const MatrixType& matrixT() const
00142 {
00143 eigen_assert(m_isInitialized && "RealSchur is not initialized.");
00144 return m_matT;
00145 }
00146
00164 RealSchur& compute(const MatrixType& matrix, bool computeU = true);
00165
00170 ComputationInfo info() const
00171 {
00172 eigen_assert(m_isInitialized && "RealSchur is not initialized.");
00173 return m_info;
00174 }
00175
00180 static const int m_maxIterations = 40;
00181
00182 private:
00183
00184 MatrixType m_matT;
00185 MatrixType m_matU;
00186 ColumnVectorType m_workspaceVector;
00187 HessenbergDecomposition<MatrixType> m_hess;
00188 ComputationInfo m_info;
00189 bool m_isInitialized;
00190 bool m_matUisUptodate;
00191
00192 typedef Matrix<Scalar,3,1> Vector3s;
00193
00194 Scalar computeNormOfT();
00195 Index findSmallSubdiagEntry(Index iu, Scalar norm);
00196 void splitOffTwoRows(Index iu, bool computeU, Scalar exshift);
00197 void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo);
00198 void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector);
00199 void performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace);
00200 };
00201
00202
00203 template<typename MatrixType>
00204 RealSchur<MatrixType>& RealSchur<MatrixType>::compute(const MatrixType& matrix, bool computeU)
00205 {
00206 assert(matrix.cols() == matrix.rows());
00207
00208
00209 m_hess.compute(matrix);
00210 m_matT = m_hess.matrixH();
00211 if (computeU)
00212 m_matU = m_hess.matrixQ();
00213
00214
00215 m_workspaceVector.resize(m_matT.cols());
00216 Scalar* workspace = &m_workspaceVector.coeffRef(0);
00217
00218
00219
00220
00221
00222 Index iu = m_matT.cols() - 1;
00223 Index iter = 0;
00224 Index totalIter = 0;
00225 Scalar exshift(0);
00226 Scalar norm = computeNormOfT();
00227
00228 if(norm!=0)
00229 {
00230 while (iu >= 0)
00231 {
00232 Index il = findSmallSubdiagEntry(iu, norm);
00233
00234
00235 if (il == iu)
00236 {
00237 m_matT.coeffRef(iu,iu) = m_matT.coeff(iu,iu) + exshift;
00238 if (iu > 0)
00239 m_matT.coeffRef(iu, iu-1) = Scalar(0);
00240 iu--;
00241 iter = 0;
00242 }
00243 else if (il == iu-1)
00244 {
00245 splitOffTwoRows(iu, computeU, exshift);
00246 iu -= 2;
00247 iter = 0;
00248 }
00249 else
00250 {
00251
00252 Vector3s firstHouseholderVector(0,0,0), shiftInfo;
00253 computeShift(iu, iter, exshift, shiftInfo);
00254 iter = iter + 1;
00255 totalIter = totalIter + 1;
00256 if (totalIter > m_maxIterations * matrix.cols()) break;
00257 Index im;
00258 initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector);
00259 performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace);
00260 }
00261 }
00262 }
00263 if(totalIter <= m_maxIterations * matrix.cols())
00264 m_info = Success;
00265 else
00266 m_info = NoConvergence;
00267
00268 m_isInitialized = true;
00269 m_matUisUptodate = computeU;
00270 return *this;
00271 }
00272
00274 template<typename MatrixType>
00275 inline typename MatrixType::Scalar RealSchur<MatrixType>::computeNormOfT()
00276 {
00277 const Index size = m_matT.cols();
00278
00279
00280
00281 Scalar norm(0);
00282 for (Index j = 0; j < size; ++j)
00283 norm += m_matT.row(j).segment((std::max)(j-1,Index(0)), size-(std::max)(j-1,Index(0))).cwiseAbs().sum();
00284 return norm;
00285 }
00286
00288 template<typename MatrixType>
00289 inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(Index iu, Scalar norm)
00290 {
00291 Index res = iu;
00292 while (res > 0)
00293 {
00294 Scalar s = internal::abs(m_matT.coeff(res-1,res-1)) + internal::abs(m_matT.coeff(res,res));
00295 if (s == 0.0)
00296 s = norm;
00297 if (internal::abs(m_matT.coeff(res,res-1)) < NumTraits<Scalar>::epsilon() * s)
00298 break;
00299 res--;
00300 }
00301 return res;
00302 }
00303
00305 template<typename MatrixType>
00306 inline void RealSchur<MatrixType>::splitOffTwoRows(Index iu, bool computeU, Scalar exshift)
00307 {
00308 const Index size = m_matT.cols();
00309
00310
00311
00312 Scalar p = Scalar(0.5) * (m_matT.coeff(iu-1,iu-1) - m_matT.coeff(iu,iu));
00313 Scalar q = p * p + m_matT.coeff(iu,iu-1) * m_matT.coeff(iu-1,iu);
00314 m_matT.coeffRef(iu,iu) += exshift;
00315 m_matT.coeffRef(iu-1,iu-1) += exshift;
00316
00317 if (q >= Scalar(0))
00318 {
00319 Scalar z = internal::sqrt(internal::abs(q));
00320 JacobiRotation<Scalar> rot;
00321 if (p >= Scalar(0))
00322 rot.makeGivens(p + z, m_matT.coeff(iu, iu-1));
00323 else
00324 rot.makeGivens(p - z, m_matT.coeff(iu, iu-1));
00325
00326 m_matT.rightCols(size-iu+1).applyOnTheLeft(iu-1, iu, rot.adjoint());
00327 m_matT.topRows(iu+1).applyOnTheRight(iu-1, iu, rot);
00328 m_matT.coeffRef(iu, iu-1) = Scalar(0);
00329 if (computeU)
00330 m_matU.applyOnTheRight(iu-1, iu, rot);
00331 }
00332
00333 if (iu > 1)
00334 m_matT.coeffRef(iu-1, iu-2) = Scalar(0);
00335 }
00336
00338 template<typename MatrixType>
00339 inline void RealSchur<MatrixType>::computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo)
00340 {
00341 shiftInfo.coeffRef(0) = m_matT.coeff(iu,iu);
00342 shiftInfo.coeffRef(1) = m_matT.coeff(iu-1,iu-1);
00343 shiftInfo.coeffRef(2) = m_matT.coeff(iu,iu-1) * m_matT.coeff(iu-1,iu);
00344
00345
00346 if (iter == 10)
00347 {
00348 exshift += shiftInfo.coeff(0);
00349 for (Index i = 0; i <= iu; ++i)
00350 m_matT.coeffRef(i,i) -= shiftInfo.coeff(0);
00351 Scalar s = internal::abs(m_matT.coeff(iu,iu-1)) + internal::abs(m_matT.coeff(iu-1,iu-2));
00352 shiftInfo.coeffRef(0) = Scalar(0.75) * s;
00353 shiftInfo.coeffRef(1) = Scalar(0.75) * s;
00354 shiftInfo.coeffRef(2) = Scalar(-0.4375) * s * s;
00355 }
00356
00357
00358 if (iter == 30)
00359 {
00360 Scalar s = (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
00361 s = s * s + shiftInfo.coeff(2);
00362 if (s > Scalar(0))
00363 {
00364 s = internal::sqrt(s);
00365 if (shiftInfo.coeff(1) < shiftInfo.coeff(0))
00366 s = -s;
00367 s = s + (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
00368 s = shiftInfo.coeff(0) - shiftInfo.coeff(2) / s;
00369 exshift += s;
00370 for (Index i = 0; i <= iu; ++i)
00371 m_matT.coeffRef(i,i) -= s;
00372 shiftInfo.setConstant(Scalar(0.964));
00373 }
00374 }
00375 }
00376
00378 template<typename MatrixType>
00379 inline void RealSchur<MatrixType>::initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector)
00380 {
00381 Vector3s& v = firstHouseholderVector;
00382
00383 for (im = iu-2; im >= il; --im)
00384 {
00385 const Scalar Tmm = m_matT.coeff(im,im);
00386 const Scalar r = shiftInfo.coeff(0) - Tmm;
00387 const Scalar s = shiftInfo.coeff(1) - Tmm;
00388 v.coeffRef(0) = (r * s - shiftInfo.coeff(2)) / m_matT.coeff(im+1,im) + m_matT.coeff(im,im+1);
00389 v.coeffRef(1) = m_matT.coeff(im+1,im+1) - Tmm - r - s;
00390 v.coeffRef(2) = m_matT.coeff(im+2,im+1);
00391 if (im == il) {
00392 break;
00393 }
00394 const Scalar lhs = m_matT.coeff(im,im-1) * (internal::abs(v.coeff(1)) + internal::abs(v.coeff(2)));
00395 const Scalar rhs = v.coeff(0) * (internal::abs(m_matT.coeff(im-1,im-1)) + internal::abs(Tmm) + internal::abs(m_matT.coeff(im+1,im+1)));
00396 if (internal::abs(lhs) < NumTraits<Scalar>::epsilon() * rhs)
00397 {
00398 break;
00399 }
00400 }
00401 }
00402
00404 template<typename MatrixType>
00405 inline void RealSchur<MatrixType>::performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace)
00406 {
00407 assert(im >= il);
00408 assert(im <= iu-2);
00409
00410 const Index size = m_matT.cols();
00411
00412 for (Index k = im; k <= iu-2; ++k)
00413 {
00414 bool firstIteration = (k == im);
00415
00416 Vector3s v;
00417 if (firstIteration)
00418 v = firstHouseholderVector;
00419 else
00420 v = m_matT.template block<3,1>(k,k-1);
00421
00422 Scalar tau, beta;
00423 Matrix<Scalar, 2, 1> ess;
00424 v.makeHouseholder(ess, tau, beta);
00425
00426 if (beta != Scalar(0))
00427 {
00428 if (firstIteration && k > il)
00429 m_matT.coeffRef(k,k-1) = -m_matT.coeff(k,k-1);
00430 else if (!firstIteration)
00431 m_matT.coeffRef(k,k-1) = beta;
00432
00433
00434 m_matT.block(k, k, 3, size-k).applyHouseholderOnTheLeft(ess, tau, workspace);
00435 m_matT.block(0, k, (std::min)(iu,k+3) + 1, 3).applyHouseholderOnTheRight(ess, tau, workspace);
00436 if (computeU)
00437 m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace);
00438 }
00439 }
00440
00441 Matrix<Scalar, 2, 1> v = m_matT.template block<2,1>(iu-1, iu-2);
00442 Scalar tau, beta;
00443 Matrix<Scalar, 1, 1> ess;
00444 v.makeHouseholder(ess, tau, beta);
00445
00446 if (beta != Scalar(0))
00447 {
00448 m_matT.coeffRef(iu-1, iu-2) = beta;
00449 m_matT.block(iu-1, iu-1, 2, size-iu+1).applyHouseholderOnTheLeft(ess, tau, workspace);
00450 m_matT.block(0, iu-1, iu+1, 2).applyHouseholderOnTheRight(ess, tau, workspace);
00451 if (computeU)
00452 m_matU.block(0, iu-1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace);
00453 }
00454
00455
00456 for (Index i = im+2; i <= iu; ++i)
00457 {
00458 m_matT.coeffRef(i,i-2) = Scalar(0);
00459 if (i > im+2)
00460 m_matT.coeffRef(i,i-3) = Scalar(0);
00461 }
00462 }
00463
00464 }
00465
00466 #endif // EIGEN_REAL_SCHUR_H