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