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
00029
00030 #ifndef __GR_SVD_H
00031 #define __GR_SVD_H
00032
00033 #include <TooN/TooN.h>
00034 #include <cmath>
00035 #include <vector>
00036 #include <algorithm>
00037
00038 namespace TooN
00039 {
00040
00059 template<int M, int N, class Precision = DefaultPrecision, bool WANT_U = 1, bool WANT_V = 1>
00060 class GR_SVD
00061 {
00062 public:
00063
00064 template<class Precision2, class Base> GR_SVD(const Matrix<M, N, Precision2, Base> &A);
00065
00066 static const int BigDim = M>N?M:N;
00067 static const int SmallDim = M<N?M:N;
00068
00069 const Matrix<M,N,Precision>& get_U() { if(!WANT_U) throw(0); return mU;}
00070 const Matrix<N,N,Precision>& get_V() { if(!WANT_V) throw(0); return mV;}
00071 const Vector<N, Precision>& get_diagonal() {return vDiagonal;}
00072
00073 Precision get_largest_singular_value();
00074 Precision get_smallest_singular_value();
00075 int get_smallest_singular_value_index();
00076
00082 void get_inv_diag(Vector<N>& inv_diag, const Precision condition)
00083 {
00084 Precision dMax = get_largest_singular_value();
00085 for(int i=0; i<N; ++i)
00086 inv_diag[i] = (vDiagonal[i] * condition > dMax) ?
00087 static_cast<Precision>(1)/vDiagonal[i] : 0;
00088 }
00089
00094 template <int Rows2, int Cols2, typename P2, typename B2>
00095 Matrix<N,Cols2, typename Internal::MultiplyType<Precision,P2>::type >
00096 backsub(const Matrix<Rows2,Cols2,P2,B2>& rhs, const Precision condition=1e9)
00097 {
00098 Vector<N,Precision> inv_diag;
00099 get_inv_diag(inv_diag,condition);
00100 return (get_V() * diagmult(inv_diag, (get_U().T() * rhs)));
00101 }
00102
00107 template <int Size, typename P2, typename B2>
00108 Vector<N, typename Internal::MultiplyType<Precision,P2>::type >
00109 backsub(const Vector<Size,P2,B2>& rhs, const Precision condition=1e9)
00110 {
00111 Vector<N,Precision> inv_diag;
00112 get_inv_diag(inv_diag,condition);
00113 return (get_V() * diagmult(inv_diag, (get_U().T() * rhs)));
00114 }
00115
00117 Matrix<N,M,Precision> get_pinv(const Precision condition=1e9)
00118 {
00119 Vector<N,Precision> inv_diag(N);
00120 get_inv_diag(inv_diag,condition);
00121 return diagmult(get_V(),inv_diag) * get_U().T();
00122 }
00123
00125 void reorder();
00126
00127 protected:
00128 void Bidiagonalize();
00129 void Accumulate_RHS();
00130 void Accumulate_LHS();
00131 void Diagonalize();
00132 bool Diagonalize_SubLoop(int k, Precision &z);
00133
00134 Vector<N,Precision> vDiagonal;
00135 Vector<BigDim, Precision> vOffDiagonal;
00136 Matrix<M, N, Precision> mU;
00137 Matrix<N, N, Precision> mV;
00138
00139 int nError;
00140 int nIterations;
00141 Precision anorm;
00142 };
00143
00144
00145
00146 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00147 template<class Precision2, class Base>
00148 GR_SVD<M, N, Precision, WANT_U, WANT_V>::GR_SVD(const Matrix<M, N, Precision2, Base> &mA)
00149 {
00150 nError = 0;
00151 mU = mA;
00152 Bidiagonalize();
00153 Accumulate_RHS();
00154 Accumulate_LHS();
00155 Diagonalize();
00156 };
00157
00158 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00159 void GR_SVD<M,N,Precision, WANT_U, WANT_V>::Bidiagonalize()
00160 {
00161 using std::abs;
00162 using std::max;
00163
00164 Precision g = 0.0;
00165 Precision scale = 0.0;
00166 anorm = 0.0;
00167 for(int i=0; i<N; ++i)
00168 {
00169 const int l = i+1;
00170 vOffDiagonal[i] = scale * g;
00171 g = 0.0;
00172 Precision s = 0.0;
00173 scale = 0.0;
00174 if( i < M )
00175 {
00176 for(int k=i; k<M; ++k)
00177 scale += abs(mU[k][i]);
00178 if(scale != 0.0)
00179 {
00180 for(int k=i; k<M; ++k)
00181 {
00182 mU[k][i] /= scale;
00183 s += mU[k][i] * mU[k][i];
00184 }
00185 Precision f = mU[i][i];
00186 g = -(f>=0?sqrt(s):-sqrt(s));
00187 Precision h = f * g - s;
00188 mU[i][i] = f - g;
00189 if(i!=(N-1))
00190 {
00191 for(int j=l; j<N; ++j)
00192 {
00193 s = 0.0;
00194 for(int k=i; k<M; ++k)
00195 s += mU[k][i] * mU[k][j];
00196 f = s / h;
00197 for(int k=i; k<M; ++k)
00198 mU[k][j] += f * mU[k][i];
00199 }
00200 }
00201 for(int k=i; k<M; ++k)
00202 mU[k][i] *= scale;
00203 }
00204 }
00205 vDiagonal[i] = scale * g;
00206 g = 0.0;
00207 s = 0.0;
00208 scale = 0.0;
00209 if(!(i >= M || i == (N-1)))
00210 {
00211 for(int k=l; k<N; ++k)
00212 scale += abs(mU[i][k]);
00213 if(scale != 0.0)
00214 {
00215 for(int k=l; k<N; k++)
00216 {
00217 mU[i][k] /= scale;
00218 s += mU[i][k] * mU[i][k];
00219 }
00220 Precision f = mU[i][l];
00221 g = -(f>=0?sqrt(s):-sqrt(s));
00222 Precision h = f * g - s;
00223 mU[i][l] = f - g;
00224 for(int k=l; k<N; ++k)
00225 vOffDiagonal[k] = mU[i][k] / h;
00226 if(i != (M-1))
00227 {
00228 for(int j=l; j<M; ++j)
00229 {
00230 s = 0.0;
00231 for(int k=l; k<N; ++k)
00232 s += mU[j][k] * mU[i][k];
00233 for(int k=l; k<N; ++k)
00234 mU[j][k] += s * vOffDiagonal[k];
00235 }
00236 }
00237 for(int k=l; k<N; ++k)
00238 mU[i][k] *= scale;
00239 }
00240 }
00241 anorm = max(anorm, abs(vDiagonal[i]) + abs(vOffDiagonal[i]));
00242 }
00243
00244
00245 }
00246
00247 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00248 void GR_SVD<M,N,Precision,WANT_U,WANT_V>::Accumulate_RHS()
00249 {
00250
00251
00252
00253 mV[N-1][N-1] = static_cast<Precision>(1);
00254 Precision g = vOffDiagonal[N-1];
00255
00256
00257 for(int i=N-2; i>=0; --i)
00258 {
00259 const int l = i + 1;
00260 if( g!=0)
00261 {
00262 for(int j=l; j<N; ++j)
00263 mV[j][i] = (mU[i][j] / mU[i][l]) / g;
00264 for(int j=l; j<N; ++j)
00265 {
00266 Precision s = 0;
00267 for(int k=l; k<N; ++k)
00268 s += mU[i][k] * mV[k][j];
00269 for(int k=l; k<N; ++k)
00270 mV[k][j] += s * mV[k][i];
00271 }
00272 }
00273 for(int j=l; j<N; ++j)
00274 mV[i][j] = mV[j][i] = 0;
00275 mV[i][i] = static_cast<Precision>(1);
00276 g = vOffDiagonal[i];
00277 }
00278 }
00279
00280 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00281 void GR_SVD<M,N,Precision,WANT_U,WANT_V>::Accumulate_LHS()
00282 {
00283
00284
00285 for(int i=SmallDim-1; i>=0; --i)
00286 {
00287 const int l = i+1;
00288 Precision g = vDiagonal[i];
00289
00290 if(i != (N-1))
00291 for(int j=l; j<N; ++j)
00292 mU[i][j] = 0.0;
00293 if(g == 0.0)
00294 for(int j=i; j<M; ++j)
00295 mU[j][i] = 0.0;
00296 else
00297 {
00298
00299 Precision inv_g = static_cast<Precision>(1) / g;
00300 if(i != (SmallDim-1))
00301 {
00302 for(int j=l; j<N; ++j)
00303 {
00304 Precision s = 0;
00305 for(int k=l; k<M; ++k)
00306 s += mU[k][i] * mU[k][j];
00307 Precision f = (s / mU[i][i]) * inv_g;
00308 for(int k=i; k<M; ++k)
00309 mU[k][j] += f * mU[k][i];
00310 }
00311 }
00312 for(int j=i; j<M; ++j)
00313 mU[j][i] *= inv_g;
00314 }
00315 mU[i][i] += static_cast<Precision>(1);
00316 }
00317 }
00318
00319 template<int M, int N, class Precision,bool WANT_U, bool WANT_V>
00320 void GR_SVD<M,N,Precision,WANT_U,WANT_V>::Diagonalize()
00321 {
00322
00323 for(int k=N-1; k>=0; --k)
00324 {
00325 nIterations = 0;
00326 Precision z;
00327 bool bConverged_Or_Error = false;
00328 do
00329 bConverged_Or_Error = Diagonalize_SubLoop(k, z);
00330 while(!bConverged_Or_Error);
00331
00332 if(nError)
00333 return;
00334
00335 if(z < 0)
00336 {
00337 vDiagonal[k] = -z;
00338 if(WANT_V)
00339 for(int j=0; j<N; ++j)
00340 mV[j][k] = -mV[j][k];
00341 }
00342 }
00343 };
00344
00345
00346 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00347 bool GR_SVD<M,N,Precision,WANT_U, WANT_V>::Diagonalize_SubLoop(int k, Precision &z)
00348 {
00349 using std::abs;
00350 const int k1 = k-1;
00351
00352 for(int l=k; l>=0; --l)
00353 {
00354 const int l1 = l-1;
00355 const bool rv1_test = ((abs(vOffDiagonal[l]) + anorm) == anorm);
00356 const bool w_test = ((abs(vDiagonal[l1]) + anorm) == anorm);
00357 if(!rv1_test && w_test)
00358 {
00359 Precision c = 0;
00360 Precision s = 1.0;
00361 for(int i=l; i<=k; ++i)
00362 {
00363 Precision f = s * vOffDiagonal[i];
00364 vOffDiagonal[i] *= c;
00365 if((abs(f) + anorm) == anorm)
00366 break;
00367 Precision g = vDiagonal[i];
00368 Precision h = sqrt(f * f + g * g);
00369 vDiagonal[i] = h;
00370 c = g / h;
00371 s = -f / h;
00372 if(WANT_U)
00373 for(int j=0; j<M; ++j)
00374 {
00375 Precision y = mU[j][l1];
00376 Precision z = mU[j][i];
00377 mU[j][l1] = y*c + z*s;
00378 mU[j][i] = -y*s + z*c;
00379 }
00380 }
00381 }
00382 if(rv1_test || w_test)
00383 {
00384
00385 z = vDiagonal[k];
00386 if(l == k)
00387 return true;
00388 if(nIterations == 30)
00389 {
00390 nError = k;
00391 return true;
00392 }
00393 ++nIterations;
00394 Precision x = vDiagonal[l];
00395 Precision y = vDiagonal[k1];
00396 Precision g = vOffDiagonal[k1];
00397 Precision h = vOffDiagonal[k];
00398 Precision f = ((y-z)*(y+z) + (g-h)*(g+h)) / (2.0*h*y);
00399 g = sqrt(f*f + 1.0);
00400 Precision signed_g = (f>=0)?g:-g;
00401 f = ((x-z)*(x+z) + h*(y/(f + signed_g) - h)) / x;
00402
00403
00404 Precision c = 1.0;
00405 Precision s = 1.0;
00406 for(int i1 = l; i1<=k1; ++i1)
00407 {
00408 const int i=i1+1;
00409 g = vOffDiagonal[i];
00410 y = vDiagonal[i];
00411 h = s*g;
00412 g = c*g;
00413 z = sqrt(f*f + h*h);
00414 vOffDiagonal[i1] = z;
00415 c = f/z;
00416 s = h/z;
00417 f = x*c + g*s;
00418 g = -x*s + g*c;
00419 h = y*s;
00420 y *= c;
00421 if(WANT_V)
00422 for(int j=0; j<N; ++j)
00423 {
00424 Precision xx = mV[j][i1];
00425 Precision zz = mV[j][i];
00426 mV[j][i1] = xx*c + zz*s;
00427 mV[j][i] = -xx*s + zz*c;
00428 }
00429 z = sqrt(f*f + h*h);
00430 vDiagonal[i1] = z;
00431 if(z!=0)
00432 {
00433 c = f/z;
00434 s = h/z;
00435 }
00436 f = c*g + s*y;
00437 x = -s*g + c*y;
00438 if(WANT_U)
00439 for(int j=0; j<M; ++j)
00440 {
00441 Precision yy = mU[j][i1];
00442 Precision zz = mU[j][i];
00443 mU[j][i1] = yy*c + zz*s;
00444 mU[j][i] = -yy*s + zz*c;
00445 }
00446 }
00447 vOffDiagonal[l] = 0;
00448 vOffDiagonal[k] = f;
00449 vDiagonal[k] = x;
00450 return false;
00451
00452 }
00453 }
00454
00455 throw(0);
00456 return false;
00457 }
00458
00459
00460 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00461 Precision GR_SVD<M,N,Precision,WANT_U,WANT_V>::get_largest_singular_value()
00462 {
00463 using std::max;
00464 Precision d = vDiagonal[0];
00465 for(int i=1; i<N; ++i) d = max(d, vDiagonal[i]);
00466 return d;
00467 }
00468
00469 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00470 Precision GR_SVD<M,N,Precision,WANT_U,WANT_V>::get_smallest_singular_value()
00471 {
00472 using std::min;
00473 Precision d = vDiagonal[0];
00474 for(int i=1; i<N; ++i) d = min(d, vDiagonal[i]);
00475 return d;
00476 }
00477
00478 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00479 int GR_SVD<M,N,Precision,WANT_U,WANT_V>::get_smallest_singular_value_index()
00480 {
00481 using std::min;
00482 int nMin=0;
00483 Precision d = vDiagonal[0];
00484 for(int i=1; i<N; ++i)
00485 if(vDiagonal[i] < d)
00486 {
00487 d = vDiagonal[i];
00488 nMin = i;
00489 }
00490 return nMin;
00491 }
00492
00493 template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
00494 void GR_SVD<M,N,Precision,WANT_U,WANT_V>::reorder()
00495 {
00496 std::vector<std::pair<Precision, unsigned int> > vSort;
00497 vSort.reserve(N);
00498 for(unsigned int i=0; i<N; ++i)
00499 vSort.push_back(std::make_pair(-vDiagonal[i], i));
00500 std::sort(vSort.begin(), vSort.end());
00501 for(unsigned int i=0; i<N; ++i)
00502 vDiagonal[i] = -vSort[i].first;
00503 if(WANT_U)
00504 {
00505 Matrix<M, N, Precision> mU_copy = mU;
00506 for(unsigned int i=0; i<N; ++i)
00507 mU.T()[i] = mU_copy.T()[vSort[i].second];
00508 }
00509 if(WANT_V)
00510 {
00511 Matrix<N, N, Precision> mV_copy = mV;
00512 for(unsigned int i=0; i<N; ++i)
00513 mV.T()[i] = mV_copy.T()[vSort[i].second];
00514 }
00515 }
00516
00517 }
00518 #endif
00519
00520
00521
00522
00523
00524