00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <sstream>
00024
00025 #include "SVD.hpp"
00026 #include "MathTools.hpp"
00027
00028 namespace kn{
00029
00030
00032
00034 void decompositionSVD(Matrix<double>& a,
00035 Vector<double>& w,
00036 Matrix<double>& v){
00037
00038 if(w.size()!=a.columns()){
00039 std::ostringstream out;
00040 out << a.columns();
00041 throw MathException("size of the second parameter is not correct (should be " + out.str() + ")" ,"decompositionSVD");
00042 }
00043
00044 if(v.columns()!=a.columns() || v.rows()!=a.columns()){
00045 std::ostringstream out;
00046 out << a.columns();
00047 throw MathException("size of the third parameter is not correct (should be " + out.str() + "x" + out.str() + ")" ,"decompositionSVD");
00048 }
00049
00050 bool flag;
00051 int i,its,j,jj,k,l=0,nm=0;
00052 double anorm, c,f=0.0,g,h,s,scale,x,y,z=0.0;
00053 int m = a.rows();
00054 int n = a.columns();
00055 Vector<double> rv1(n);
00056
00057 g = scale = anorm = 0.0;
00058
00059 for(i=1; i<=n; ++i)
00060 {
00061 l = i+1;
00062 rv1[i-1] = scale*g;
00063 g = s = scale = 0.0;
00064 if(i <= m)
00065 {
00066 for(k=i; k<=m; ++k)
00067 scale += std::fabs(a[k-1][i-1]);
00068
00069 if(scale)
00070 {
00071 for(k=i; k<=m; ++k)
00072 {
00073 a[k-1][i-1] /= scale;
00074 s += a[k-1][i-1]*a[k-1][i-1];
00075 }
00076
00077 f = a[i-1][i-1];
00078 g = -setSign(sqrt(s),f);
00079 h = f*g - s;
00080 a[i-1][i-1] = f - g;
00081
00082 for(j=l; j<=n; ++j)
00083 {
00084 for(s=0.0,k=i; k<=m; ++k)
00085 s += a[k-1][i-1]*a[k-1][j-1];
00086
00087 f = s/h;
00088
00089 for(k=i; k<=m; ++k)
00090 a[k-1][j-1] += f*a[k-1][i-1];
00091 }
00092
00093 for(k=i; k<=m; ++k)
00094 a[k-1][i-1] *= scale;
00095 }
00096 }
00097 w[i-1] = scale * g;
00098 g = s = scale = 0.0;
00099
00100 if(i <= m && i != n)
00101 {
00102 for(k=l; k<=n; ++k)
00103 scale += std::fabs(a[i-1][k-1]);
00104
00105 if(scale)
00106 {
00107 for(k=l; k<=n; ++k)
00108 {
00109 a[i-1][k-1] /= scale;
00110 s += a[i-1][k-1]*a[i-1][k-1];
00111 }
00112
00113 f = a[i-1][l-1];
00114 g = -setSign(sqrt(s),f);
00115 h = f*g - s;
00116 a[i-1][l-1] = f-g;
00117
00118 for(k=l; k<=n; ++k)
00119 rv1[k-1] = a[i-1][k-1] / h;
00120
00121 for(j=l; j<=m; ++j)
00122 {
00123 for(s=0.0,k=l; k<=n; ++k)
00124 s += a[j-1][k-1] * a[i-1][k-1];
00125
00126 for(k=l; k<=n; ++k)
00127 a[j-1][k-1] += s * rv1[k-1];
00128 }
00129
00130 for(k=l; k<=n; ++k)
00131 a[i-1][k-1] *= scale;
00132 }
00133 }
00134
00135 anorm = std::max(anorm,(std::fabs(w[i-1])+ std::fabs(rv1[i-1])));
00136 }
00137
00138 for(i = n; i>=1; i--)
00139 {
00140 if(i < n)
00141 {
00142 if(g)
00143 {
00144 for(j=l; j<=n; ++j)
00145 v[j-1][i-1] = (a[i-1][j-1]/a[i-1][l-1])/g;
00146
00147 for(j=l; j<=n; ++j)
00148 {
00149 for(s=0.0,k=l; k<=n; ++k)
00150 s += a[i-1][k-1] * v[k-1][j-1];
00151
00152 for(k=l; k<=n; ++k)
00153 v[k-1][j-1] += s * v[k-1][i-1];
00154 }
00155 }
00156 for(j=l; j<=n; ++j)
00157 v[i-1][j-1] = v[j-1][i-1] = 0.0;
00158 }
00159
00160 v[i-1][i-1] = 1.0;
00161 g = rv1[i-1];
00162 l = i;
00163 }
00164
00165 for(i=(int)std::min(m,n); i>=1; i--)
00166 {
00167 l = i+1;
00168 g = w[i-1];
00169
00170 for(j=l; j<=n; ++j)
00171 a[i-1][j-1] = 0.0;
00172
00173 if(g)
00174 {
00175 g = 1.0/g;
00176
00177 for(j=l; j<=n; ++j)
00178 {
00179 for(s=0.0,k=l; k<=m; ++k)
00180 s += a[k-1][i-1] * a[k-1][j-1];
00181
00182 f = (s/a[i-1][i-1])*g;
00183
00184 for(k=i;k<=m;++k)
00185 a[k-1][j-1] += f*a[k-1][i-1];
00186 }
00187
00188 for(j=i;j<=m;++j)
00189 a[j-1][i-1] *= g;
00190 }
00191 else for(j=i; j<=m; ++j)
00192 a[j-1][i-1] = 0.0;
00193
00194 ++a[i-1][i-1];
00195 }
00196
00197 for(k=n; k>=1; k--)
00198 {
00199 for(its=1; its<=30; ++its)
00200 {
00201 flag = true;
00202
00203 for(l=k; l>=1; l--)
00204 {
00205 nm = l-1;
00206 if((double)(std::abs(rv1[l-1])+anorm) == anorm)
00207 {
00208 flag = false;
00209 break;
00210 }
00211
00212 if((double)(std::abs(w[nm-1])+anorm) == anorm)
00213 break;
00214 }
00215 if(flag)
00216 {
00217 c = 0.0;
00218 s = 1.0;
00219
00220 for(i=l;i<=k;++i)
00221 {
00222 f=s*rv1[i-1];
00223 rv1[i-1] = c*rv1[i-1];
00224 if((double)(std::abs(f)+anorm) == anorm)
00225 break;
00226 g=w[i-1];
00227 h = pythag(f,g);
00228 w[i-1]=h;
00229 h=1.0/h;
00230 c=g*h;
00231 s=-f*h;
00232
00233 for(j=1;j<=m;++j)
00234 {
00235 y=a[j-1][nm-1];
00236 z=a[j-1][i-1];
00237 a[j-1][nm-1]=y*c+z*s;
00238 a[j-1][i-1]=z*c-y*s;
00239 }
00240 }
00241 }
00242
00243 z=w[k-1];
00244 if(l==k)
00245 {
00246 if(z < 0.0)
00247 {
00248 w[k-1] = -z;
00249 for(j=1;j<=n;++j)
00250 v[j-1][k-1] = -v[j-1][k-1];
00251 }
00252 break;
00253 }
00254 if(its == 30) return;
00255
00256 x=w[l-1];
00257 nm=k-1;
00258 y=w[nm-1];
00259 g=rv1[nm-1];
00260 h=rv1[k-1];
00261 f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
00262 g= pythag(f,1.0);
00263 f=((x-z)*(x+z)+h*((y/(f + setSign(g,f)))-h))/x;
00264 c=s=1.0;
00265 for (j=l;j<=nm;j++)
00266 {
00267 i=j+1;
00268 g=rv1[i-1];
00269 y=w[i-1];
00270 h=s*g;
00271 g=c*g;
00272 z = pythag(f,h);
00273 rv1[j-1]=z;
00274 c=f/z;
00275 s=h/z;
00276 f=x*c+g*s;
00277 g=g*c-x*s;
00278 h=y*s;
00279 y*=c;
00280 for (jj=1;jj<=n;jj++)
00281 {
00282 x=v[jj-1][j-1];
00283 z=v[jj-1][i-1];
00284 v[jj-1][j-1]=x*c+z*s;
00285 v[jj-1][i-1]=z*c-x*s;
00286 }
00287 z = pythag(f,h);
00288 w[j-1]=z;
00289 if (z)
00290 {
00291 z=1.0/z;
00292 c=f*z;
00293 s=h*z;
00294 }
00295 f=(c*g)+(s*y);
00296 x=(c*y)-(s*g);
00297 for (jj=1;jj<=m;jj++)
00298 {
00299 y=a[jj-1][j-1];
00300 z=a[jj-1][i-1];
00301 a[jj-1][j-1]=y*c+z*s;
00302 a[jj-1][i-1]=z*c-y*s;
00303 }
00304 }
00305 rv1[l-1]=0.0;
00306 rv1[k-1]=f;
00307 w[k-1]=x;
00308 }
00309 }
00310 }
00311
00312
00314
00316 void sortSingularValuesSVD(Matrix<double>& u,
00317 Vector<double>& w,
00318 Matrix<double>& v){
00319
00320 if(w.size()!=u.columns()){
00321 std::ostringstream out;
00322 out << u.columns();
00323 throw MathException("size of the second parameter is not correct (should be " + out.str() + ")" ,"sortSingularValuesSVD");
00324 }
00325
00326 if(v.columns()!=u.columns() || v.rows()!=u.columns()){
00327 std::ostringstream out;
00328 out << u.columns();
00329 throw MathException("size of the third parameter is not correct (should be " + out.str() + "x" + out.str() + ")" ,"sortSingularValuesSVD");
00330 }
00331
00332 for(unsigned int i=0; i<w.size(); ++i){
00333 for(unsigned int j=0; j<w.size()-i-1; ++j){
00334 if(w[j] < w[j+1]){
00335 w.swap(j,j+1);
00336 v.swapColumns(j,j+1);
00337 u.swapColumns(j,j+1);
00338 }
00339 }
00340 }
00341 }
00342
00343
00345
00347 void solveSVD(const Matrix<double>& u,
00348 const Vector<double>& w,
00349 const Matrix<double>& v,
00350 const Vector<double>& b,
00351 Vector<double>& x){
00352
00353 if(w.size()!=u.columns()){
00354 std::ostringstream out;
00355 out << u.columns();
00356 throw MathException("size of the second parameter is not correct (should be " + out.str() + ")" ,"solveSVD");
00357 }
00358
00359 if(v.columns()!=u.columns() || v.rows()!=u.columns()){
00360 std::ostringstream out;
00361 out << u.columns();
00362 throw MathException("size of the third parameter is not correct (should be " + out.str() + "x" + out.str() + ")" ,"solveSVD");
00363 }
00364
00365 if(x.size()!=u.columns()){
00366 std::ostringstream out;
00367 out << u.columns();
00368 throw MathException("size of the fourth parameter is not correct (should be " + out.str() + ")" ,"solveSVD");
00369 }
00370
00371 if(b.size()!=u.rows()){
00372 std::ostringstream out;
00373 out << u.rows();
00374 throw MathException("size of the fifth parameter is not correct (should be " + out.str() + ")" ,"solveSVD");
00375 }
00376
00377
00378 int jj, j, i;
00379 double s;
00380
00381 int m = u.rows();
00382 int n = u.columns();
00383
00384 Vector<double> tmp(n);
00385
00386
00387 for(j=0; j<n;++j){
00388 s = 0.0;
00389 if(w[j] != 0.0){
00390 for(i=0; i<m; ++i)
00391 s += u[i][j]*b[i];
00392 s /= w[j];
00393 }
00394 tmp[j] = s;
00395 }
00396
00397 for(j=0; j<n;++j){
00398 s = 0.0;
00399 for(jj=0; jj<n; ++jj)
00400 s += v[j][jj]*tmp[jj];
00401 x[j] = s;
00402 }
00403
00404 }
00405
00406 }