00001 //http://perso.orange.fr/jean-pierre.moreau/c_matrices.html 00002 /* ----------------------- MODULE feigen.cpp ------------------------ * 00003 * Reference: "Numerical Algorithms with C By G. Engeln-Mueller and * 00004 * F. Uhlig, Springer-Verlag, 1996" [BIBLI 11]. * 00005 * ------------------------------------------------------------------ */ 00006 #include <basis.h> 00007 #include <vmblock.h> 00008 00009 00010 #define MAXIT 50 /* Maximal number of */ 00011 /* iterations per eigenvalue */ 00012 00013 /*--------------------------------------------------------------------* 00014 * Auxiliary functions for eigen * 00015 *--------------------------------------------------------------------*/ 00016 00017 00018 static int balance /* balance a matrix .........................*/ 00019 (int n, /* size of matrix ..............*/ 00020 REAL * mat[], /* matrix ......................*/ 00021 REAL scal[], /* Scaling data ................*/ 00022 int * low, /* first relevant row index ....*/ 00023 int * high, /* last relevant row index .....*/ 00024 int basis /* base of computer numbers ....*/ 00025 ) 00026 /*====================================================================* 00027 * * 00028 * balance balances the matrix mat so that the rows with zero entries* 00029 * off the diagonal are isolated and the remaining columns and rows * 00030 * are resized to have one norm close to 1. * 00031 * * 00032 *====================================================================* 00033 * * 00034 * Input parameters: * 00035 * ================ * 00036 * n int n; ( n > 0 ) * 00037 * Dimension of mat * 00038 * mat REAL *mat[n]; * 00039 * n x n input matrix * 00040 * basis int basis; * 00041 * Base of number representaion in the given computer * 00042 * (see BASIS) * 00043 * * 00044 * Output parameters: * 00045 * ================== * 00046 * mat REAL *mat[n]; * 00047 * scaled matrix * 00048 * low int *low; * 00049 * high int *high; * 00050 * the rows 0 to low-1 and those from high to n-1 * 00051 * contain isolated eigenvalues (only nonzero entry on * 00052 * the diagonal) * 00053 * scal REAL scal[]; * 00054 * the vector scal contains the isolated eigenvalues in * 00055 * the positions 0 to low-1 and high to n-1, its other * 00056 * components contain the scaling factors for * 00057 * transforming mat. * 00058 * * 00059 *====================================================================* 00060 * * 00061 * Macros: SWAP, ABS * 00062 * ======= * 00063 * * 00064 *====================================================================* 00065 * * 00066 * Constants used: TRUE, FALSE * 00067 * ============== * 00068 * * 00069 *====================================================================*/ 00070 { 00071 register int i, j; 00072 int iter, k, m; 00073 REAL b2, r, c, f, g, s; 00074 00075 b2 = (REAL) (basis * basis); 00076 m = 0; 00077 k = n - 1; 00078 00079 do 00080 { 00081 iter = FALSE; 00082 for (j = k; j >= 0; j--) 00083 { 00084 for (r = ZERO, i = 0; i <= k; i++) 00085 if (i != j) r += ABS (mat[j][i]); 00086 00087 if (r == ZERO) 00088 { 00089 scal[k] = (REAL) j; 00090 if (j != k) 00091 { 00092 for (i = 0; i <= k; i++) SWAP (REAL, mat[i][j], mat[i][k]) 00093 for (i = m; i < n; i++) SWAP (REAL, mat[j][i], mat[k][i]) 00094 } 00095 k--; 00096 iter = TRUE; 00097 } 00098 } /* end of j */ 00099 } /* end of do */ 00100 while (iter); 00101 00102 do 00103 { 00104 iter = FALSE; 00105 for (j = m; j <= k; j++) 00106 { 00107 for (c = ZERO, i = m; i <= k; i++) 00108 if (i != j) c += ABS (mat[i][j]); 00109 if (c == ZERO) 00110 { 00111 scal[m] = (REAL) j; 00112 if ( j != m ) 00113 { 00114 for (i = 0; i <= k; i++) SWAP (REAL, mat[i][j], mat[i][m]) 00115 for (i = m; i < n; i++) SWAP (REAL, mat[j][i], mat[m][i]) 00116 } 00117 m++; 00118 iter = TRUE; 00119 } 00120 } /* end of j */ 00121 } /* end of do */ 00122 while (iter); 00123 00124 *low = m; 00125 *high = k; 00126 for (i = m; i <= k; i++) scal[i] = ONE; 00127 00128 do 00129 { 00130 iter = FALSE; 00131 for (i = m; i <= k; i++) 00132 { 00133 for (c = r = ZERO, j = m; j <= k; j++) 00134 if (j !=i) 00135 { 00136 c += ABS (mat[j][i]); 00137 r += ABS (mat[i][j]); 00138 } 00139 g = r / basis; 00140 f = ONE; 00141 s = c + r; 00142 00143 while (c < g) 00144 { 00145 f *= basis; 00146 c *= b2; 00147 } 00148 00149 g = r * basis; 00150 while (c >= g) 00151 { 00152 f /= basis; 00153 c /= b2; 00154 } 00155 00156 if ((c + r) / f < (REAL)0.95 * s) 00157 { 00158 g = ONE / f; 00159 scal[i] *= f; 00160 iter = TRUE; 00161 for (j = m; j < n; j++ ) mat[i][j] *= g; 00162 for (j = 0; j <= k; j++ ) mat[j][i] *= f; 00163 } 00164 } 00165 } 00166 while (iter); 00167 00168 return (0); 00169 } 00170 00171 00172 static int balback /* reverse balancing ........................*/ 00173 (int n, /* Dimension of matrix .........*/ 00174 int low, /* first nonzero row ...........*/ 00175 int high, /* last nonzero row ............*/ 00176 REAL scal[], /* Scaling data ................*/ 00177 REAL * eivec[] /* Eigenvectors ................*/ 00178 ) 00179 /*====================================================================* 00180 * * 00181 * balback reverses the balancing of balance for the eigenvactors. * 00182 * * 00183 *====================================================================* 00184 * * 00185 * Input parameters: * 00186 * ================ * 00187 * n int n; ( n > 0 ) * 00188 * Dimension of mat * 00189 * low int low; * 00190 * high int high; see balance * 00191 * eivec REAL *eivec[n]; * 00192 * Matrix of eigenvectors, as computed in qr2 * 00193 * scal REAL scal[]; * 00194 * Scaling data from balance * 00195 * * 00196 * Output parameter: * 00197 * ================ * 00198 * eivec REAL *eivec[n]; * 00199 * Non-normalized eigenvectors of the original matrix * 00200 * * 00201 * Macros : SWAP() * 00202 * ======== * 00203 * * 00204 *====================================================================*/ 00205 { 00206 register int i, j, k; 00207 REAL s; 00208 00209 for (i = low; i <= high; i++) 00210 { 00211 s = scal[i]; 00212 for (j = 0; j < n; j++) eivec[i][j] *= s; 00213 } 00214 00215 for (i = low - 1; i >= 0; i--) 00216 { 00217 k = (int) scal[i]; 00218 if (k != i) 00219 for (j = 0; j < n; j++) SWAP (REAL, eivec[i][j], eivec[k][j]) 00220 } 00221 00222 for (i = high + 1; i < n; i++) 00223 { 00224 k = (int) scal[i]; 00225 if (k != i) 00226 for (j = 0; j < n; j++) SWAP (REAL, eivec[i][j], eivec[k][j]) 00227 } 00228 return (0); 00229 } 00230 00231 00232 00233 static int elmhes /* reduce matrix to upper Hessenberg form ....*/ 00234 (int n, /* Dimension of matrix .........*/ 00235 int low, /* first nonzero row ...........*/ 00236 int high, /* last nonzero row ............*/ 00237 REAL * mat[], /* input/output matrix .........*/ 00238 int perm[] /* Permutation vector ..........*/ 00239 ) 00240 /*====================================================================* 00241 * * 00242 * elmhes transforms the matrix mat to upper Hessenberg form. * 00243 * * 00244 *====================================================================* 00245 * * 00246 * Input parameters: * 00247 * ================ * 00248 * n int n; ( n > 0 ) * 00249 * Dimension of mat * 00250 * low int low; * 00251 * high int high; see balance * 00252 * mat REAL *mat[n]; * 00253 * n x n matrix * 00254 * * 00255 * Output parameter: * 00256 * ================= * 00257 * mat REAL *mat[n]; * 00258 * upper Hessenberg matrix; additional information on * 00259 * the transformation is stored in the lower triangle * 00260 * perm int perm[]; * 00261 * Permutation vector for elmtrans * 00262 * * 00263 *====================================================================* 00264 * * 00265 * Macros: SWAP, ABS * 00266 * ======= * 00267 * * 00268 *====================================================================*/ 00269 { 00270 register int i, j, m; 00271 REAL x, y; 00272 00273 for (m = low + 1; m < high; m++) 00274 { 00275 i = m; 00276 x = ZERO; 00277 for (j = m; j <= high; j++) 00278 if (ABS (mat[j][m-1]) > ABS (x)) 00279 { 00280 x = mat[j][m-1]; 00281 i = j; 00282 } 00283 00284 perm[m] = i; 00285 if (i != m) 00286 { 00287 for (j = m - 1; j < n; j++) SWAP (REAL, mat[i][j], mat[m][j]) 00288 for (j = 0; j <= high; j++) SWAP (REAL, mat[j][i], mat[j][m]) 00289 } 00290 00291 if (x != ZERO) 00292 { 00293 for (i = m + 1; i <= high; i++) 00294 { 00295 y = mat[i][m-1]; 00296 if (y != ZERO) 00297 { 00298 y = mat[i][m-1] = y / x; 00299 for (j = m; j < n; j++) mat[i][j] -= y * mat[m][j]; 00300 for (j = 0; j <= high; j++) mat[j][m] += y * mat[j][i]; 00301 } 00302 } /* end i */ 00303 } 00304 } /* end m */ 00305 00306 return (0); 00307 } 00308 00309 00310 static int elmtrans /* copy to Hessenberg form .................*/ 00311 (int n, /* Dimension of matrix .........*/ 00312 int low, /* first nonzero row ...........*/ 00313 int high, /* last nonzero row ............*/ 00314 REAL * mat[], /* input matrix ................*/ 00315 int perm[], /* row permutations ............*/ 00316 REAL * h[] /* Hessenberg matrix ...........*/ 00317 ) 00318 /*====================================================================* 00319 * * 00320 * elmtrans copies the Hessenberg matrix stored in mat to h. * 00321 * * 00322 *====================================================================* 00323 * * 00324 * Input parameters: * 00325 * ================ * 00326 * n int n; ( n > 0 ) * 00327 * Dimension of mat and eivec * 00328 * low int low; * 00329 * high int high; see balance * 00330 * mat REAL *mat[n]; * 00331 * n x n input matrix * 00332 * perm int *perm; * 00333 * Permutation data from elmhes * 00334 * * 00335 * Output parameter: * 00336 * ================ * 00337 * h REAL *h[n]; * 00338 * Hessenberg matrix * 00339 * * 00340 *====================================================================*/ 00341 { 00342 register int k, i, j; 00343 00344 for (i = 0; i < n; i++) 00345 { 00346 for (k = 0; k < n; k++) h[i][k] = ZERO; 00347 h[i][i] = ONE; 00348 } 00349 00350 for (i = high - 1; i > low; i--) 00351 { 00352 j = perm[i]; 00353 for (k = i + 1; k <= high; k++) h[k][i] = mat[k][i-1]; 00354 if ( i != j ) 00355 { 00356 for (k = i; k <= high; k++) 00357 { 00358 h[i][k] = h[j][k]; 00359 h[j][k] = ZERO; 00360 } 00361 h[j][i] = ONE; 00362 } 00363 } 00364 00365 return (0); 00366 } 00367 00368 00369 /* ------------------------------------------------------------------ */ 00370 00371 static int orthes /* reduce orthogonally to upper Hessenberg form */ 00372 ( 00373 int n, /* Dimension of matrix */ 00374 int low, /* [low,low]..[high,high]: */ 00375 int high, /* submatrix to be reduced */ 00376 REAL *mat[], /* input/output matrix */ 00377 REAL d[] /* reduction information */ 00378 ) /* error code */ 00379 00380 /*********************************************************************** 00381 * This function reduces matrix mat to upper Hessenberg form by * 00382 * Householder transformations. All details of the transformations are * 00383 * stored in the remaining triangle of the Hessenberg matrix and in * 00384 * vector d. * 00385 * * 00386 * Input parameters: * 00387 * ================= * 00388 * n dimension of mat * 00389 * low \ rows 0 to low-1 and high+1 to n-1 contain isolated * 00390 * high > eigenvalues, i. e. eigenvalues corresponding to * 00391 * / eigenvectors that are multiples of unit vectors * 00392 * mat [0..n-1,0..n-1] matrix to be reduced * 00393 * * 00394 * Output parameters: * 00395 * ================== * 00396 * mat the desired Hessenberg matrix together with the first part * 00397 * of the reduction information below the subdiagonal * 00398 * d [0..n-1] vector with the remaining reduction information * 00399 * * 00400 * Return value: * 00401 * ============= * 00402 * Error code. This can only be the value 0 here. * 00403 * * 00404 * global names used: * 00405 * ================== * 00406 * REAL, MACH_EPS, ZERO, SQRT * 00407 * * 00408 * -------------------------------------------------------------------- * 00409 * Literature: Numerical Mathematics 12 (1968), pages 359 and 360 * 00410 ***********************************************************************/ 00411 00412 { 00413 int i, j, m; /* loop variables */ 00414 REAL s, /* Euclidian norm sigma of the subdiagonal column */ 00415 /* vector v of mat, that shall be reflected into a */ 00416 /* multiple of the unit vector e1 = (1,0,...,0) */ 00417 /* (v = (v1,..,v(high-m+1)) */ 00418 x = ZERO, /* first element of v in the beginning, then */ 00419 /* summation variable in the actual Householder */ 00420 /* transformation */ 00421 y, /* sigma^2 in the beginning, then ||u||^2, with */ 00422 /* u := v +- sigma * e1 */ 00423 eps; /* tolerance for checking if the transformation is */ 00424 /* valid */ 00425 00426 eps = (REAL)128.0 * MACH_EPS; 00427 00428 for (m = low + 1; m < high; m++) 00429 { 00430 for (y = ZERO, i = high; i >= m; i--) 00431 x = mat[i][m - 1], 00432 d[i] = x, 00433 y = y + x * x; 00434 if (y <= eps) 00435 s = ZERO; 00436 else 00437 { 00438 s = (x >= ZERO) ? -SQRT(y) : SQRT(y); 00439 y -= x * s; 00440 d[m] = x - s; 00441 00442 for (j = m; j < n; j++) /* multiply mat from the */ 00443 { /* left by (E-(u*uT)/y) */ 00444 for (x = ZERO, i = high; i >= m; i--) 00445 x += d[i] * mat[i][j]; 00446 for (x /= y, i = m; i <= high; i++) 00447 mat[i][j] -= x * d[i]; 00448 } 00449 00450 for (i = 0; i <= high; i++) /* multiply mat from the */ 00451 { /* right by (E-(u*uT)/y) */ 00452 for (x = ZERO, j = high; j >= m; j--) 00453 x += d[j] * mat[i][j]; 00454 for (x /= y, j = m; j <= high; j++) 00455 mat[i][j] -= x * d[j]; 00456 } 00457 } 00458 00459 mat[m][m - 1] = s; 00460 } 00461 00462 return 0; 00463 00464 } /* --------------------------- orthes -------------------------- */ 00465 00466 00467 /* ------------------------------------------------------------------ */ 00468 00469 static int orttrans /* compute orthogonal transformation matrix */ 00470 ( 00471 int n, /* Dimension of matrix */ 00472 int low, /* [low,low]..[high,high]: submatrix */ 00473 int high, /* affected by the reduction */ 00474 REAL *mat[], /* Hessenberg matrix, reduction inf. */ 00475 REAL d[], /* remaining reduction information */ 00476 REAL *v[] /* transformation matrix */ 00477 ) /* error code */ 00478 00479 /*********************************************************************** 00480 * compute the matrix v of accumulated transformations from the * 00481 * information left by the Householder reduction of matrix mat to upper * 00482 * Hessenberg form below the Hessenberg matrix in mat and in the * 00483 * vector d. The contents of the latter are destroyed. * 00484 * * 00485 * Input parameters: * 00486 * ================= * 00487 * n dimension of mat * 00488 * low \ rows 0 to low-1 and high+1 to n-1 contain isolated * 00489 * high > eigenvalues, i. e. eigenvalues corresponding to * 00490 * / eigenvectors that are multiples of unit vectors * 00491 * mat [0..n-1,0..n-1] matrix produced by `orthes' giving the * 00492 * upper Hessenberg matrix and part of the information on the * 00493 * orthogonal reduction * 00494 * d [0..n-1] vector with the remaining information on the * 00495 * orthogonal reduction to upper Hessenberg form * 00496 * * 00497 * Output parameters: * 00498 * ================== * 00499 * d input vector destroyed by this function * 00500 * v [0..n-1,0..n-1] matrix defining the similarity reduction * 00501 * to upper Hessenberg form * 00502 * * 00503 * Return value: * 00504 * ============= * 00505 * Error code. This can only be the value 0 here. * 00506 * * 00507 * global names used: * 00508 * ================= * 00509 * REAL, ZERO, ONE * 00510 * * 00511 * -------------------------------------------------------------------- * 00512 * Literature: Numerical Mathematics 16 (1970), page 191 * 00513 ***********************************************************************/ 00514 00515 { 00516 int i, j, m; /* loop variables */ 00517 REAL x, /* summation variable in the */ 00518 /* Householder transformation */ 00519 y; /* sigma respectively */ 00520 /* sigma * (v1 +- sigma) */ 00521 00522 for (i = 0; i < n; i++) /* form the unit matrix in v */ 00523 { 00524 for (j = 0; j < n; j++) 00525 v[i][j] = ZERO; 00526 v[i][i] = ONE; 00527 } 00528 00529 for (m = high - 1; m > low; m--) /* apply the transformations */ 00530 { /* that reduced mat to upper */ 00531 y = mat[m][m - 1]; /* Hessenberg form also to the */ 00532 /* unit matrix in v. This */ 00533 if (y != ZERO) /* produces the desired */ 00534 { /* transformation matrix in v. */ 00535 y *= d[m]; 00536 for (i = m + 1; i <= high; i++) 00537 d[i] = mat[i][m - 1]; 00538 for (j = m; j <= high; j++) 00539 { 00540 for (x = ZERO, i = m; i <= high; i++) 00541 x += d[i] * v[i][j]; 00542 for (x /= y, i = m; i <= high; i++) 00543 v[i][j] += x * d[i]; 00544 } 00545 } 00546 } 00547 00548 return 0; 00549 00550 } /* -------------------------- orttrans ------------------------- */ 00551 00552 00553 static int hqrvec /* compute eigenvectors ......................*/ 00554 (int n, /* Dimension of matrix .......*/ 00555 int low, /* first nonzero row .........*/ 00556 int high, /* last nonzero row ..........*/ 00557 REAL * h[], /* upper Hessenberg matrix ...*/ 00558 REAL wr[], /* Real parts of evalues .....*/ 00559 REAL wi[], /* Imaginary parts of evalues */ 00560 REAL * eivec[] /* Eigenvectors ..............*/ 00561 ) 00562 /*====================================================================* 00563 * * 00564 * hqrvec computes the eigenvectors for the eigenvalues found in hqr2* 00565 * * 00566 *====================================================================* 00567 * * 00568 * Input parameters: * 00569 * ================ * 00570 * n int n; ( n > 0 ) * 00571 * Dimension of mat and eivec, number of eigenvalues. * 00572 * low int low; * 00573 * high int high; see balance * 00574 * h REAL *h[n]; * 00575 * upper Hessenberg matrix * 00576 * wr REAL wr[n]; * 00577 * Real parts of the n eigenvalues. * 00578 * wi REAL wi[n]; * 00579 * Imaginary parts of the n eigenvalues. * 00580 * * 00581 * Output parameter: * 00582 * ================ * 00583 * eivec REAL *eivec[n]; * 00584 * Matrix, whose columns are the eigenvectors * 00585 * * 00586 * Return value : * 00587 * ============= * 00588 * = 0 all ok * 00589 * = 1 h is the zero matrix. * 00590 * * 00591 *====================================================================* 00592 * * 00593 * function in use : * 00594 * ================== * 00595 * * 00596 * int comdiv(): complex division * 00597 * * 00598 *====================================================================* 00599 * * 00600 * Constants used : MACH_EPS * 00601 * ================= * 00602 * * 00603 * Macros : SQR, ABS * 00604 * ======== * 00605 * * 00606 *====================================================================*/ 00607 { 00608 int i, j, k; 00609 int l, m, en, na; 00610 REAL p, q, r = ZERO, s = ZERO, t, w, x, y, z = ZERO, 00611 ra, sa, vr, vi, norm; 00612 00613 for (norm = ZERO, i = 0; i < n; i++) /* find norm of h */ 00614 { 00615 for (j = i; j < n; j++) norm += ABS(h[i][j]); 00616 } 00617 00618 if (norm == ZERO) return (1); /* zero matrix */ 00619 00620 for (en = n - 1; en >= 0; en--) /* transform back */ 00621 { 00622 p = wr[en]; 00623 q = wi[en]; 00624 na = en - 1; 00625 if (q == ZERO) 00626 { 00627 m = en; 00628 h[en][en] = ONE; 00629 for (i = na; i >= 0; i--) 00630 { 00631 w = h[i][i] - p; 00632 r = h[i][en]; 00633 for (j = m; j <= na; j++) r += h[i][j] * h[j][en]; 00634 if (wi[i] < ZERO) 00635 { 00636 z = w; 00637 s = r; 00638 } 00639 else 00640 { 00641 m = i; 00642 if (wi[i] == ZERO) 00643 h[i][en] = -r / ((w != ZERO) ? (w) : (MACH_EPS * norm)); 00644 else 00645 { /* Solve the linear system: */ 00646 /* | w x | | h[i][en] | | -r | */ 00647 /* | | | | = | | */ 00648 /* | y z | | h[i+1][en] | | -s | */ 00649 00650 x = h[i][i+1]; 00651 y = h[i+1][i]; 00652 q = SQR (wr[i] - p) + SQR (wi[i]); 00653 h[i][en] = t = (x * s - z * r) / q; 00654 h[i+1][en] = ( (ABS(x) > ABS(z) ) ? 00655 (-r -w * t) / x : (-s -y * t) / z); 00656 } 00657 } /* wi[i] >= 0 */ 00658 } /* end i */ 00659 } /* end q = 0 */ 00660 00661 else if (q < ZERO) 00662 { 00663 m = na; 00664 if (ABS(h[en][na]) > ABS(h[na][en])) 00665 { 00666 h[na][na] = - (h[en][en] - p) / h[en][na]; 00667 h[na][en] = - q / h[en][na]; 00668 } 00669 else 00670 comdiv(-h[na][en], ZERO, h[na][na]-p, q, &h[na][na], &h[na][en]); 00671 00672 h[en][na] = ONE; 00673 h[en][en] = ZERO; 00674 for (i = na - 1; i >= 0; i--) 00675 { 00676 w = h[i][i] - p; 00677 ra = h[i][en]; 00678 sa = ZERO; 00679 for (j = m; j <= na; j++) 00680 { 00681 ra += h[i][j] * h[j][na]; 00682 sa += h[i][j] * h[j][en]; 00683 } 00684 00685 if (wi[i] < ZERO) 00686 { 00687 z = w; 00688 r = ra; 00689 s = sa; 00690 } 00691 else 00692 { 00693 m = i; 00694 if (wi[i] == ZERO) 00695 comdiv (-ra, -sa, w, q, &h[i][na], &h[i][en]); 00696 else 00697 { 00698 00699 /* solve complex linear system: */ 00700 /* | w+i*q x | | h[i][na] + i*h[i][en] | | -ra+i*sa | */ 00701 /* | | | | = | | */ 00702 /* | y z+i*q| | h[i+1][na]+i*h[i+1][en]| | -r+i*s | */ 00703 00704 x = h[i][i+1]; 00705 y = h[i+1][i]; 00706 vr = SQR (wr[i] - p) + SQR (wi[i]) - SQR (q); 00707 vi = TWO * q * (wr[i] - p); 00708 if (vr == ZERO && vi == ZERO) 00709 vr = MACH_EPS * norm * 00710 (ABS (w) + ABS (q) + ABS (x) + ABS (y) + ABS (z)); 00711 00712 comdiv (x * r - z * ra + q * sa, x * s - z * sa -q * ra, 00713 vr, vi, &h[i][na], &h[i][en]); 00714 if (ABS (x) > ABS (z) + ABS (q)) 00715 { 00716 h[i+1][na] = (-ra - w * h[i][na] + q * h[i][en]) / x; 00717 h[i+1][en] = (-sa - w * h[i][en] - q * h[i][na]) / x; 00718 } 00719 else 00720 comdiv (-r - y * h[i][na], -s - y * h[i][en], z, q, 00721 &h[i+1][na], &h[i+1][en]); 00722 00723 } /* end wi[i] > 0 */ 00724 } /* end wi[i] >= 0 */ 00725 } /* end i */ 00726 } /* if q < 0 */ 00727 } /* end en */ 00728 00729 for (i = 0; i < n; i++) /* Eigenvectors for the evalues for */ 00730 if (i < low || i > high) /* rows < low and rows > high */ 00731 for (k = i + 1; k < n; k++) eivec[i][k] = h[i][k]; 00732 00733 for (j = n - 1; j >= low; j--) 00734 { 00735 m = (j <= high) ? j : high; 00736 if (wi[j] < ZERO) 00737 { 00738 for (l = j - 1, i = low; i <= high; i++) 00739 { 00740 for (y = z = ZERO, k = low; k <= m; k++) 00741 { 00742 y += eivec[i][k] * h[k][l]; 00743 z += eivec[i][k] * h[k][j]; 00744 } 00745 00746 eivec[i][l] = y; 00747 eivec[i][j] = z; 00748 } 00749 } 00750 else 00751 if (wi[j] == ZERO) 00752 { 00753 for (i = low; i <= high; i++) 00754 { 00755 for (z = ZERO, k = low; k <= m; k++) 00756 z += eivec[i][k] * h[k][j]; 00757 eivec[i][j] = z; 00758 } 00759 } 00760 00761 } /* end j */ 00762 00763 return (0); 00764 } 00765 00766 00767 static int hqr2 /* compute eigenvalues .......................*/ 00768 (int vec, /* switch for computing evectors*/ 00769 int n, /* Dimension of matrix .........*/ 00770 int low, /* first nonzero row ...........*/ 00771 int high, /* last nonzero row ............*/ 00772 REAL * h[], /* Hessenberg matrix ...........*/ 00773 REAL wr[], /* Real parts of eigenvalues ...*/ 00774 REAL wi[], /* Imaginary parts of evalues ..*/ 00775 REAL * eivec[], /* Matrix of eigenvectors ......*/ 00776 int cnt[] /* Iteration counter ...........*/ 00777 ) 00778 /*====================================================================* 00779 * * 00780 * hqr2 computes the eigenvalues and (if vec != 0) the eigenvectors * 00781 * of an n * n upper Hessenberg matrix. * 00782 * * 00783 *====================================================================* 00784 * * 00785 * Control parameter: * 00786 * ================== * 00787 * vec int vec; * 00788 * = 0 compute eigenvalues only * 00789 * = 1 compute all eigenvalues and eigenvectors * 00790 * * 00791 * Input parameters: * 00792 * ================ * 00793 * n int n; ( n > 0 ) * 00794 * Dimension of mat and eivec, * 00795 * length of the real parts vector wr and of the * 00796 * imaginary parts vector wi of the eigenvalues. * 00797 * low int low; * 00798 * high int high; see balance * 00799 * h REAL *h[n]; * 00800 * upper Hessenberg matrix * 00801 * * 00802 * Output parameters: * 00803 * ================== * 00804 * eivec REAL *eivec[n]; ( bei vec = 1 ) * 00805 * Matrix, which for vec = 1 contains the eigenvectors * 00806 * as follows : * 00807 * For real eigebvalues the corresponding column * 00808 * contains the corresponding eigenvactor, while for * 00809 * complex eigenvalues the corresponding column contains* 00810 * the real part of the eigenvactor with its imaginary * 00811 * part is stored in the subsequent column of eivec. * 00812 * The eigenvactor for the complex conjugate eigenvactor* 00813 * is given by the complex conjugate eigenvactor. * 00814 * wr REAL wr[n]; * 00815 * Real part of the n eigenvalues. * 00816 * wi REAL wi[n]; * 00817 * Imaginary parts of the eigenvalues * 00818 * cnt int cnt[n]; * 00819 * vector of iterations used for each eigenvalue. * 00820 * For a complex conjugate eigenvalue pair the second * 00821 * entry is negative. * 00822 * * 00823 * Return value : * 00824 * ============= * 00825 * = 0 all ok * 00826 * = 4xx Iteration maximum exceeded when computing evalue xx * 00827 * = 99 zero matrix * 00828 * * 00829 *====================================================================* 00830 * * 00831 * functions in use : * 00832 * =================== * 00833 * * 00834 * int hqrvec(): reverse transform for eigenvectors * 00835 * * 00836 *====================================================================* 00837 * * 00838 * Constants used : MACH_EPS, MAXIT * 00839 * ================= * 00840 * * 00841 * Macros : SWAP, ABS, SQRT * 00842 * ========= * 00843 * * 00844 *====================================================================*/ 00845 { 00846 int i, j; 00847 int na, en, iter, k, l, m; 00848 REAL p = ZERO, q = ZERO, r = ZERO, s, t, w, x, y, z; 00849 00850 for (i = 0; i < n; i++) 00851 if (i < low || i > high) 00852 { 00853 wr[i] = h[i][i]; 00854 wi[i] = ZERO; 00855 cnt[i] = 0; 00856 } 00857 00858 en = high; 00859 t = ZERO; 00860 00861 while (en >= low) 00862 { 00863 iter = 0; 00864 na = en - 1; 00865 00866 for ( ; ; ) 00867 { 00868 for (l = en; l > low; l--) /* search for small */ 00869 if ( ABS(h[l][l-1]) <= /* subdiagonal element */ 00870 MACH_EPS * (ABS(h[l-1][l-1]) + ABS(h[l][l])) ) break; 00871 00872 x = h[en][en]; 00873 if (l == en) /* found one evalue */ 00874 { 00875 wr[en] = h[en][en] = x + t; 00876 wi[en] = ZERO; 00877 cnt[en] = iter; 00878 en--; 00879 break; 00880 } 00881 00882 y = h[na][na]; 00883 w = h[en][na] * h[na][en]; 00884 00885 if (l == na) /* found two evalues */ 00886 { 00887 p = (y - x) * 0.5; 00888 q = p * p + w; 00889 z = SQRT (ABS (q)); 00890 x = h[en][en] = x + t; 00891 h[na][na] = y + t; 00892 cnt[en] = -iter; 00893 cnt[na] = iter; 00894 if (q >= ZERO) 00895 { /* real eigenvalues */ 00896 z = (p < ZERO) ? (p - z) : (p + z); 00897 wr[na] = x + z; 00898 wr[en] = s = x - w / z; 00899 wi[na] = wi[en] = ZERO; 00900 x = h[en][na]; 00901 r = SQRT (x * x + z * z); 00902 00903 if (vec) 00904 { 00905 p = x / r; 00906 q = z / r; 00907 for (j = na; j < n; j++) 00908 { 00909 z = h[na][j]; 00910 h[na][j] = q * z + p * h[en][j]; 00911 h[en][j] = q * h[en][j] - p * z; 00912 } 00913 00914 for (i = 0; i <= en; i++) 00915 { 00916 z = h[i][na]; 00917 h[i][na] = q * z + p * h[i][en]; 00918 h[i][en] = q * h[i][en] - p * z; 00919 } 00920 00921 for (i = low; i <= high; i++) 00922 { 00923 z = eivec[i][na]; 00924 eivec[i][na] = q * z + p * eivec[i][en]; 00925 eivec[i][en] = q * eivec[i][en] - p * z; 00926 } 00927 } /* end if (vec) */ 00928 } /* end if (q >= ZERO) */ 00929 else /* pair of complex */ 00930 { /* conjugate evalues */ 00931 wr[na] = wr[en] = x + p; 00932 wi[na] = z; 00933 wi[en] = - z; 00934 } 00935 00936 en -= 2; 00937 break; 00938 } /* end if (l == na) */ 00939 00940 if (iter >= MAXIT) 00941 { 00942 cnt[en] = MAXIT + 1; 00943 return (en); /* MAXIT Iterations */ 00944 } 00945 00946 if ( (iter != 0) && (iter % 10 == 0) ) 00947 { 00948 t += x; 00949 for (i = low; i <= en; i++) h[i][i] -= x; 00950 s = ABS (h[en][na]) + ABS (h[na][en-2]); 00951 x = y = (REAL)0.75 * s; 00952 w = - (REAL)0.4375 * s * s; 00953 } 00954 00955 iter ++; 00956 00957 for (m = en - 2; m >= l; m--) 00958 { 00959 z = h[m][m]; 00960 r = x - z; 00961 s = y - z; 00962 p = ( r * s - w ) / h[m+1][m] + h[m][m+1]; 00963 q = h[m + 1][m + 1] - z - r - s; 00964 r = h[m + 2][m + 1]; 00965 s = ABS (p) + ABS (q) + ABS (r); 00966 p /= s; 00967 q /= s; 00968 r /= s; 00969 if (m == l) break; 00970 if ( ABS (h[m][m-1]) * (ABS (q) + ABS (r)) <= 00971 MACH_EPS * ABS (p) 00972 * ( ABS (h[m-1][m-1]) + ABS (z) + ABS (h[m+1][m+1])) ) 00973 break; 00974 } 00975 00976 for (i = m + 2; i <= en; i++) h[i][i-2] = ZERO; 00977 for (i = m + 3; i <= en; i++) h[i][i-3] = ZERO; 00978 00979 for (k = m; k <= na; k++) 00980 { 00981 if (k != m) /* double QR step, for rows l to en */ 00982 { /* and columns m to en */ 00983 p = h[k][k-1]; 00984 q = h[k+1][k-1]; 00985 r = (k != na) ? h[k+2][k-1] : ZERO; 00986 x = ABS (p) + ABS (q) + ABS (r); 00987 if (x == ZERO) continue; /* next k */ 00988 p /= x; 00989 q /= x; 00990 r /= x; 00991 } 00992 s = SQRT (p * p + q * q + r * r); 00993 if (p < ZERO) s = -s; 00994 00995 if (k != m) h[k][k-1] = -s * x; 00996 else if (l != m) 00997 h[k][k-1] = -h[k][k-1]; 00998 p += s; 00999 x = p / s; 01000 y = q / s; 01001 z = r / s; 01002 q /= p; 01003 r /= p; 01004 01005 for (j = k; j < n; j++) /* modify rows */ 01006 { 01007 p = h[k][j] + q * h[k+1][j]; 01008 if (k != na) 01009 { 01010 p += r * h[k+2][j]; 01011 h[k+2][j] -= p * z; 01012 } 01013 h[k+1][j] -= p * y; 01014 h[k][j] -= p * x; 01015 } 01016 01017 j = (k + 3 < en) ? (k + 3) : en; 01018 for (i = 0; i <= j; i++) /* modify columns */ 01019 { 01020 p = x * h[i][k] + y * h[i][k+1]; 01021 if (k != na) 01022 { 01023 p += z * h[i][k+2]; 01024 h[i][k+2] -= p * r; 01025 } 01026 h[i][k+1] -= p * q; 01027 h[i][k] -= p; 01028 } 01029 01030 if (vec) /* if eigenvectors are needed ..................*/ 01031 { 01032 for (i = low; i <= high; i++) 01033 { 01034 p = x * eivec[i][k] + y * eivec[i][k+1]; 01035 if (k != na) 01036 { 01037 p += z * eivec[i][k+2]; 01038 eivec[i][k+2] -= p * r; 01039 } 01040 eivec[i][k+1] -= p * q; 01041 eivec[i][k] -= p; 01042 } 01043 } 01044 } /* end k */ 01045 01046 } /* end for ( ; ;) */ 01047 01048 } /* while (en >= low) All evalues found */ 01049 01050 if (vec) /* transform evectors back */ 01051 if (hqrvec (n, low, high, h, wr, wi, eivec)) return (99); 01052 return (0); 01053 } 01054 01055 01056 static int norm_1 /* normalize eigenvectors to have one norm 1 .*/ 01057 (int n, /* Dimension of matrix ...........*/ 01058 REAL * v[], /* Matrix with eigenvektors ......*/ 01059 REAL wi[] /* Imaginary parts of evalues ....*/ 01060 ) 01061 /*====================================================================* 01062 * * 01063 * norm_1 normalizes the one norm of the column vectors in v. * 01064 * (special attention to complex vectors in v is given) * 01065 * * 01066 *====================================================================* 01067 * * 01068 * Input parameters: * 01069 * ================ * 01070 * n int n; ( n > 0 ) * 01071 * Dimension of matrix v * 01072 * v REAL *v[]; * 01073 * Matrix of eigenvectors * 01074 * wi REAL wi[]; * 01075 * Imaginary parts of the eigenvalues * 01076 * * 01077 * Output parameter: * 01078 * ================ * 01079 * v REAL *v[]; * 01080 * Matrix with normalized eigenvectors * 01081 * * 01082 * Return value : * 01083 * ============= * 01084 * = 0 all ok * 01085 * = 1 n < 1 * 01086 * * 01087 *====================================================================* 01088 * * 01089 * functions used : * 01090 * ================= * 01091 * REAL comabs(): complex absolute value * 01092 * int comdiv(): complex division * 01093 * * 01094 * Macros : ABS * 01095 * ======== * 01096 * * 01097 *====================================================================*/ 01098 { 01099 int i, j; 01100 REAL maxi, tr, ti; 01101 01102 if (n < 1) return (1); 01103 01104 for (j = 0; j < n; j++) 01105 { 01106 if (wi[j] == ZERO) 01107 { 01108 maxi = v[0][j]; 01109 for (i = 1; i < n; i++) 01110 if (ABS (v[i][j]) > ABS (maxi)) maxi = v[i][j]; 01111 01112 if (maxi != ZERO) 01113 { 01114 maxi = ONE / maxi; 01115 for (i = 0; i < n; i++) v[i][j] *= maxi; 01116 } 01117 } 01118 else 01119 { 01120 tr = v[0][j]; 01121 ti = v[0][j+1]; 01122 for (i = 1; i < n; i++) 01123 if ( comabs (v[i][j], v[i][j+1]) > comabs (tr, ti) ) 01124 { 01125 tr = v[i][j]; 01126 ti = v[i][j+1]; 01127 } 01128 01129 if (tr != ZERO || ti != ZERO) 01130 for (i = 0; i < n; i++) 01131 comdiv (v[i][j], v[i][j+1], tr, ti, &v[i][j], &v[i][j+1]); 01132 01133 j++; /* raise j by two */ 01134 } 01135 } 01136 return (0); 01137 } 01138 01139 01140 int eigen /* Compute all evalues/evectors of a matrix ..*/ 01141 ( 01142 int vec, /* switch for computing evectors ...*/ 01143 int ortho, /* orthogonal Hessenberg reduction? */ 01144 int ev_norm, /* normalize Eigenvectors? .........*/ 01145 int n, /* size of matrix ..................*/ 01146 REAL ** mat, /* input matrix ....................*/ 01147 REAL ** eivec, /* Eigenvectors ....................*/ 01148 REAL * valre, /* real parts of eigenvalues .......*/ 01149 REAL * valim, /* imaginary parts of eigenvalues ..*/ 01150 int * cnt /* Iteration counter ...............*/ 01151 ) 01152 /*====================================================================* 01153 * * 01154 * The function eigen determines all eigenvalues and (if desired) * 01155 * all eigenvectors of a real square n * n matrix via the QR method* 01156 * in the version of Martin, Parlett, Peters, Reinsch and Wilkinson.* 01157 * * 01158 *====================================================================* 01159 * * 01160 * Literature: * 01161 * =========== * 01162 * 1) Peters, Wilkinson: Eigenvectors of real and complex * 01163 * matrices by LR and QR triangularisations, * 01164 * Num. Math. 16, p.184-204, (1970); [PETE70]; contribution * 01165 * II/15, p. 372 - 395 in [WILK71]. * 01166 * 2) Martin, Wilkinson: Similarity reductions of a general * 01167 * matrix to Hessenberg form, Num. Math. 12, p. 349-368,(1968)* 01168 * [MART 68]; contribution II,13, p. 339 - 358 in [WILK71]. * 01169 * 3) Parlett, Reinsch: Balancing a matrix for calculations of * 01170 * eigenvalues and eigenvectors, Num. Math. 13, p. 293-304, * 01171 * (1969); [PARL69]; contribution II/11, p.315 - 326 in * 01172 * [WILK71]. * 01173 * * 01174 *====================================================================* 01175 * * 01176 * Control parameters: * 01177 * =================== * 01178 * vec int vec; * 01179 * call for eigen : * 01180 * = 0 compute eigenvalues only * 01181 * = 1 compute all eigenvalues and eigenvectors * 01182 * ortho flag that shows if transformation of mat to * 01183 * Hessenberg form shall be done orthogonally by * 01184 * `orthes' (flag set) or elementarily by `elmhes' * 01185 * (flag cleared). The Householder matrices used in * 01186 * orthogonal transformation have the advantage of * 01187 * preserving the symmetry of input matrices. * 01188 * ev_norm flag that shows if Eigenvectors shall be * 01189 * normalized (flag set) or not (flag cleared) * 01190 * * 01191 * Input parameters: * 01192 * ================ * 01193 * n int n; ( n > 0 ) * 01194 * size of matrix, number of eigenvalues * 01195 * mat REAL *mat[n]; * 01196 * matrix * 01197 * * 01198 * Output parameters: * 01199 * ================== * 01200 * eivec REAL *eivec[n]; ( bei vec = 1 ) * 01201 * matrix, if vec = 1 this holds the eigenvectors * 01202 * thus : * 01203 * If the jth eigenvalue of the matrix is real then the * 01204 * jth column is the corresponding real eigenvector; * 01205 * if the jth eigenvalue is complex then the jth column * 01206 * of eivec contains the real part of the eigenvector * 01207 * while its imaginary part is in column j+1. * 01208 * (the j+1st eigenvector is the complex conjugate * 01209 * vector.) * 01210 * valre REAL valre[n]; * 01211 * Real parts of the eigenvalues. * 01212 * valim REAL valim[n]; * 01213 * Imaginary parts of the eigenvalues * 01214 * cnt int cnt[n]; * 01215 * vector containing the number of iterations for each * 01216 * eigenvalue. (for a complex conjugate pair the second * 01217 * entry is negative.) * 01218 * * 01219 * Return value : * 01220 * ============= * 01221 * = 0 all ok * 01222 * = 1 n < 1 or other invalid input parameter * 01223 * = 2 insufficient memory * 01224 * = 10x error x from balance() * 01225 * = 20x error x from elmh() * 01226 * = 30x error x from elmtrans() (for vec = 1 only) * 01227 * = 4xx error xx from hqr2() * 01228 * = 50x error x from balback() (for vec = 1 only) * 01229 * = 60x error x from norm_1() (for vec = 1 only) * 01230 * * 01231 *====================================================================* 01232 * * 01233 * Functions in use : * 01234 * =================== * 01235 * * 01236 * static int balance (): Balancing of an n x n matrix * 01237 * static int elmh (): Transformation to upper Hessenberg form * 01238 * static int elmtrans(): intialize eigenvectors * 01239 * static int hqr2 (): compute eigenvalues/eigenvectors * 01240 * static int balback (): Reverse balancing to obtain eigenvectors * 01241 * static int norm_1 (): Normalize eigenvectors * 01242 * * 01243 * void *vmalloc(): allocate vector or matrix * 01244 * void vmfree(): free list of vectors and matrices * 01245 * * 01246 *====================================================================* 01247 * * 01248 * Constants used : NULL, BASIS * 01249 * =================== * 01250 * * 01251 *====================================================================*/ 01252 { 01253 register int i; 01254 int low, high, rc; 01255 REAL *scale, 01256 *d = NULL; 01257 void *vmblock; 01258 01259 if (n < 1) return (1); /* n >= 1 ............*/ 01260 01261 if (valre == NULL || valim == NULL || mat == NULL || cnt == NULL) 01262 return (1); 01263 01264 for (i = 0; i < n; i++) 01265 if (mat[i] == NULL) return (1); 01266 01267 for (i = 0; i < n; i++) cnt[i] = 0; 01268 01269 if (n == 1) /* n = 1 .............*/ 01270 { 01271 eivec[0][0] = ONE; 01272 valre[0] = mat[0][0]; 01273 valim[0] = ZERO; 01274 return (0); 01275 } 01276 01277 if (vec) 01278 { 01279 if (eivec == NULL) return (1); 01280 for (i = 0; i < n; i++) 01281 if (eivec[i] == NULL) return (1); 01282 } 01283 01284 vmblock = vminit(); 01285 scale = (REAL *)vmalloc(vmblock, VEKTOR, n, 0); 01286 if (! vmcomplete(vmblock)) /* memory error */ 01287 return 2; 01288 01289 if (vec && ortho) /* with Eigenvectors */ 01290 { /* and orthogonal */ 01291 /* Hessenberg reduction? */ 01292 d = (REAL *)vmalloc(vmblock, VEKTOR, n, 0); 01293 if (! vmcomplete(vmblock)) 01294 { 01295 vmfree(vmblock); 01296 return 1; 01297 } 01298 } 01299 01300 /* balance mat for nearly */ 01301 rc = balance (n, mat, scale, /* equal row and column */ 01302 &low, &high, BASIS); /* one norms */ 01303 if (rc) 01304 { 01305 vmfree(vmblock); 01306 return (100 + rc); 01307 } 01308 01309 if (ortho) 01310 rc = orthes(n, low, high, mat, d); 01311 else 01312 rc = elmhes (n, low, high, mat, cnt); /* reduce mat to upper */ 01313 if (rc) /* Hessenberg form */ 01314 { 01315 vmfree(vmblock); 01316 return (200 + rc); 01317 } 01318 01319 if (vec) /* initialize eivec */ 01320 { 01321 if (ortho) 01322 rc = orttrans(n, low, high, mat, d, eivec); 01323 else 01324 rc = elmtrans (n, low, high, mat, cnt, eivec); 01325 if (rc) 01326 { 01327 vmfree(vmblock); 01328 return (300 + rc); 01329 } 01330 } 01331 01332 rc = hqr2 (vec, n, low, high, mat, /* execute Francis QR */ 01333 valre, valim, eivec, cnt); /* algorithm to obtain */ 01334 if (rc) /* eigenvalues */ 01335 { 01336 vmfree(vmblock); 01337 return (400 + rc); 01338 } 01339 01340 if (vec) 01341 { 01342 rc = balback (n, low, high, /* reverse balancing if */ 01343 scale, eivec); /* eigenvaectors are to */ 01344 if (rc) /* be determined */ 01345 { 01346 vmfree(vmblock); 01347 return (500 + rc); 01348 } 01349 if (ev_norm) 01350 rc = norm_1 (n, eivec, valim); /* normalize eigenvectors */ 01351 if (rc) 01352 { 01353 vmfree(vmblock); 01354 return (600 + rc); 01355 } 01356 } 01357 01358 vmfree(vmblock); /* free buffers */ 01359 01360 01361 return (0); 01362 } 01363 01364 /* ------------------------ END feigen.cpp -------------------------- */