00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef EIGEN_SELFADJOINTEIGENSOLVER_H
00026 #define EIGEN_SELFADJOINTEIGENSOLVER_H
00027
00041 template<typename _MatrixType> class SelfAdjointEigenSolver
00042 {
00043 public:
00044
00045 enum {Size = _MatrixType::RowsAtCompileTime };
00046 typedef _MatrixType MatrixType;
00047 typedef typename MatrixType::Scalar Scalar;
00048 typedef typename NumTraits<Scalar>::Real RealScalar;
00049 typedef std::complex<RealScalar> Complex;
00050 typedef Matrix<RealScalar, MatrixType::ColsAtCompileTime, 1> RealVectorType;
00051 typedef Matrix<RealScalar, Dynamic, 1> RealVectorTypeX;
00052 typedef Tridiagonalization<MatrixType> TridiagonalizationType;
00053
00054 SelfAdjointEigenSolver()
00055 : m_eivec(int(Size), int(Size)),
00056 m_eivalues(int(Size))
00057 {
00058 ei_assert(Size!=Dynamic);
00059 }
00060
00061 SelfAdjointEigenSolver(int size)
00062 : m_eivec(size, size),
00063 m_eivalues(size)
00064 {}
00065
00071 SelfAdjointEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true)
00072 : m_eivec(matrix.rows(), matrix.cols()),
00073 m_eivalues(matrix.cols())
00074 {
00075 compute(matrix, computeEigenvectors);
00076 }
00077
00085 SelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true)
00086 : m_eivec(matA.rows(), matA.cols()),
00087 m_eivalues(matA.cols())
00088 {
00089 compute(matA, matB, computeEigenvectors);
00090 }
00091
00092 void compute(const MatrixType& matrix, bool computeEigenvectors = true);
00093
00094 void compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true);
00095
00097 MatrixType eigenvectors(void) const
00098 {
00099 #ifndef NDEBUG
00100 ei_assert(m_eigenvectorsOk);
00101 #endif
00102 return m_eivec;
00103 }
00104
00106 RealVectorType eigenvalues(void) const { return m_eivalues; }
00107
00112 MatrixType operatorSqrt() const
00113 {
00114 return m_eivec * m_eivalues.cwise().sqrt().asDiagonal() * m_eivec.adjoint();
00115 }
00116
00121 MatrixType operatorInverseSqrt() const
00122 {
00123 return m_eivec * m_eivalues.cwise().inverse().cwise().sqrt().asDiagonal() * m_eivec.adjoint();
00124 }
00125
00126
00127 protected:
00128 MatrixType m_eivec;
00129 RealVectorType m_eivalues;
00130 #ifndef NDEBUG
00131 bool m_eigenvectorsOk;
00132 #endif
00133 };
00134
00135 #ifndef EIGEN_HIDE_HEAVY_CODE
00136
00137
00138 template<typename Scalar>
00139 static void ei_givens_rotation(Scalar a, Scalar b, Scalar& c, Scalar& s)
00140 {
00141 if (b==0)
00142 {
00143 c = 1; s = 0;
00144 }
00145 else if (ei_abs(b)>ei_abs(a))
00146 {
00147 Scalar t = -a/b;
00148 s = Scalar(1)/ei_sqrt(1+t*t);
00149 c = s * t;
00150 }
00151 else
00152 {
00153 Scalar t = -b/a;
00154 c = Scalar(1)/ei_sqrt(1+t*t);
00155 s = c * t;
00156 }
00157 }
00158
00175 template<typename RealScalar, typename Scalar>
00176 static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int start, int end, Scalar* matrixQ, int n);
00177
00183 template<typename MatrixType>
00184 void SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
00185 {
00186 #ifndef NDEBUG
00187 m_eigenvectorsOk = computeEigenvectors;
00188 #endif
00189 assert(matrix.cols() == matrix.rows());
00190 int n = matrix.cols();
00191 m_eivalues.resize(n,1);
00192
00193 if(n==1)
00194 {
00195 m_eivalues.coeffRef(0,0) = ei_real(matrix.coeff(0,0));
00196 m_eivec.setOnes();
00197 return;
00198 }
00199
00200 m_eivec = matrix;
00201
00202
00203
00204
00205 RealVectorType& diag = m_eivalues;
00206 typename TridiagonalizationType::SubDiagonalType subdiag(n-1);
00207 TridiagonalizationType::decomposeInPlace(m_eivec, diag, subdiag, computeEigenvectors);
00208
00209 int end = n-1;
00210 int start = 0;
00211 while (end>0)
00212 {
00213 for (int i = start; i<end; ++i)
00214 if (ei_isMuchSmallerThan(ei_abs(subdiag[i]),(ei_abs(diag[i])+ei_abs(diag[i+1]))))
00215 subdiag[i] = 0;
00216
00217
00218 while (end>0 && subdiag[end-1]==0)
00219 end--;
00220 if (end<=0)
00221 break;
00222 start = end - 1;
00223 while (start>0 && subdiag[start-1]!=0)
00224 start--;
00225
00226 ei_tridiagonal_qr_step(diag.data(), subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n);
00227 }
00228
00229
00230
00231
00232 for (int i = 0; i < n-1; ++i)
00233 {
00234 int k;
00235 m_eivalues.segment(i,n-i).minCoeff(&k);
00236 if (k > 0)
00237 {
00238 std::swap(m_eivalues[i], m_eivalues[k+i]);
00239 m_eivec.col(i).swap(m_eivec.col(k+i));
00240 }
00241 }
00242 }
00243
00251 template<typename MatrixType>
00252 void SelfAdjointEigenSolver<MatrixType>::
00253 compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors)
00254 {
00255 ei_assert(matA.cols()==matA.rows() && matB.rows()==matA.rows() && matB.cols()==matB.rows());
00256
00257
00258 LLT<MatrixType> cholB(matB);
00259
00260
00261 MatrixType matC = matA;
00262 cholB.matrixL().solveTriangularInPlace(matC);
00263
00264 matC = matC.adjoint().eval();
00265 cholB.matrixL().template marked<LowerTriangular>().solveTriangularInPlace(matC);
00266 matC = matC.adjoint().eval();
00267
00268
00269
00270
00271
00272
00273
00274
00275 compute(matC, computeEigenvectors);
00276
00277 if (computeEigenvectors)
00278 {
00279
00280 cholB.matrixL().adjoint().template marked<UpperTriangular>().solveTriangularInPlace(m_eivec);
00281 for (int i=0; i<m_eivec.cols(); ++i)
00282 m_eivec.col(i) = m_eivec.col(i).normalized();
00283 }
00284 }
00285
00286 #endif // EIGEN_HIDE_HEAVY_CODE
00287
00292 template<typename Derived>
00293 inline Matrix<typename NumTraits<typename ei_traits<Derived>::Scalar>::Real, ei_traits<Derived>::ColsAtCompileTime, 1>
00294 MatrixBase<Derived>::eigenvalues() const
00295 {
00296 ei_assert(Flags&SelfAdjointBit);
00297 return SelfAdjointEigenSolver<typename Derived::PlainMatrixType>(eval(),false).eigenvalues();
00298 }
00299
00300 template<typename Derived, bool IsSelfAdjoint>
00301 struct ei_operatorNorm_selector
00302 {
00303 static inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real
00304 operatorNorm(const MatrixBase<Derived>& m)
00305 {
00306
00307
00308 return m.eigenvalues().cwise().abs().maxCoeff();
00309 }
00310 };
00311
00312 template<typename Derived> struct ei_operatorNorm_selector<Derived, false>
00313 {
00314 static inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real
00315 operatorNorm(const MatrixBase<Derived>& m)
00316 {
00317 typename Derived::PlainMatrixType m_eval(m);
00318
00319
00320 return ei_sqrt(
00321 (m_eval*m_eval.adjoint())
00322 .template marked<SelfAdjoint>()
00323 .eigenvalues()
00324 .maxCoeff()
00325 );
00326 }
00327 };
00328
00333 template<typename Derived>
00334 inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real
00335 MatrixBase<Derived>::operatorNorm() const
00336 {
00337 return ei_operatorNorm_selector<Derived, Flags&SelfAdjointBit>
00338 ::operatorNorm(derived());
00339 }
00340
00341 #ifndef EIGEN_EXTERN_INSTANTIATIONS
00342 template<typename RealScalar, typename Scalar>
00343 static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int start, int end, Scalar* matrixQ, int n)
00344 {
00345 RealScalar td = (diag[end-1] - diag[end])*RealScalar(0.5);
00346 RealScalar e2 = ei_abs2(subdiag[end-1]);
00347 RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * ei_sqrt(td*td + e2));
00348 RealScalar x = diag[start] - mu;
00349 RealScalar z = subdiag[start];
00350
00351 for (int k = start; k < end; ++k)
00352 {
00353 RealScalar c, s;
00354 ei_givens_rotation(x, z, c, s);
00355
00356
00357 RealScalar sdk = s * diag[k] + c * subdiag[k];
00358 RealScalar dkp1 = s * subdiag[k] + c * diag[k+1];
00359
00360 diag[k] = c * (c * diag[k] - s * subdiag[k]) - s * (c * subdiag[k] - s * diag[k+1]);
00361 diag[k+1] = s * sdk + c * dkp1;
00362 subdiag[k] = c * sdk - s * dkp1;
00363
00364 if (k > start)
00365 subdiag[k - 1] = c * subdiag[k-1] - s * z;
00366
00367 x = subdiag[k];
00368
00369 if (k < end - 1)
00370 {
00371 z = -s * subdiag[k+1];
00372 subdiag[k + 1] = c * subdiag[k+1];
00373 }
00374
00375
00376
00377 if (matrixQ)
00378 {
00379 #ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
00380 #else
00381 int kn = k*n;
00382 int kn1 = (k+1)*n;
00383 #endif
00384
00385 for (int i=0; i<n; ++i)
00386 {
00387 #ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
00388 Scalar matrixQ_i_k = matrixQ[i*n+k];
00389 matrixQ[i*n+k] = c * matrixQ_i_k - s * matrixQ[i*n+k+1];
00390 matrixQ[i*n+k+1] = s * matrixQ_i_k + c * matrixQ[i*n+k+1];
00391 #else
00392 Scalar matrixQ_i_k = matrixQ[i+kn];
00393 matrixQ[i+kn] = c * matrixQ_i_k - s * matrixQ[i+kn1];
00394 matrixQ[i+kn1] = s * matrixQ_i_k + c * matrixQ[i+kn1];
00395 #endif
00396 }
00397 }
00398 }
00399 }
00400 #endif
00401
00402 #endif // EIGEN_SELFADJOINTEIGENSOLVER_H