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
00026
00027
00028 #ifndef mrpt_ops_matrices_eigen_H
00029 #define mrpt_ops_matrices_eigen_H
00030
00031 #include <mrpt/math/math_frwds.h>
00032 #include <mrpt/math/matrices_metaprogramming.h>
00033
00034
00035
00036
00037
00038
00039 namespace mrpt
00040 {
00041 namespace math
00042 {
00043 namespace detail
00044 {
00045
00046
00047
00048 template <class MAT,class ARR> void tred2(MAT &a, const size_t nn, ARR &d, ARR &e);
00049 template <class MAT,class ARR> void tqli(ARR &d, ARR &e, const size_t nn, MAT &z);
00050
00051
00052
00053
00054 template <class MATRIX1,class MATRIX2,class VECTOR1> void
00055 eigenVectorsMatrix(const MATRIX1 &M,MATRIX2 *eVecs,VECTOR1 &eVals )
00056 {
00057 ASSERTMSG_(M.isSquare(), "eigenvalues can be computed for square matrices only.")
00058 bool doEVecs = (eVecs!=NULL);
00059 const size_t N = M.getColCount();
00060
00061
00062 typedef typename MATRIX1::value_type T;
00063 MAT_TYPE_SAMESIZE_OF(MATRIX1) a;
00064 a.setSize(M.getRowCount(),M.getColCount());
00065
00066
00067 ARRAY_TYPE_SAMESIZE_ROWS_OF(MATRIX1) d,e;
00068 d.resize(M.getRowCount());
00069 e.resize(M.getRowCount());
00070
00071 MRPT_START
00072
00073
00074 #ifdef _DEBUG
00075 for (size_t i=0;i<N;i++)
00076 for (size_t j=i;j<N;j++)
00077 if (M.get_unsafe(i,j)!=M.get_unsafe(j,i))
00078 {
00079 THROW_EXCEPTION(format("eigenVectors: The matrix is not symmetric! m(%lu,%lu)=%.16e != m(%lu,%lu)=%.16e\n",
00080 static_cast<unsigned long>(i),static_cast<unsigned long>(j), static_cast<double> ( M.get_unsafe(i,j) ),
00081 static_cast<unsigned long>(j),static_cast<unsigned long>(i), static_cast<double> ( M.get_unsafe(j,i) )) )
00082 }
00083 #endif
00084
00085
00086
00087 a = M;
00088
00089
00090
00091 tred2( a, N, d, e);
00092 tqli(d,e,N,a);
00093
00094
00095
00096
00097
00098
00099
00100 std::vector<unsigned int> indxs(N+1);
00101 std::vector<bool> already(N+1, false);
00102
00103 for (size_t i=0;i<N;i++)
00104 {
00105 size_t minIndx = std::numeric_limits<size_t>::max();
00106 for (size_t j=0;j<N;j++)
00107 if (!already[j])
00108 {
00109 if (minIndx==std::numeric_limits<size_t>::max()) minIndx = j;
00110 else
00111 if (d[j]<d[minIndx]) minIndx = j;
00112 }
00113
00114
00115 indxs[i] = static_cast<unsigned int> ( minIndx );
00116 already[minIndx] = true;
00117 }
00118
00119 for (size_t i=0;i<N;i++)
00120 ASSERT_(already[i]);
00121
00122
00123 eVals.resize(N);
00124 if (doEVecs) eVecs->setSize(N,N);
00125
00126
00127 for (size_t i=0;i<N;i++)
00128 {
00129 eVals[i]=d[indxs[i]];
00130 if (doEVecs)
00131 for (size_t j=0;j<N;j++)
00132 eVecs->get_unsafe(i,j) = a.get_unsafe(i,indxs[j]);
00133 }
00134
00135 MRPT_END_WITH_CLEAN_UP( std::cout << "[eigenVectors] The matrix leading to exception is:" << std::endl << M << std::endl; )
00136 }
00137
00138
00139
00140 template <class MATRIX1,class MATRIX2,class VECTOR1> void
00141 eigenVectorsMatrix_special_2x2(const MATRIX1 &M,MATRIX2 *eVecs,VECTOR1 &eVals )
00142 {
00143 typedef typename MATRIX1::value_type T;
00144 const T t = M.get_unsafe(0,0) + M.get_unsafe(1,1);
00145 const T de = M.get_unsafe(0,0)*M.get_unsafe(1,1)-M.get_unsafe(1,0)*M.get_unsafe(0,1);
00146 eVals.resize(2);
00147
00148 const T disc = ::sqrt(0.25*t*t-de);
00149 eVals[0] =0.5*t - disc;
00150 eVals[1] =0.5*t + disc;
00151 if (!eVecs) return;
00152 eVecs->setSize(2,2);
00153 const T c = M.get_unsafe(1,0);
00154 const T b = M.get_unsafe(0,1);
00155 if (c!=0)
00156 {
00157 eVecs->get_unsafe(0,0)=eVals[0]-M.get_unsafe(1,1);
00158 const T ev1n = 1.0/hypot( eVecs->get_unsafe(0,0), c );
00159 eVecs->get_unsafe(0,0)*=ev1n;
00160 eVecs->get_unsafe(1,0)=c*ev1n;
00161
00162 eVecs->get_unsafe(0,1)=eVals[1]-M.get_unsafe(1,1);
00163 const T ev2n = 1.0/hypot( eVecs->get_unsafe(0,1), c );
00164 eVecs->get_unsafe(0,1)*=ev2n;
00165 eVecs->get_unsafe(1,1)=c*ev2n;
00166 }
00167 else if (b!=0)
00168 {
00169 eVecs->get_unsafe(1,0)=eVals[0]-M.get_unsafe(0,0);
00170 const T ev1n = 1.0/hypot( eVecs->get_unsafe(1,0), b );
00171 eVecs->get_unsafe(1,0)*=ev1n;
00172 eVecs->get_unsafe(0,0)=b*ev1n;
00173
00174 eVecs->get_unsafe(1,1)=eVals[1]-M.get_unsafe(0,0);
00175 const T ev2n = 1.0/hypot( eVecs->get_unsafe(1,1), b );
00176 eVecs->get_unsafe(1,1)*=ev2n;
00177 eVecs->get_unsafe(0,1)=b*ev2n;
00178
00179 } else
00180 {
00181 eVecs->get_unsafe(0,0)=1;
00182 eVecs->get_unsafe(1,0)=0;
00183 eVecs->get_unsafe(0,1)=0;
00184 eVecs->get_unsafe(1,1)=1;
00185 }
00186 }
00187
00188
00189
00190 template <class T> inline T pythag(const T a, const T b) {
00191 T at, bt, ct;
00192 return static_cast<T>(( ((at = fabs(a)) > (bt = fabs(b)) ?
00193 (ct = bt/at, at*(::sqrt(1.0+ct*ct))) :
00194 (bt ? (ct = at/bt, bt*(::sqrt(1.0+ct*ct))): 0)) ) );
00195 }
00196
00197 template <class T> inline T SIGN(T a,T b) { return static_cast<T>(( ((b) >= 0 ? fabs(a) : -fabs(a)) )); }
00198
00199
00200
00201
00202
00203
00204
00205
00206 template <class MAT,class ARR>
00207 void tred2(MAT &a, const size_t n, ARR &d, ARR &e)
00208 {
00209 typename MAT::value_type scale,hh,h,g,f;
00210
00211 for (size_t i=n-1;i!=0;i--)
00212 {
00213
00214 h=scale=0.0;
00215 if (i > 1)
00216 {
00217 for (size_t k=0;k<i;k++)
00218 scale += fabs(a.get_unsafe(i,k));
00219 if (scale == 0)
00220 e[i]=a.get_unsafe(i,i-1);
00221 else
00222 {
00223 for (size_t k=0;k<i;k++)
00224 {
00225 a.get_unsafe(i,k) /= scale;
00226 h += a.get_unsafe(i,k)*a.get_unsafe(i,k);
00227 }
00228 f=a.get_unsafe(i,i-1);
00229 g=(f >= 0 ? -::sqrt(h) : (::sqrt(h)));
00230 e[i]=scale*g;
00231 h -= f*g;
00232 a.get_unsafe(i,i-1)=f-g;
00233 f=0;
00234 for (size_t j=0;j<i;j++)
00235 {
00236 a.get_unsafe(j,i)=a.get_unsafe(i,j)/h;
00237 g=0.0;
00238 for (size_t k=0;k<=j;k++)
00239 g += a.get_unsafe(j,k)*a.get_unsafe(i,k);
00240 for (size_t k=j+1;k<i;k++)
00241 g += a.get_unsafe(k,j)*a.get_unsafe(i,k);
00242 e[j]=g/h;
00243 f += e[j]*a.get_unsafe(i,j);
00244 }
00245 hh=f/(h+h);
00246 for (size_t j=0;j<i;j++)
00247 {
00248 f=a.get_unsafe(i,j);
00249 e[j]=g=e[j]-hh*f;
00250 for (size_t k=0;k<=j;k++)
00251 a.get_unsafe(j,k) -= (f*e[k]+g*a.get_unsafe(i,k));
00252 }
00253 }
00254 } else
00255 e[i]=a.get_unsafe(i,i-1);
00256 d[i]=h;
00257 }
00258
00259
00260 d[0]=0;
00261 e[0]=0;
00262
00263
00264
00265 for (size_t i=0;i<n;i++)
00266 {
00267 if (d[i])
00268 for (size_t j=0;j<i;j++)
00269 {
00270 g=0.0;
00271 for (size_t k=0;k<i;k++)
00272 g += a.get_unsafe(i,k)*a.get_unsafe(k,j);
00273 for (size_t k=0;k<i;k++)
00274 a.get_unsafe(k,j) -= g*a.get_unsafe(k,i);
00275 }
00276 d[i]=a.get_unsafe(i,i);
00277 a.get_unsafe(i,i)=1;
00278 for (size_t j=0;j<i;j++)
00279 a.get_unsafe(j,i)=a.get_unsafe(i,j)= 0;
00280 }
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 template <class MAT,class ARR>
00294 void tqli(ARR &d, ARR &e, const size_t n, MAT &z)
00295 {
00296 typedef typename MAT::value_type T;
00297
00298 T s,r,p,g,f,dd,c,b;
00299 const T EPS= std::numeric_limits<T>::epsilon();
00300
00301 for (size_t i=1;i<n;i++)
00302 e[i-1]=e[i];
00303
00304 e[n-1]=0.0;
00305 for (size_t l=0;l<n;l++)
00306 {
00307 size_t iter=0;
00308 size_t m;
00309 do
00310 {
00311 for (m=l;m<(n-1);m++)
00312 {
00313 dd=static_cast<T>(( fabs(d[m])+fabs(d[m+1]) ) );
00314
00315
00316
00317
00318
00319
00320
00321
00322 if (fabs(e[m]) <= EPS*dd) break;
00323 }
00324 if (m != l)
00325 {
00326 if (iter++ == 60) THROW_EXCEPTION("tqli: Too many iterations in tqli!")
00327
00328 g=static_cast<T>(( (d[l+1]-d[l])/(2.0*e[l])));
00329 r=pythag(g,static_cast<T>(1.0));
00330 g=d[m]-d[l]+e[l]/(g+SIGN(r,g));
00331 s = c = 1;
00332 p = 0;
00333 int i;
00334 for (i=int(m)-1;i>=int(l);i--)
00335 {
00336 f=s*e[i];
00337 b=c*e[i];
00338 e[i+1]=(r=pythag(f,g));
00339 if (r == 0.0)
00340 {
00341 d[i+1] -= p;
00342 e[m]=0.0;
00343 break;
00344 }
00345 s=f/r;
00346 c=g/r;
00347 g=d[i+1]-p;
00348 r=(d[i]-g)*s+2.0f*c*b;
00349 d[i+1]=g+(p=s*r);
00350 g=c*r-b;
00351
00352 for (size_t k=0;k<n;k++)
00353 {
00354 f=z.get_unsafe(k,i+1);
00355 z.get_unsafe(k,i+1)=s*z.get_unsafe(k,i)+c*f;
00356 z.get_unsafe(k,i)=c*z.get_unsafe(k,i)-s*f;
00357 }
00358 }
00359
00360 if (r == 0.0 && i >= int(l)) continue;
00361 d[l] -= p;
00362 e[l]=g;
00363 e[m]=0.0;
00364 }
00365 } while (m != l);
00366 }
00367 }
00368
00369
00370
00371
00372
00373 }
00374 }
00375 }
00376
00377 #endif