Statistiques
| Révision :

root / tmp / org.txm.analec.rcp / src / JamaPlus / SingularValueDecomposition.java @ 2094

Historique | Voir | Annoter | Télécharger (16,18 ko)

1
package JamaPlus;
2
import JamaPlus.util.*;
3

    
4
   /** Singular Value Decomposition.
5
   <P>
6
   For an m-by-n matrix A with m >= n, the singular value decomposition is
7
   an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
8
   an n-by-n orthogonal matrix V so that A = U*S*V'.
9
   <P>
10
   The singular values, sigma[k] = S[k][k], are ordered so that
11
   sigma[0] >= sigma[1] >= ... >= sigma[n-1].
12
   <P>
13
   The singular value decompostion always exists, so the constructor will
14
   never fail.  The matrix condition number and the effective numerical
15
   rank can be computed from this decomposition.
16
   */
17

    
18
public class SingularValueDecomposition implements java.io.Serializable {
19

    
20
/* ------------------------
21
   Class variables
22
 * ------------------------ */
23

    
24
   /** Arrays for internal storage of U and V.
25
   @serial internal storage of U.
26
   @serial internal storage of V.
27
   */
28
   private double[][] U, V;
29

    
30
   /** Array for internal storage of singular values.
31
   @serial internal storage of singular values.
32
   */
33
   private double[] s;
34

    
35
   /** Row and column dimensions.
36
   @serial row dimension.
37
   @serial column dimension.
38
   */
39
   private int m, n;
40
   
41
   private boolean transpose; // pour éviter les bugs quand m<n (cf.ci-dessous) 
42

    
43
/* ------------------------
44
   Constructor
45
 * ------------------------ */
46

    
47
   /** Construct the singular value decomposition
48
   @param A    Rectangular matrix
49
   @return     Structure to access U, S and V.
50
   */
51

    
52
   public SingularValueDecomposition (Matrix Arg) {
53

    
54
      // Derived from LINPACK code.
55
      // Initialize.
56
      /* Apparently the failing cases are only a proper subset of (m<n), 
57
         so let's not throw error.  Correct fix to come later?
58
      if (m<n) {
59
          throw new IllegalArgumentException("Jama SVD only works for m >= n"); }
60
      */
61
      /* 
62
       * Une façon très simple de contourner le problème ci-dessus :
63
       * si m < n on transpose A
64
       * (ce qui revient à échanger U et V, S restant inchangé)
65
       */
66
   transpose = Arg.getColumnDimension()>Arg.getRowDimension();
67
    Matrix M = transpose ? Arg.transpose() : Arg.copy();
68
  
69
     double[][] A = M.getArray();
70
      m = M.getRowDimension();
71
      n = M.getColumnDimension();
72

    
73
      s = new double [n];
74
      U = new double [m][n];
75
      V = new double [n][n];
76
      double[] e = new double [n];
77
      double[] work = new double [m];
78
      boolean wantu = true;
79
      boolean wantv = true;
80

    
81
      // Reduce A to bidiagonal form, storing the diagonal elements
82
      // in s and the super-diagonal elements in e.
83

    
84
      int nct = Math.min(m-1,n);
85
      int nrt = Math.max(0,Math.min(n-2,m));
86
      for (int k = 0; k < Math.max(nct,nrt); k++) {
87
         if (k < nct) {
88

    
89
            // Compute the transformation for the k-th column and
90
            // place the k-th diagonal in s[k].
91
            // Compute 2-norm of k-th column without under/overflow.
92
            s[k] = 0;
93
            for (int i = k; i < m; i++) {
94
               s[k] = Math.hypot(s[k],A[i][k]);
95
            }
96
            if (s[k] != 0.0) {
97
               if (A[k][k] < 0.0) {
98
                  s[k] = -s[k];
99
               }
100
               for (int i = k; i < m; i++) {
101
                  A[i][k] /= s[k];
102
               }
103
               A[k][k] += 1.0;
104
            }
105
            s[k] = -s[k];
106
         }
107
         for (int j = k+1; j < n; j++) {
108
            if ((k < nct) & (s[k] != 0.0))  {
109

    
110
            // Apply the transformation.
111

    
112
               double t = 0;
113
               for (int i = k; i < m; i++) {
114
                  t += A[i][k]*A[i][j];
115
               }
116
               t = -t/A[k][k];
117
               for (int i = k; i < m; i++) {
118
                  A[i][j] += t*A[i][k];
119
               }
120
            }
121

    
122
            // Place the k-th row of A into e for the
123
            // subsequent calculation of the row transformation.
124

    
125
            e[j] = A[k][j];
126
         }
127
         if (wantu & (k < nct)) {
128

    
129
            // Place the transformation in U for subsequent back
130
            // multiplication.
131

    
132
            for (int i = k; i < m; i++) {
133
               U[i][k] = A[i][k];
134
            }
135
         }
136
         if (k < nrt) {
137

    
138
            // Compute the k-th row transformation and place the
139
            // k-th super-diagonal in e[k].
140
            // Compute 2-norm without under/overflow.
141
            e[k] = 0;
142
            for (int i = k+1; i < n; i++) {
143
               e[k] = Math.hypot(e[k],e[i]);
144
            }
145
            if (e[k] != 0.0) {
146
               if (e[k+1] < 0.0) {
147
                  e[k] = -e[k];
148
               }
149
               for (int i = k+1; i < n; i++) {
150
                  e[i] /= e[k];
151
               }
152
               e[k+1] += 1.0;
153
            }
154
            e[k] = -e[k];
155
            if ((k+1 < m) & (e[k] != 0.0)) {
156

    
157
            // Apply the transformation.
158

    
159
               for (int i = k+1; i < m; i++) {
160
                  work[i] = 0.0;
161
               }
162
               for (int j = k+1; j < n; j++) {
163
                  for (int i = k+1; i < m; i++) {
164
                     work[i] += e[j]*A[i][j];
165
                  }
166
               }
167
               for (int j = k+1; j < n; j++) {
168
                  double t = -e[j]/e[k+1];
169
                  for (int i = k+1; i < m; i++) {
170
                     A[i][j] += t*work[i];
171
                  }
172
               }
173
            }
174
            if (wantv) {
175

    
176
            // Place the transformation in V for subsequent
177
            // back multiplication.
178

    
179
               for (int i = k+1; i < n; i++) {
180
                  V[i][k] = e[i];
181
               }
182
            }
183
         }
184
      }
185

    
186
      // Set up the final bidiagonal matrix or order p.
187

    
188
      int p = Math.min(n,m+1);
189
      if (nct < n) {
190
         s[nct] = A[nct][nct];
191
      }
192
      if (m < p) {
193
         s[p-1] = 0.0;
194
      }
195
      if (nrt+1 < p) {
196
         e[nrt] = A[nrt][p-1];
197
      }
198
      e[p-1] = 0.0;
199

    
200
      // If required, generate U.
201

    
202
      if (wantu) {
203
         for (int j = nct; j < n; j++) {
204
            for (int i = 0; i < m; i++) {
205
               U[i][j] = 0.0;
206
            }
207
            U[j][j] = 1.0;
208
         }
209
         for (int k = nct-1; k >= 0; k--) {
210
            if (s[k] != 0.0) {
211
               for (int j = k+1; j < n; j++) {
212
                  double t = 0;
213
                  for (int i = k; i < m; i++) {
214
                     t += U[i][k]*U[i][j];
215
                  }
216
                  t = -t/U[k][k];
217
                  for (int i = k; i < m; i++) {
218
                     U[i][j] += t*U[i][k];
219
                  }
220
               }
221
               for (int i = k; i < m; i++ ) {
222
                  U[i][k] = -U[i][k];
223
               }
224
               U[k][k] = 1.0 + U[k][k];
225
               for (int i = 0; i < k-1; i++) {
226
                  U[i][k] = 0.0;
227
               }
228
            } else {
229
               for (int i = 0; i < m; i++) {
230
                  U[i][k] = 0.0;
231
               }
232
               U[k][k] = 1.0;
233
            }
234
         }
235
      }
236

    
237
      // If required, generate V.
238

    
239
      if (wantv) {
240
         for (int k = n-1; k >= 0; k--) {
241
            if ((k < nrt) & (e[k] != 0.0)) {
242
               for (int j = k+1; j < n; j++) {
243
                  double t = 0;
244
                  for (int i = k+1; i < n; i++) {
245
                     t += V[i][k]*V[i][j];
246
                  }
247
                  t = -t/V[k+1][k];
248
                  for (int i = k+1; i < n; i++) {
249
                     V[i][j] += t*V[i][k];
250
                  }
251
               }
252
            }
253
            for (int i = 0; i < n; i++) {
254
               V[i][k] = 0.0;
255
            }
256
            V[k][k] = 1.0;
257
         }
258
      }
259

    
260
      // Main iteration loop for the singular values.
261

    
262
      int pp = p-1;
263
      int iter = 0;
264
      double eps = Math.pow(2.0,-52.0);
265
      double tiny = Math.pow(2.0,-966.0);
266
      while (p > 0) {
267
         int k,kase;
268

    
269
         // Here is where a test for too many iterations would go.
270

    
271
         // This section of the program inspects for
272
         // negligible elements in the s and e arrays.  On
273
         // completion the variables kase and k are set as follows.
274

    
275
         // kase = 1     if s(p) and e[k-1] are negligible and k<p
276
         // kase = 2     if s(k) is negligible and k<p
277
         // kase = 3     if e[k-1] is negligible, k<p, and
278
         //              s(k), ..., s(p) are not negligible (qr step).
279
         // kase = 4     if e(p-1) is negligible (convergence).
280

    
281
         for (k = p-2; k >= -1; k--) {
282
            if (k == -1) {
283
               break;
284
            }
285
            if (Math.abs(e[k]) <=
286
                  tiny + eps*(Math.abs(s[k]) + Math.abs(s[k+1]))) {
287
               e[k] = 0.0;
288
               break;
289
            }
290
         }
291
         if (k == p-2) {
292
            kase = 4;
293
         } else {
294
            int ks;
295
            for (ks = p-1; ks >= k; ks--) {
296
               if (ks == k) {
297
                  break;
298
               }
299
               double t = (ks != p ? Math.abs(e[ks]) : 0.) + 
300
                          (ks != k+1 ? Math.abs(e[ks-1]) : 0.);
301
               if (Math.abs(s[ks]) <= tiny + eps*t)  {
302
                  s[ks] = 0.0;
303
                  break;
304
               }
305
            }
306
            if (ks == k) {
307
               kase = 3;
308
            } else if (ks == p-1) {
309
               kase = 1;
310
            } else {
311
               kase = 2;
312
               k = ks;
313
            }
314
         }
315
         k++;
316

    
317
         // Perform the task indicated by kase.
318

    
319
         switch (kase) {
320

    
321
            // Deflate negligible s(p).
322

    
323
            case 1: {
324
               double f = e[p-2];
325
               e[p-2] = 0.0;
326
               for (int j = p-2; j >= k; j--) {
327
                  double t = Math.hypot(s[j],f);
328
                  double cs = s[j]/t;
329
                  double sn = f/t;
330
                  s[j] = t;
331
                  if (j != k) {
332
                     f = -sn*e[j-1];
333
                     e[j-1] = cs*e[j-1];
334
                  }
335
                  if (wantv) {
336
                     for (int i = 0; i < n; i++) {
337
                        t = cs*V[i][j] + sn*V[i][p-1];
338
                        V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
339
                        V[i][j] = t;
340
                     }
341
                  }
342
               }
343
            }
344
            break;
345

    
346
            // Split at negligible s(k).
347

    
348
            case 2: {
349
               double f = e[k-1];
350
               e[k-1] = 0.0;
351
               for (int j = k; j < p; j++) {
352
                  double t = Math.hypot(s[j],f);
353
                  double cs = s[j]/t;
354
                  double sn = f/t;
355
                  s[j] = t;
356
                  f = -sn*e[j];
357
                  e[j] = cs*e[j];
358
                  if (wantu) {
359
                     for (int i = 0; i < m; i++) {
360
                        t = cs*U[i][j] + sn*U[i][k-1];
361
                        U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
362
                        U[i][j] = t;
363
                     }
364
                  }
365
               }
366
            }
367
            break;
368

    
369
            // Perform one qr step.
370

    
371
            case 3: {
372

    
373
               // Calculate the shift.
374
   
375
               double scale = Math.max(Math.max(Math.max(Math.max(
376
                       Math.abs(s[p-1]),Math.abs(s[p-2])),Math.abs(e[p-2])), 
377
                       Math.abs(s[k])),Math.abs(e[k]));
378
               double sp = s[p-1]/scale;
379
               double spm1 = s[p-2]/scale;
380
               double epm1 = e[p-2]/scale;
381
               double sk = s[k]/scale;
382
               double ek = e[k]/scale;
383
               double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
384
               double c = (sp*epm1)*(sp*epm1);
385
               double shift = 0.0;
386
               if ((b != 0.0) | (c != 0.0)) {
387
                  shift = Math.sqrt(b*b + c);
388
                  if (b < 0.0) {
389
                     shift = -shift;
390
                  }
391
                  shift = c/(b + shift);
392
               }
393
               double f = (sk + sp)*(sk - sp) + shift;
394
               double g = sk*ek;
395
   
396
               // Chase zeros.
397
   
398
               for (int j = k; j < p-1; j++) {
399
                  double t = Math.hypot(f,g);
400
                  double cs = f/t;
401
                  double sn = g/t;
402
                  if (j != k) {
403
                     e[j-1] = t;
404
                  }
405
                  f = cs*s[j] + sn*e[j];
406
                  e[j] = cs*e[j] - sn*s[j];
407
                  g = sn*s[j+1];
408
                  s[j+1] = cs*s[j+1];
409
                  if (wantv) {
410
                     for (int i = 0; i < n; i++) {
411
                        t = cs*V[i][j] + sn*V[i][j+1];
412
                        V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
413
                        V[i][j] = t;
414
                     }
415
                  }
416
                  t = Math.hypot(f,g);
417
                  cs = f/t;
418
                  sn = g/t;
419
                  s[j] = t;
420
                  f = cs*e[j] + sn*s[j+1];
421
                  s[j+1] = -sn*e[j] + cs*s[j+1];
422
                  g = sn*e[j+1];
423
                  e[j+1] = cs*e[j+1];
424
                  if (wantu && (j < m-1)) {
425
                     for (int i = 0; i < m; i++) {
426
                        t = cs*U[i][j] + sn*U[i][j+1];
427
                        U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
428
                        U[i][j] = t;
429
                     }
430
                  }
431
               }
432
               e[p-2] = f;
433
               iter = iter + 1;
434
            }
435
            break;
436

    
437
            // Convergence.
438

    
439
            case 4: {
440

    
441
               // Make the singular values positive.
442
   
443
               if (s[k] <= 0.0) {
444
                  s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
445
                  if (wantv) {
446
                     for (int i = 0; i <= pp; i++) {
447
                        V[i][k] = -V[i][k];
448
                     }
449
                  }
450
               }
451
   
452
               // Order the singular values.
453
   
454
               while (k < pp) {
455
                  if (s[k] >= s[k+1]) {
456
                     break;
457
                  }
458
                  double t = s[k];
459
                  s[k] = s[k+1];
460
                  s[k+1] = t;
461
                  if (wantv && (k < n-1)) {
462
                     for (int i = 0; i < n; i++) {
463
                        t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
464
                     }
465
                  }
466
                  if (wantu && (k < m-1)) {
467
                     for (int i = 0; i < m; i++) {
468
                        t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
469
                     }
470
                  }
471
                  k++;
472
               }
473
               iter = 0;
474
               p--;
475
            }
476
            break;
477
         }
478
      }
479
   }
480

    
481
/* ------------------------
482
   Public Methods
483
 * ------------------------ */
484

    
485
   /** Return the left singular vectors
486
   @return     U
487
   */
488

    
489
   public Matrix getU () {
490
      return transpose ? new Matrix(V,n,n) : new Matrix(U,m,n);
491
   }
492

    
493
   /** Return the right singular vectors
494
   @return     V
495
   */
496

    
497
   public Matrix getV () {
498
      return transpose ? new Matrix(U,m,n) : new Matrix(V,n,n);
499
   }
500

    
501
   /** Return the one-dimensional array of singular values
502
   @return     diagonal of S.
503
   */
504

    
505
   public double[] getSingularValues () {
506
      return s;
507
   }
508

    
509
   /** Return the diagonal matrix of singular values
510
   @return     S
511
   */
512

    
513
   public Matrix getS () {
514
      Matrix X = new Matrix(n,n);
515
      double[][] S = X.getArray();
516
      for (int i = 0; i < n; i++) {
517
         for (int j = 0; j < n; j++) {
518
            S[i][j] = 0.0;
519
         }
520
         S[i][i] = this.s[i];
521
      }
522
      return X;
523
   }
524

    
525
   /** Two norm
526
   @return     max(S)
527
   */
528

    
529
   public double norm2 () {
530
      return s[0];
531
   }
532

    
533
   /** Two norm condition number
534
   @return     max(S)/min(S)
535
   */
536

    
537
   public double cond () {
538
      return s[0]/s[Math.min(m,n)-1];
539
   }
540

    
541
   /** Effective numerical matrix rank
542
   @return     Number of nonnegligible singular values.
543
   */
544

    
545
   public int rank () {
546
      double eps = Math.pow(2.0,-52.0);
547
      double tol = Math.max(m,n)*s[0]*eps;
548
      int r = 0;
549
      for (int i = 0; i < s.length; i++) {
550
         if (s[i] > tol) {
551
            r++;
552
         }
553
      }
554
      return r;
555
   }
556
}