• Main Page
  • Classes
  • Files
  • Examples
  • File List
  • File Members

svd.cpp

Go to the documentation of this file.
00001 //===========================================================================
00043 //===========================================================================
00044 
00045 #include <cmath>
00046 #include <cstdlib>
00047 #include <SharkDefs.h>
00048 #include <LinAlg/LinAlg.h>
00049 
00050 static double SIGN(double a, double b)
00051 {
00052     return b > 0 ? fabs(a) : -fabs(a);
00053 }
00054 
00055 //===========================================================================
00109 void svd
00110 (
00111     const Array2D< double >& amatA,
00112     Array2D< double >& umatA,
00113     Array2D< double >& vmatA,
00114     Array  < double >& w, // singular values
00115     unsigned maxIterations,
00116     bool ignoreThreshold
00117 )
00118 {
00119     unsigned m = amatA.rows(); /* rows */
00120     unsigned n = amatA.cols(); /* cols */
00121 //  double** const a = amatA.ptrArr(); /* input matrix */
00122 //  double **u = umatA.ptrArr(); /* left vectors */
00123 //  double **v = vmatA.ptrArr(); /* right vectors */
00124 
00125     int flag;
00126     unsigned i, its, j, jj, k, l, nm(0);
00127     double anorm, c, f, g, h, s, scale, x, y, z;
00128 
00129     Array< double > rv1(n);
00130 
00131     /* copy A to U */
00132     for (i = 0; i < m; i++) {
00133         for (j = 0; j < n; j++) {
00134             umatA(i, j) = amatA(i, j);
00135         }
00136     }
00137 
00138     /* householder reduction to bidiagonal form */
00139     g = scale = anorm = 0.0;
00140 
00141     for (i = 0; i < n; i++) {
00142         l = i + 1;
00143         rv1(i) = scale * g;
00144         g = s = scale = 0.0;
00145 
00146         if (i < m) {
00147             for (k = i; k < m; k++) {
00148                 scale += fabs(umatA(k, i));
00149             }
00150 
00151             if (scale != 0.0) {
00152                 for (k = i; k < m; k++) {
00153                     umatA(k, i) /= scale;
00154                     s += umatA(k, i) * umatA(k, i);
00155                 }
00156 
00157                 f = umatA(i, i);
00158                 g = -SIGN(sqrt(s), f);
00159                 h = f * g - s;
00160                 umatA(i, i) = f - g;
00161 
00162                 for (j = l; j < n; j++) {
00163                     s = 0.0;
00164                     for (k = i; k < m; k++) {
00165                         s += umatA(k, i) * umatA(k, j);
00166                     }
00167 
00168                     f = s / h;
00169                     for (k = i; k < m; k++) {
00170                         umatA(k, j) += f * umatA(k, i);
00171                     }
00172                 }
00173 
00174                 for (k = i; k < m; k++) {
00175                     umatA(k, i) *= scale;
00176                 }
00177             }
00178         }
00179 
00180         w(i) = scale * g;
00181         g = s = scale = 0.0;
00182 
00183         if (i < m && i != n - 1) {
00184             for (k = l; k < n; k++) {
00185                 scale += fabs(umatA(i, k));
00186             }
00187 
00188             if (scale != 0.0) {
00189                 for (k = l; k < n; k++) {
00190                     umatA(i, k) /= scale;
00191                     s += umatA(i, k) * umatA(i, k);
00192                 }
00193 
00194                 f = umatA(i, l);
00195                 g = -SIGN(sqrt(s), f);
00196                 h = f * g - s;
00197                 umatA(i, l) = f - g;
00198 
00199                 for (k = l; k < n; k++) {
00200                     rv1(k) = umatA(i, k) / h;
00201                 }
00202 
00203                 for (j = l; j < m; j++) {
00204                     s = 0.0;
00205                     for (k = l; k < n; k++) {
00206                         s += umatA(j, k) * umatA(i, k);
00207                     }
00208 
00209                     for (k = l; k < n; k++) {
00210                         umatA(j, k) += s * rv1(k);
00211                     }
00212                 }
00213 
00214                 for (k = l; k < n; k++) {
00215                     umatA(i, k) *= scale;
00216                 }
00217             }
00218         }
00219 
00220         anorm = Shark::max(anorm, fabs(w(i)) + fabs(rv1(i)));
00221     }
00222 
00223     /* accumulation of right-hand transformations */
00224     for (l = i = n; i--; l--) {
00225         if (l < n) {
00226             if (g != 0.0) {
00227                 for (j = l; j < n; j++) {
00228                     /* double division avoids possible underflow */
00229                     vmatA(j, i) = (umatA(i, j) / umatA(i, l)) / g;
00230                 }
00231 
00232                 for (j = l; j < n; j++) {
00233                     s = 0.0;
00234                     for (k = l; k < n; k++) {
00235                         s += umatA(i, k) * vmatA(k, j);
00236                     }
00237 
00238                     for (k = l; k < n; k++) {
00239                         vmatA(k, j) += s * vmatA(k, i);
00240                     }
00241                 }
00242             }
00243 
00244             for (j = l; j < n; j++) {
00245                 vmatA(i, j) = vmatA(j, i) = 0.0;
00246             }
00247         }
00248 
00249         vmatA(i, i) = 1.0;
00250         g = rv1(i);
00251     }
00252 
00253     /* accumulation of left-hand transformations */
00254     for (l = i = Shark::min(m, n); i--; l--) {
00255         g = w(i);
00256 
00257         for (j = l; j < n; j++) {
00258             umatA(i, j) = 0.0;
00259         }
00260 
00261         if (g != 0.0) {
00262             g = 1.0 / g;
00263 
00264             for (j = l; j < n; j++) {
00265                 s = 0.0;
00266                 for (k = l; k < m; k++) {
00267                     s += umatA(k, i) * umatA(k, j);
00268                 }
00269 
00270                 /* double division avoids possible underflow */
00271                 f = (s / umatA(i, i)) * g;
00272 
00273                 for (k = i; k < m; k++) {
00274                     umatA(k, j) += f * umatA(k, i);
00275                 }
00276             }
00277 
00278             for (j = i; j < m; j++) {
00279                 umatA(j, i) *= g;
00280             }
00281         }
00282         else {
00283             for (j = i; j < m; j++) {
00284                 umatA(j, i) = 0.0;
00285             }
00286         }
00287 
00288         umatA(i, i)++;
00289     }
00290 
00291     /* diagonalization of the bidiagonal form */
00292     for (k = n; k--;) {
00293         for (its = 1; its <= maxIterations; its++) {
00294             flag = 1;
00295 
00296             /* test for splitting */
00297 //          for (l = k + 1; l--; )
00298             /* Thomas Buecher:
00299                     nderung, die fehlerhaft sein kann, aber Absturz verhindert:
00300                 l kann 0 werden --> nm (zwei Zeilen tiefer) wird riesig, da 0-1 auf
00301                 unsigned typ berechnet wird
00302             */
00303             for (l = k; l > 0; l--) {
00304                 /* rv1(0) is always zero, so there is no exit */
00305                 nm = l - 1;
00306 
00307                 if (fabs(rv1(l)) + anorm == anorm) {
00308                     flag = 0;
00309                     break;
00310                 }
00311 
00312                 if (fabs(w(nm)) + anorm == anorm) {
00313                     break;
00314                 }
00315             }
00316 
00317             if (flag) {
00318                 /* cancellation of rv1(l) if l greater than 0 */
00319                 c = 0.0;
00320                 s = 1.0;
00321 
00322                 for (i = l; i <= k; i++) {
00323                     f = s * rv1(i);
00324                     rv1(i) *= c;
00325 
00326                     if (fabs(f) + anorm == anorm) {
00327                         break;
00328                     }
00329 
00330                     g = w(i);
00331                     h = hypot(f, g);
00332                     w(i) = h;
00333                     h = 1.0 / h;
00334                     c = g * h;
00335                     s = -f * h;
00336 
00337                     for (j = 0; j < m; j++) {
00338                         y = umatA(j, nm);
00339                         z = umatA(j, i);
00340                         umatA(j, nm) = y * c + z * s;
00341                         umatA(j, i ) = z * c - y * s;
00342                     }
00343                 }
00344             }
00345 
00346             /* test for convergence */
00347             z = w(k);
00348 
00349             if (l == k) {
00350                 if (z < 0.0) {
00351                     w(k) = -z;
00352                     for (j = 0; j < n; j++) {
00353                         vmatA(j, k) = -vmatA(j, k);
00354                     }
00355                 }
00356                 break;
00357             }
00358 
00359             if( its == maxIterations ) { 
00360                 if(ignoreThreshold)
00361                     break ;
00362                 else
00363                     throw SHARKEXCEPTION("too many iterations for diagonalization of the bidiagonal form during SVD");
00364             }
00365 
00366 
00367             /* shift from bottom 2 by 2 minor */
00368             x = w(l);
00369             nm = k - 1;
00370             y = w(nm);
00371             g = rv1(nm);
00372             h = rv1(k);
00373             f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
00374             g = hypot(f, 1.0);
00375             f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;
00376 
00377             /* next qr transformation */
00378             c = s = 1.0;
00379 
00380             for (j = l; j < k; j++) {
00381                 i = j + 1;
00382                 g = rv1(i);
00383                 y = w(i);
00384                 h = s * g;
00385                 g *= c;
00386                 z = hypot(f, h);
00387                 rv1(j) = z;
00388                 c = f / z;
00389                 s = h / z;
00390                 f = x * c + g * s;
00391                 g = g * c - x * s;
00392                 h = y * s;
00393                 y *= c;
00394 
00395                 for (jj = 0; jj < n; jj++) {
00396                     x = vmatA(jj, j);
00397                     z = vmatA(jj, i);
00398                     vmatA(jj, j) = x * c + z * s;
00399                     vmatA(jj, i) = z * c - x * s;
00400                 }
00401 
00402                 z = hypot(f, h);
00403                 w(j) = z;
00404 
00405                 /* rotation can be arbitrary if z is zero */
00406                 if (z != 0.0) {
00407                     z = 1.0 / z;
00408                     c = f * z;
00409                     s = h * z;
00410                 }
00411 
00412                 f = c * g + s * y;
00413                 x = c * y - s * g;
00414 
00415                 for (jj = 0; jj < m; jj++) {
00416                     y = umatA(jj, j);
00417                     z = umatA(jj, i);
00418                     umatA(jj, j) = y * c + z * s;
00419                     umatA(jj, i) = z * c - y * s;
00420                 }
00421             }
00422 
00423             rv1(l) = 0.0;
00424             rv1(k) = f;
00425             w(k) = x;
00426         }
00427     }
00428 }
00429 
00430 
00431 //===========================================================================
00462 // void svd
00463 // (
00464 //  const Array< double >& A,
00465 //  Array< double >& U,
00466 //  Array< double >& V,
00467 //  Array< double >& W
00468 // )
00469 // {
00470 //  SIZE_CHECK(A.ndim() == 2 && A.dim(0) == A.dim(1))
00471 // 
00472 //  Array2DReference< double > amatL(const_cast< Array< double >& >(A));
00473 //  Array2DReference< double > umatL(U);
00474 //  Array2DReference< double > vmatL(V);
00475 // 
00476 //  U.resize(A.dim(0), A.dim(1), false);
00477 //  V.resize(A.dim(1), A.dim(1), false);
00478 //  W.resize(A.dim(1), false);
00479 // 
00480 //  svd(amatL, umatL, vmatL, W);
00481 //  svdsort(umatL, vmatL, W);
00482 // }
  • Shark Main Page
  • Array
  • Rng
  • LinAlg
  • FileUtil
  • EALib
  • MOO-EALib
  • ReClaM
  • Fuzzy
  • Mixture
  • Tutorials
  • FAQ