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