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