root / tmp / org.txm.analec.rcp / src matt / JamaPlus / SingularValueDecomposition.java @ 1900
Historique | Voir | Annoter | Télécharger (16,18 ko)
1 | 481 | mdecorde | package JamaPlus; |
---|---|---|---|
2 | 481 | mdecorde | import JamaPlus.util.*; |
3 | 481 | mdecorde | |
4 | 481 | mdecorde | /** Singular Value Decomposition.
|
5 | 481 | mdecorde | <P>
|
6 | 481 | mdecorde | For an m-by-n matrix A with m >= n, the singular value decomposition is
|
7 | 481 | mdecorde | an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
|
8 | 481 | mdecorde | an n-by-n orthogonal matrix V so that A = U*S*V'.
|
9 | 481 | mdecorde | <P>
|
10 | 481 | mdecorde | The singular values, sigma[k] = S[k][k], are ordered so that
|
11 | 481 | mdecorde | sigma[0] >= sigma[1] >= ... >= sigma[n-1].
|
12 | 481 | mdecorde | <P>
|
13 | 481 | mdecorde | The singular value decompostion always exists, so the constructor will
|
14 | 481 | mdecorde | never fail. The matrix condition number and the effective numerical
|
15 | 481 | mdecorde | rank can be computed from this decomposition.
|
16 | 481 | mdecorde | */
|
17 | 481 | mdecorde | |
18 | 481 | mdecorde | public class SingularValueDecomposition implements java.io.Serializable { |
19 | 481 | mdecorde | |
20 | 481 | mdecorde | /* ------------------------
|
21 | 481 | mdecorde | Class variables
|
22 | 481 | mdecorde | * ------------------------ */
|
23 | 481 | mdecorde | |
24 | 481 | mdecorde | /** Arrays for internal storage of U and V.
|
25 | 481 | mdecorde | @serial internal storage of U.
|
26 | 481 | mdecorde | @serial internal storage of V.
|
27 | 481 | mdecorde | */
|
28 | 481 | mdecorde | private double[][] U, V; |
29 | 481 | mdecorde | |
30 | 481 | mdecorde | /** Array for internal storage of singular values.
|
31 | 481 | mdecorde | @serial internal storage of singular values.
|
32 | 481 | mdecorde | */
|
33 | 481 | mdecorde | private double[] s; |
34 | 481 | mdecorde | |
35 | 481 | mdecorde | /** Row and column dimensions.
|
36 | 481 | mdecorde | @serial row dimension.
|
37 | 481 | mdecorde | @serial column dimension.
|
38 | 481 | mdecorde | */
|
39 | 481 | mdecorde | private int m, n; |
40 | 481 | mdecorde | |
41 | 481 | mdecorde | private boolean transpose; // pour éviter les bugs quand m<n (cf.ci-dessous) |
42 | 481 | mdecorde | |
43 | 481 | mdecorde | /* ------------------------
|
44 | 481 | mdecorde | Constructor
|
45 | 481 | mdecorde | * ------------------------ */
|
46 | 481 | mdecorde | |
47 | 481 | mdecorde | /** Construct the singular value decomposition
|
48 | 481 | mdecorde | @param A Rectangular matrix
|
49 | 481 | mdecorde | @return Structure to access U, S and V.
|
50 | 481 | mdecorde | */
|
51 | 481 | mdecorde | |
52 | 481 | mdecorde | public SingularValueDecomposition (Matrix Arg) {
|
53 | 481 | mdecorde | |
54 | 481 | mdecorde | // Derived from LINPACK code.
|
55 | 481 | mdecorde | // Initialize.
|
56 | 481 | mdecorde | /* Apparently the failing cases are only a proper subset of (m<n),
|
57 | 481 | mdecorde | so let's not throw error. Correct fix to come later?
|
58 | 481 | mdecorde | if (m<n) {
|
59 | 481 | mdecorde | throw new IllegalArgumentException("Jama SVD only works for m >= n"); }
|
60 | 481 | mdecorde | */
|
61 | 481 | mdecorde | /*
|
62 | 481 | mdecorde | * Une façon très simple de contourner le problème ci-dessus :
|
63 | 481 | mdecorde | * si m < n on transpose A
|
64 | 481 | mdecorde | * (ce qui revient à échanger U et V, S restant inchangé)
|
65 | 481 | mdecorde | */
|
66 | 481 | mdecorde | transpose = Arg.getColumnDimension()>Arg.getRowDimension(); |
67 | 481 | mdecorde | Matrix M = transpose ? Arg.transpose() : Arg.copy(); |
68 | 481 | mdecorde | |
69 | 481 | mdecorde | double[][] A = M.getArray(); |
70 | 481 | mdecorde | m = M.getRowDimension(); |
71 | 481 | mdecorde | n = M.getColumnDimension(); |
72 | 481 | mdecorde | |
73 | 481 | mdecorde | s = new double [n]; |
74 | 481 | mdecorde | U = new double [m][n]; |
75 | 481 | mdecorde | V = new double [n][n]; |
76 | 481 | mdecorde | double[] e = new double [n]; |
77 | 481 | mdecorde | double[] work = new double [m]; |
78 | 481 | mdecorde | boolean wantu = true; |
79 | 481 | mdecorde | boolean wantv = true; |
80 | 481 | mdecorde | |
81 | 481 | mdecorde | // Reduce A to bidiagonal form, storing the diagonal elements
|
82 | 481 | mdecorde | // in s and the super-diagonal elements in e.
|
83 | 481 | mdecorde | |
84 | 481 | mdecorde | int nct = Math.min(m-1,n); |
85 | 481 | mdecorde | int nrt = Math.max(0,Math.min(n-2,m)); |
86 | 481 | mdecorde | for (int k = 0; k < Math.max(nct,nrt); k++) { |
87 | 481 | mdecorde | if (k < nct) {
|
88 | 481 | mdecorde | |
89 | 481 | mdecorde | // Compute the transformation for the k-th column and
|
90 | 481 | mdecorde | // place the k-th diagonal in s[k].
|
91 | 481 | mdecorde | // Compute 2-norm of k-th column without under/overflow.
|
92 | 481 | mdecorde | s[k] = 0;
|
93 | 481 | mdecorde | for (int i = k; i < m; i++) { |
94 | 481 | mdecorde | s[k] = Math.hypot(s[k],A[i][k]);
|
95 | 481 | mdecorde | } |
96 | 481 | mdecorde | if (s[k] != 0.0) { |
97 | 481 | mdecorde | if (A[k][k] < 0.0) { |
98 | 481 | mdecorde | s[k] = -s[k]; |
99 | 481 | mdecorde | } |
100 | 481 | mdecorde | for (int i = k; i < m; i++) { |
101 | 481 | mdecorde | A[i][k] /= s[k]; |
102 | 481 | mdecorde | } |
103 | 481 | mdecorde | A[k][k] += 1.0;
|
104 | 481 | mdecorde | } |
105 | 481 | mdecorde | s[k] = -s[k]; |
106 | 481 | mdecorde | } |
107 | 481 | mdecorde | for (int j = k+1; j < n; j++) { |
108 | 481 | mdecorde | if ((k < nct) & (s[k] != 0.0)) { |
109 | 481 | mdecorde | |
110 | 481 | mdecorde | // Apply the transformation.
|
111 | 481 | mdecorde | |
112 | 481 | mdecorde | double t = 0; |
113 | 481 | mdecorde | for (int i = k; i < m; i++) { |
114 | 481 | mdecorde | t += A[i][k]*A[i][j]; |
115 | 481 | mdecorde | } |
116 | 481 | mdecorde | t = -t/A[k][k]; |
117 | 481 | mdecorde | for (int i = k; i < m; i++) { |
118 | 481 | mdecorde | A[i][j] += t*A[i][k]; |
119 | 481 | mdecorde | } |
120 | 481 | mdecorde | } |
121 | 481 | mdecorde | |
122 | 481 | mdecorde | // Place the k-th row of A into e for the
|
123 | 481 | mdecorde | // subsequent calculation of the row transformation.
|
124 | 481 | mdecorde | |
125 | 481 | mdecorde | e[j] = A[k][j]; |
126 | 481 | mdecorde | } |
127 | 481 | mdecorde | if (wantu & (k < nct)) {
|
128 | 481 | mdecorde | |
129 | 481 | mdecorde | // Place the transformation in U for subsequent back
|
130 | 481 | mdecorde | // multiplication.
|
131 | 481 | mdecorde | |
132 | 481 | mdecorde | for (int i = k; i < m; i++) { |
133 | 481 | mdecorde | U[i][k] = A[i][k]; |
134 | 481 | mdecorde | } |
135 | 481 | mdecorde | } |
136 | 481 | mdecorde | if (k < nrt) {
|
137 | 481 | mdecorde | |
138 | 481 | mdecorde | // Compute the k-th row transformation and place the
|
139 | 481 | mdecorde | // k-th super-diagonal in e[k].
|
140 | 481 | mdecorde | // Compute 2-norm without under/overflow.
|
141 | 481 | mdecorde | e[k] = 0;
|
142 | 481 | mdecorde | for (int i = k+1; i < n; i++) { |
143 | 481 | mdecorde | e[k] = Math.hypot(e[k],e[i]);
|
144 | 481 | mdecorde | } |
145 | 481 | mdecorde | if (e[k] != 0.0) { |
146 | 481 | mdecorde | if (e[k+1] < 0.0) { |
147 | 481 | mdecorde | e[k] = -e[k]; |
148 | 481 | mdecorde | } |
149 | 481 | mdecorde | for (int i = k+1; i < n; i++) { |
150 | 481 | mdecorde | e[i] /= e[k]; |
151 | 481 | mdecorde | } |
152 | 481 | mdecorde | e[k+1] += 1.0; |
153 | 481 | mdecorde | } |
154 | 481 | mdecorde | e[k] = -e[k]; |
155 | 481 | mdecorde | if ((k+1 < m) & (e[k] != 0.0)) { |
156 | 481 | mdecorde | |
157 | 481 | mdecorde | // Apply the transformation.
|
158 | 481 | mdecorde | |
159 | 481 | mdecorde | for (int i = k+1; i < m; i++) { |
160 | 481 | mdecorde | work[i] = 0.0;
|
161 | 481 | mdecorde | } |
162 | 481 | mdecorde | for (int j = k+1; j < n; j++) { |
163 | 481 | mdecorde | for (int i = k+1; i < m; i++) { |
164 | 481 | mdecorde | work[i] += e[j]*A[i][j]; |
165 | 481 | mdecorde | } |
166 | 481 | mdecorde | } |
167 | 481 | mdecorde | for (int j = k+1; j < n; j++) { |
168 | 481 | mdecorde | double t = -e[j]/e[k+1]; |
169 | 481 | mdecorde | for (int i = k+1; i < m; i++) { |
170 | 481 | mdecorde | A[i][j] += t*work[i]; |
171 | 481 | mdecorde | } |
172 | 481 | mdecorde | } |
173 | 481 | mdecorde | } |
174 | 481 | mdecorde | if (wantv) {
|
175 | 481 | mdecorde | |
176 | 481 | mdecorde | // Place the transformation in V for subsequent
|
177 | 481 | mdecorde | // back multiplication.
|
178 | 481 | mdecorde | |
179 | 481 | mdecorde | for (int i = k+1; i < n; i++) { |
180 | 481 | mdecorde | V[i][k] = e[i]; |
181 | 481 | mdecorde | } |
182 | 481 | mdecorde | } |
183 | 481 | mdecorde | } |
184 | 481 | mdecorde | } |
185 | 481 | mdecorde | |
186 | 481 | mdecorde | // Set up the final bidiagonal matrix or order p.
|
187 | 481 | mdecorde | |
188 | 481 | mdecorde | int p = Math.min(n,m+1); |
189 | 481 | mdecorde | if (nct < n) {
|
190 | 481 | mdecorde | s[nct] = A[nct][nct]; |
191 | 481 | mdecorde | } |
192 | 481 | mdecorde | if (m < p) {
|
193 | 481 | mdecorde | s[p-1] = 0.0; |
194 | 481 | mdecorde | } |
195 | 481 | mdecorde | if (nrt+1 < p) { |
196 | 481 | mdecorde | e[nrt] = A[nrt][p-1];
|
197 | 481 | mdecorde | } |
198 | 481 | mdecorde | e[p-1] = 0.0; |
199 | 481 | mdecorde | |
200 | 481 | mdecorde | // If required, generate U.
|
201 | 481 | mdecorde | |
202 | 481 | mdecorde | if (wantu) {
|
203 | 481 | mdecorde | for (int j = nct; j < n; j++) { |
204 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
205 | 481 | mdecorde | U[i][j] = 0.0;
|
206 | 481 | mdecorde | } |
207 | 481 | mdecorde | U[j][j] = 1.0;
|
208 | 481 | mdecorde | } |
209 | 481 | mdecorde | for (int k = nct-1; k >= 0; k--) { |
210 | 481 | mdecorde | if (s[k] != 0.0) { |
211 | 481 | mdecorde | for (int j = k+1; j < n; j++) { |
212 | 481 | mdecorde | double t = 0; |
213 | 481 | mdecorde | for (int i = k; i < m; i++) { |
214 | 481 | mdecorde | t += U[i][k]*U[i][j]; |
215 | 481 | mdecorde | } |
216 | 481 | mdecorde | t = -t/U[k][k]; |
217 | 481 | mdecorde | for (int i = k; i < m; i++) { |
218 | 481 | mdecorde | U[i][j] += t*U[i][k]; |
219 | 481 | mdecorde | } |
220 | 481 | mdecorde | } |
221 | 481 | mdecorde | for (int i = k; i < m; i++ ) { |
222 | 481 | mdecorde | U[i][k] = -U[i][k]; |
223 | 481 | mdecorde | } |
224 | 481 | mdecorde | U[k][k] = 1.0 + U[k][k];
|
225 | 481 | mdecorde | for (int i = 0; i < k-1; i++) { |
226 | 481 | mdecorde | U[i][k] = 0.0;
|
227 | 481 | mdecorde | } |
228 | 481 | mdecorde | } else {
|
229 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
230 | 481 | mdecorde | U[i][k] = 0.0;
|
231 | 481 | mdecorde | } |
232 | 481 | mdecorde | U[k][k] = 1.0;
|
233 | 481 | mdecorde | } |
234 | 481 | mdecorde | } |
235 | 481 | mdecorde | } |
236 | 481 | mdecorde | |
237 | 481 | mdecorde | // If required, generate V.
|
238 | 481 | mdecorde | |
239 | 481 | mdecorde | if (wantv) {
|
240 | 481 | mdecorde | for (int k = n-1; k >= 0; k--) { |
241 | 481 | mdecorde | if ((k < nrt) & (e[k] != 0.0)) { |
242 | 481 | mdecorde | for (int j = k+1; j < n; j++) { |
243 | 481 | mdecorde | double t = 0; |
244 | 481 | mdecorde | for (int i = k+1; i < n; i++) { |
245 | 481 | mdecorde | t += V[i][k]*V[i][j]; |
246 | 481 | mdecorde | } |
247 | 481 | mdecorde | t = -t/V[k+1][k];
|
248 | 481 | mdecorde | for (int i = k+1; i < n; i++) { |
249 | 481 | mdecorde | V[i][j] += t*V[i][k]; |
250 | 481 | mdecorde | } |
251 | 481 | mdecorde | } |
252 | 481 | mdecorde | } |
253 | 481 | mdecorde | for (int i = 0; i < n; i++) { |
254 | 481 | mdecorde | V[i][k] = 0.0;
|
255 | 481 | mdecorde | } |
256 | 481 | mdecorde | V[k][k] = 1.0;
|
257 | 481 | mdecorde | } |
258 | 481 | mdecorde | } |
259 | 481 | mdecorde | |
260 | 481 | mdecorde | // Main iteration loop for the singular values.
|
261 | 481 | mdecorde | |
262 | 481 | mdecorde | int pp = p-1; |
263 | 481 | mdecorde | int iter = 0; |
264 | 481 | mdecorde | double eps = Math.pow(2.0,-52.0); |
265 | 481 | mdecorde | double tiny = Math.pow(2.0,-966.0); |
266 | 481 | mdecorde | while (p > 0) { |
267 | 481 | mdecorde | int k,kase;
|
268 | 481 | mdecorde | |
269 | 481 | mdecorde | // Here is where a test for too many iterations would go.
|
270 | 481 | mdecorde | |
271 | 481 | mdecorde | // This section of the program inspects for
|
272 | 481 | mdecorde | // negligible elements in the s and e arrays. On
|
273 | 481 | mdecorde | // completion the variables kase and k are set as follows.
|
274 | 481 | mdecorde | |
275 | 481 | mdecorde | // kase = 1 if s(p) and e[k-1] are negligible and k<p
|
276 | 481 | mdecorde | // kase = 2 if s(k) is negligible and k<p
|
277 | 481 | mdecorde | // kase = 3 if e[k-1] is negligible, k<p, and
|
278 | 481 | mdecorde | // s(k), ..., s(p) are not negligible (qr step).
|
279 | 481 | mdecorde | // kase = 4 if e(p-1) is negligible (convergence).
|
280 | 481 | mdecorde | |
281 | 481 | mdecorde | for (k = p-2; k >= -1; k--) { |
282 | 481 | mdecorde | if (k == -1) { |
283 | 481 | mdecorde | break;
|
284 | 481 | mdecorde | } |
285 | 481 | mdecorde | if (Math.abs(e[k]) <= |
286 | 481 | mdecorde | tiny + eps*(Math.abs(s[k]) + Math.abs(s[k+1]))) { |
287 | 481 | mdecorde | e[k] = 0.0;
|
288 | 481 | mdecorde | break;
|
289 | 481 | mdecorde | } |
290 | 481 | mdecorde | } |
291 | 481 | mdecorde | if (k == p-2) { |
292 | 481 | mdecorde | kase = 4;
|
293 | 481 | mdecorde | } else {
|
294 | 481 | mdecorde | int ks;
|
295 | 481 | mdecorde | for (ks = p-1; ks >= k; ks--) { |
296 | 481 | mdecorde | if (ks == k) {
|
297 | 481 | mdecorde | break;
|
298 | 481 | mdecorde | } |
299 | 481 | mdecorde | double t = (ks != p ? Math.abs(e[ks]) : 0.) + |
300 | 481 | mdecorde | (ks != k+1 ? Math.abs(e[ks-1]) : 0.); |
301 | 481 | mdecorde | if (Math.abs(s[ks]) <= tiny + eps*t) { |
302 | 481 | mdecorde | s[ks] = 0.0;
|
303 | 481 | mdecorde | break;
|
304 | 481 | mdecorde | } |
305 | 481 | mdecorde | } |
306 | 481 | mdecorde | if (ks == k) {
|
307 | 481 | mdecorde | kase = 3;
|
308 | 481 | mdecorde | } else if (ks == p-1) { |
309 | 481 | mdecorde | kase = 1;
|
310 | 481 | mdecorde | } else {
|
311 | 481 | mdecorde | kase = 2;
|
312 | 481 | mdecorde | k = ks; |
313 | 481 | mdecorde | } |
314 | 481 | mdecorde | } |
315 | 481 | mdecorde | k++; |
316 | 481 | mdecorde | |
317 | 481 | mdecorde | // Perform the task indicated by kase.
|
318 | 481 | mdecorde | |
319 | 481 | mdecorde | switch (kase) {
|
320 | 481 | mdecorde | |
321 | 481 | mdecorde | // Deflate negligible s(p).
|
322 | 481 | mdecorde | |
323 | 481 | mdecorde | case 1: { |
324 | 481 | mdecorde | double f = e[p-2]; |
325 | 481 | mdecorde | e[p-2] = 0.0; |
326 | 481 | mdecorde | for (int j = p-2; j >= k; j--) { |
327 | 481 | mdecorde | double t = Math.hypot(s[j],f); |
328 | 481 | mdecorde | double cs = s[j]/t;
|
329 | 481 | mdecorde | double sn = f/t;
|
330 | 481 | mdecorde | s[j] = t; |
331 | 481 | mdecorde | if (j != k) {
|
332 | 481 | mdecorde | f = -sn*e[j-1];
|
333 | 481 | mdecorde | e[j-1] = cs*e[j-1]; |
334 | 481 | mdecorde | } |
335 | 481 | mdecorde | if (wantv) {
|
336 | 481 | mdecorde | for (int i = 0; i < n; i++) { |
337 | 481 | mdecorde | t = cs*V[i][j] + sn*V[i][p-1];
|
338 | 481 | mdecorde | V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1]; |
339 | 481 | mdecorde | V[i][j] = t; |
340 | 481 | mdecorde | } |
341 | 481 | mdecorde | } |
342 | 481 | mdecorde | } |
343 | 481 | mdecorde | } |
344 | 481 | mdecorde | break;
|
345 | 481 | mdecorde | |
346 | 481 | mdecorde | // Split at negligible s(k).
|
347 | 481 | mdecorde | |
348 | 481 | mdecorde | case 2: { |
349 | 481 | mdecorde | double f = e[k-1]; |
350 | 481 | mdecorde | e[k-1] = 0.0; |
351 | 481 | mdecorde | for (int j = k; j < p; j++) { |
352 | 481 | mdecorde | double t = Math.hypot(s[j],f); |
353 | 481 | mdecorde | double cs = s[j]/t;
|
354 | 481 | mdecorde | double sn = f/t;
|
355 | 481 | mdecorde | s[j] = t; |
356 | 481 | mdecorde | f = -sn*e[j]; |
357 | 481 | mdecorde | e[j] = cs*e[j]; |
358 | 481 | mdecorde | if (wantu) {
|
359 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
360 | 481 | mdecorde | t = cs*U[i][j] + sn*U[i][k-1];
|
361 | 481 | mdecorde | U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1]; |
362 | 481 | mdecorde | U[i][j] = t; |
363 | 481 | mdecorde | } |
364 | 481 | mdecorde | } |
365 | 481 | mdecorde | } |
366 | 481 | mdecorde | } |
367 | 481 | mdecorde | break;
|
368 | 481 | mdecorde | |
369 | 481 | mdecorde | // Perform one qr step.
|
370 | 481 | mdecorde | |
371 | 481 | mdecorde | case 3: { |
372 | 481 | mdecorde | |
373 | 481 | mdecorde | // Calculate the shift.
|
374 | 481 | mdecorde | |
375 | 481 | mdecorde | double scale = Math.max(Math.max(Math.max(Math.max( |
376 | 481 | mdecorde | Math.abs(s[p-1]),Math.abs(s[p-2])),Math.abs(e[p-2])), |
377 | 481 | mdecorde | Math.abs(s[k])),Math.abs(e[k])); |
378 | 481 | mdecorde | double sp = s[p-1]/scale; |
379 | 481 | mdecorde | double spm1 = s[p-2]/scale; |
380 | 481 | mdecorde | double epm1 = e[p-2]/scale; |
381 | 481 | mdecorde | double sk = s[k]/scale;
|
382 | 481 | mdecorde | double ek = e[k]/scale;
|
383 | 481 | mdecorde | double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; |
384 | 481 | mdecorde | double c = (sp*epm1)*(sp*epm1);
|
385 | 481 | mdecorde | double shift = 0.0; |
386 | 481 | mdecorde | if ((b != 0.0) | (c != 0.0)) { |
387 | 481 | mdecorde | shift = Math.sqrt(b*b + c);
|
388 | 481 | mdecorde | if (b < 0.0) { |
389 | 481 | mdecorde | shift = -shift; |
390 | 481 | mdecorde | } |
391 | 481 | mdecorde | shift = c/(b + shift); |
392 | 481 | mdecorde | } |
393 | 481 | mdecorde | double f = (sk + sp)*(sk - sp) + shift;
|
394 | 481 | mdecorde | double g = sk*ek;
|
395 | 481 | mdecorde | |
396 | 481 | mdecorde | // Chase zeros.
|
397 | 481 | mdecorde | |
398 | 481 | mdecorde | for (int j = k; j < p-1; j++) { |
399 | 481 | mdecorde | double t = Math.hypot(f,g); |
400 | 481 | mdecorde | double cs = f/t;
|
401 | 481 | mdecorde | double sn = g/t;
|
402 | 481 | mdecorde | if (j != k) {
|
403 | 481 | mdecorde | e[j-1] = t;
|
404 | 481 | mdecorde | } |
405 | 481 | mdecorde | f = cs*s[j] + sn*e[j]; |
406 | 481 | mdecorde | e[j] = cs*e[j] - sn*s[j]; |
407 | 481 | mdecorde | g = sn*s[j+1];
|
408 | 481 | mdecorde | s[j+1] = cs*s[j+1]; |
409 | 481 | mdecorde | if (wantv) {
|
410 | 481 | mdecorde | for (int i = 0; i < n; i++) { |
411 | 481 | mdecorde | t = cs*V[i][j] + sn*V[i][j+1];
|
412 | 481 | mdecorde | V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1]; |
413 | 481 | mdecorde | V[i][j] = t; |
414 | 481 | mdecorde | } |
415 | 481 | mdecorde | } |
416 | 481 | mdecorde | t = Math.hypot(f,g);
|
417 | 481 | mdecorde | cs = f/t; |
418 | 481 | mdecorde | sn = g/t; |
419 | 481 | mdecorde | s[j] = t; |
420 | 481 | mdecorde | f = cs*e[j] + sn*s[j+1];
|
421 | 481 | mdecorde | s[j+1] = -sn*e[j] + cs*s[j+1]; |
422 | 481 | mdecorde | g = sn*e[j+1];
|
423 | 481 | mdecorde | e[j+1] = cs*e[j+1]; |
424 | 481 | mdecorde | if (wantu && (j < m-1)) { |
425 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
426 | 481 | mdecorde | t = cs*U[i][j] + sn*U[i][j+1];
|
427 | 481 | mdecorde | U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1]; |
428 | 481 | mdecorde | U[i][j] = t; |
429 | 481 | mdecorde | } |
430 | 481 | mdecorde | } |
431 | 481 | mdecorde | } |
432 | 481 | mdecorde | e[p-2] = f;
|
433 | 481 | mdecorde | iter = iter + 1;
|
434 | 481 | mdecorde | } |
435 | 481 | mdecorde | break;
|
436 | 481 | mdecorde | |
437 | 481 | mdecorde | // Convergence.
|
438 | 481 | mdecorde | |
439 | 481 | mdecorde | case 4: { |
440 | 481 | mdecorde | |
441 | 481 | mdecorde | // Make the singular values positive.
|
442 | 481 | mdecorde | |
443 | 481 | mdecorde | if (s[k] <= 0.0) { |
444 | 481 | mdecorde | s[k] = (s[k] < 0.0 ? -s[k] : 0.0); |
445 | 481 | mdecorde | if (wantv) {
|
446 | 481 | mdecorde | for (int i = 0; i <= pp; i++) { |
447 | 481 | mdecorde | V[i][k] = -V[i][k]; |
448 | 481 | mdecorde | } |
449 | 481 | mdecorde | } |
450 | 481 | mdecorde | } |
451 | 481 | mdecorde | |
452 | 481 | mdecorde | // Order the singular values.
|
453 | 481 | mdecorde | |
454 | 481 | mdecorde | while (k < pp) {
|
455 | 481 | mdecorde | if (s[k] >= s[k+1]) { |
456 | 481 | mdecorde | break;
|
457 | 481 | mdecorde | } |
458 | 481 | mdecorde | double t = s[k];
|
459 | 481 | mdecorde | s[k] = s[k+1];
|
460 | 481 | mdecorde | s[k+1] = t;
|
461 | 481 | mdecorde | if (wantv && (k < n-1)) { |
462 | 481 | mdecorde | for (int i = 0; i < n; i++) { |
463 | 481 | mdecorde | t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t; |
464 | 481 | mdecorde | } |
465 | 481 | mdecorde | } |
466 | 481 | mdecorde | if (wantu && (k < m-1)) { |
467 | 481 | mdecorde | for (int i = 0; i < m; i++) { |
468 | 481 | mdecorde | t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t; |
469 | 481 | mdecorde | } |
470 | 481 | mdecorde | } |
471 | 481 | mdecorde | k++; |
472 | 481 | mdecorde | } |
473 | 481 | mdecorde | iter = 0;
|
474 | 481 | mdecorde | p--; |
475 | 481 | mdecorde | } |
476 | 481 | mdecorde | break;
|
477 | 481 | mdecorde | } |
478 | 481 | mdecorde | } |
479 | 481 | mdecorde | } |
480 | 481 | mdecorde | |
481 | 481 | mdecorde | /* ------------------------
|
482 | 481 | mdecorde | Public Methods
|
483 | 481 | mdecorde | * ------------------------ */
|
484 | 481 | mdecorde | |
485 | 481 | mdecorde | /** Return the left singular vectors
|
486 | 481 | mdecorde | @return U
|
487 | 481 | mdecorde | */
|
488 | 481 | mdecorde | |
489 | 481 | mdecorde | public Matrix getU () {
|
490 | 481 | mdecorde | return transpose ? new Matrix(V,n,n) : new Matrix(U,m,n); |
491 | 481 | mdecorde | } |
492 | 481 | mdecorde | |
493 | 481 | mdecorde | /** Return the right singular vectors
|
494 | 481 | mdecorde | @return V
|
495 | 481 | mdecorde | */
|
496 | 481 | mdecorde | |
497 | 481 | mdecorde | public Matrix getV () {
|
498 | 481 | mdecorde | return transpose ? new Matrix(U,m,n) : new Matrix(V,n,n); |
499 | 481 | mdecorde | } |
500 | 481 | mdecorde | |
501 | 481 | mdecorde | /** Return the one-dimensional array of singular values
|
502 | 481 | mdecorde | @return diagonal of S.
|
503 | 481 | mdecorde | */
|
504 | 481 | mdecorde | |
505 | 481 | mdecorde | public double[] getSingularValues () { |
506 | 481 | mdecorde | return s;
|
507 | 481 | mdecorde | } |
508 | 481 | mdecorde | |
509 | 481 | mdecorde | /** Return the diagonal matrix of singular values
|
510 | 481 | mdecorde | @return S
|
511 | 481 | mdecorde | */
|
512 | 481 | mdecorde | |
513 | 481 | mdecorde | public Matrix getS () {
|
514 | 481 | mdecorde | Matrix X = new Matrix(n,n);
|
515 | 481 | mdecorde | double[][] S = X.getArray(); |
516 | 481 | mdecorde | for (int i = 0; i < n; i++) { |
517 | 481 | mdecorde | for (int j = 0; j < n; j++) { |
518 | 481 | mdecorde | S[i][j] = 0.0;
|
519 | 481 | mdecorde | } |
520 | 481 | mdecorde | S[i][i] = this.s[i];
|
521 | 481 | mdecorde | } |
522 | 481 | mdecorde | return X;
|
523 | 481 | mdecorde | } |
524 | 481 | mdecorde | |
525 | 481 | mdecorde | /** Two norm
|
526 | 481 | mdecorde | @return max(S)
|
527 | 481 | mdecorde | */
|
528 | 481 | mdecorde | |
529 | 481 | mdecorde | public double norm2 () { |
530 | 481 | mdecorde | return s[0]; |
531 | 481 | mdecorde | } |
532 | 481 | mdecorde | |
533 | 481 | mdecorde | /** Two norm condition number
|
534 | 481 | mdecorde | @return max(S)/min(S)
|
535 | 481 | mdecorde | */
|
536 | 481 | mdecorde | |
537 | 481 | mdecorde | public double cond () { |
538 | 481 | mdecorde | return s[0]/s[Math.min(m,n)-1]; |
539 | 481 | mdecorde | } |
540 | 481 | mdecorde | |
541 | 481 | mdecorde | /** Effective numerical matrix rank
|
542 | 481 | mdecorde | @return Number of nonnegligible singular values.
|
543 | 481 | mdecorde | */
|
544 | 481 | mdecorde | |
545 | 481 | mdecorde | public int rank () { |
546 | 481 | mdecorde | double eps = Math.pow(2.0,-52.0); |
547 | 481 | mdecorde | double tol = Math.max(m,n)*s[0]*eps; |
548 | 481 | mdecorde | int r = 0; |
549 | 481 | mdecorde | for (int i = 0; i < s.length; i++) { |
550 | 481 | mdecorde | if (s[i] > tol) {
|
551 | 481 | mdecorde | r++; |
552 | 481 | mdecorde | } |
553 | 481 | mdecorde | } |
554 | 481 | mdecorde | return r;
|
555 | 481 | mdecorde | } |
556 | 481 | mdecorde | } |