ssteqr.c
Go to the documentation of this file.
00001 /* ssteqr.f -- translated by f2c (version 20061008).
00002    You must link the resulting object file with libf2c:
00003         on Microsoft Windows system, link with libf2c.lib;
00004         on Linux or Unix systems, link with .../path/to/libf2c.a -lm
00005         or, if you install libf2c.a in a standard place, with -lf2c -lm
00006         -- in that order, at the end of the command line, as in
00007                 cc *.o -lf2c -lm
00008         Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
00009 
00010                 http://www.netlib.org/f2c/libf2c.zip
00011 */
00012 
00013 #include "f2c.h"
00014 #include "blaswrap.h"
00015 
00016 /* Table of constant values */
00017 
00018 static real c_b9 = 0.f;
00019 static real c_b10 = 1.f;
00020 static integer c__0 = 0;
00021 static integer c__1 = 1;
00022 static integer c__2 = 2;
00023 
00024 /* Subroutine */ int ssteqr_(char *compz, integer *n, real *d__, real *e, 
00025         real *z__, integer *ldz, real *work, integer *info)
00026 {
00027     /* System generated locals */
00028     integer z_dim1, z_offset, i__1, i__2;
00029     real r__1, r__2;
00030 
00031     /* Builtin functions */
00032     double sqrt(doublereal), r_sign(real *, real *);
00033 
00034     /* Local variables */
00035     real b, c__, f, g;
00036     integer i__, j, k, l, m;
00037     real p, r__, s;
00038     integer l1, ii, mm, lm1, mm1, nm1;
00039     real rt1, rt2, eps;
00040     integer lsv;
00041     real tst, eps2;
00042     integer lend, jtot;
00043     extern /* Subroutine */ int slae2_(real *, real *, real *, real *, real *)
00044             ;
00045     extern logical lsame_(char *, char *);
00046     real anorm;
00047     extern /* Subroutine */ int slasr_(char *, char *, char *, integer *, 
00048             integer *, real *, real *, real *, integer *), sswap_(integer *, real *, integer *, real *, integer *);
00049     integer lendm1, lendp1;
00050     extern /* Subroutine */ int slaev2_(real *, real *, real *, real *, real *
00051 , real *, real *);
00052     extern doublereal slapy2_(real *, real *);
00053     integer iscale;
00054     extern doublereal slamch_(char *);
00055     real safmin;
00056     extern /* Subroutine */ int xerbla_(char *, integer *);
00057     real safmax;
00058     extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, 
00059             real *, integer *, integer *, real *, integer *, integer *);
00060     integer lendsv;
00061     extern /* Subroutine */ int slartg_(real *, real *, real *, real *, real *
00062 ), slaset_(char *, integer *, integer *, real *, real *, real *, 
00063             integer *);
00064     real ssfmin;
00065     integer nmaxit, icompz;
00066     real ssfmax;
00067     extern doublereal slanst_(char *, integer *, real *, real *);
00068     extern /* Subroutine */ int slasrt_(char *, integer *, real *, integer *);
00069 
00070 
00071 /*  -- LAPACK routine (version 3.2) -- */
00072 /*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
00073 /*     November 2006 */
00074 
00075 /*     .. Scalar Arguments .. */
00076 /*     .. */
00077 /*     .. Array Arguments .. */
00078 /*     .. */
00079 
00080 /*  Purpose */
00081 /*  ======= */
00082 
00083 /*  SSTEQR computes all eigenvalues and, optionally, eigenvectors of a */
00084 /*  symmetric tridiagonal matrix using the implicit QL or QR method. */
00085 /*  The eigenvectors of a full or band symmetric matrix can also be found */
00086 /*  if SSYTRD or SSPTRD or SSBTRD has been used to reduce this matrix to */
00087 /*  tridiagonal form. */
00088 
00089 /*  Arguments */
00090 /*  ========= */
00091 
00092 /*  COMPZ   (input) CHARACTER*1 */
00093 /*          = 'N':  Compute eigenvalues only. */
00094 /*          = 'V':  Compute eigenvalues and eigenvectors of the original */
00095 /*                  symmetric matrix.  On entry, Z must contain the */
00096 /*                  orthogonal matrix used to reduce the original matrix */
00097 /*                  to tridiagonal form. */
00098 /*          = 'I':  Compute eigenvalues and eigenvectors of the */
00099 /*                  tridiagonal matrix.  Z is initialized to the identity */
00100 /*                  matrix. */
00101 
00102 /*  N       (input) INTEGER */
00103 /*          The order of the matrix.  N >= 0. */
00104 
00105 /*  D       (input/output) REAL array, dimension (N) */
00106 /*          On entry, the diagonal elements of the tridiagonal matrix. */
00107 /*          On exit, if INFO = 0, the eigenvalues in ascending order. */
00108 
00109 /*  E       (input/output) REAL array, dimension (N-1) */
00110 /*          On entry, the (n-1) subdiagonal elements of the tridiagonal */
00111 /*          matrix. */
00112 /*          On exit, E has been destroyed. */
00113 
00114 /*  Z       (input/output) REAL array, dimension (LDZ, N) */
00115 /*          On entry, if  COMPZ = 'V', then Z contains the orthogonal */
00116 /*          matrix used in the reduction to tridiagonal form. */
00117 /*          On exit, if INFO = 0, then if  COMPZ = 'V', Z contains the */
00118 /*          orthonormal eigenvectors of the original symmetric matrix, */
00119 /*          and if COMPZ = 'I', Z contains the orthonormal eigenvectors */
00120 /*          of the symmetric tridiagonal matrix. */
00121 /*          If COMPZ = 'N', then Z is not referenced. */
00122 
00123 /*  LDZ     (input) INTEGER */
00124 /*          The leading dimension of the array Z.  LDZ >= 1, and if */
00125 /*          eigenvectors are desired, then  LDZ >= max(1,N). */
00126 
00127 /*  WORK    (workspace) REAL array, dimension (max(1,2*N-2)) */
00128 /*          If COMPZ = 'N', then WORK is not referenced. */
00129 
00130 /*  INFO    (output) INTEGER */
00131 /*          = 0:  successful exit */
00132 /*          < 0:  if INFO = -i, the i-th argument had an illegal value */
00133 /*          > 0:  the algorithm has failed to find all the eigenvalues in */
00134 /*                a total of 30*N iterations; if INFO = i, then i */
00135 /*                elements of E have not converged to zero; on exit, D */
00136 /*                and E contain the elements of a symmetric tridiagonal */
00137 /*                matrix which is orthogonally similar to the original */
00138 /*                matrix. */
00139 
00140 /*  ===================================================================== */
00141 
00142 /*     .. Parameters .. */
00143 /*     .. */
00144 /*     .. Local Scalars .. */
00145 /*     .. */
00146 /*     .. External Functions .. */
00147 /*     .. */
00148 /*     .. External Subroutines .. */
00149 /*     .. */
00150 /*     .. Intrinsic Functions .. */
00151 /*     .. */
00152 /*     .. Executable Statements .. */
00153 
00154 /*     Test the input parameters. */
00155 
00156     /* Parameter adjustments */
00157     --d__;
00158     --e;
00159     z_dim1 = *ldz;
00160     z_offset = 1 + z_dim1;
00161     z__ -= z_offset;
00162     --work;
00163 
00164     /* Function Body */
00165     *info = 0;
00166 
00167     if (lsame_(compz, "N")) {
00168         icompz = 0;
00169     } else if (lsame_(compz, "V")) {
00170         icompz = 1;
00171     } else if (lsame_(compz, "I")) {
00172         icompz = 2;
00173     } else {
00174         icompz = -1;
00175     }
00176     if (icompz < 0) {
00177         *info = -1;
00178     } else if (*n < 0) {
00179         *info = -2;
00180     } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) {
00181         *info = -6;
00182     }
00183     if (*info != 0) {
00184         i__1 = -(*info);
00185         xerbla_("SSTEQR", &i__1);
00186         return 0;
00187     }
00188 
00189 /*     Quick return if possible */
00190 
00191     if (*n == 0) {
00192         return 0;
00193     }
00194 
00195     if (*n == 1) {
00196         if (icompz == 2) {
00197             z__[z_dim1 + 1] = 1.f;
00198         }
00199         return 0;
00200     }
00201 
00202 /*     Determine the unit roundoff and over/underflow thresholds. */
00203 
00204     eps = slamch_("E");
00205 /* Computing 2nd power */
00206     r__1 = eps;
00207     eps2 = r__1 * r__1;
00208     safmin = slamch_("S");
00209     safmax = 1.f / safmin;
00210     ssfmax = sqrt(safmax) / 3.f;
00211     ssfmin = sqrt(safmin) / eps2;
00212 
00213 /*     Compute the eigenvalues and eigenvectors of the tridiagonal */
00214 /*     matrix. */
00215 
00216     if (icompz == 2) {
00217         slaset_("Full", n, n, &c_b9, &c_b10, &z__[z_offset], ldz);
00218     }
00219 
00220     nmaxit = *n * 30;
00221     jtot = 0;
00222 
00223 /*     Determine where the matrix splits and choose QL or QR iteration */
00224 /*     for each block, according to whether top or bottom diagonal */
00225 /*     element is smaller. */
00226 
00227     l1 = 1;
00228     nm1 = *n - 1;
00229 
00230 L10:
00231     if (l1 > *n) {
00232         goto L160;
00233     }
00234     if (l1 > 1) {
00235         e[l1 - 1] = 0.f;
00236     }
00237     if (l1 <= nm1) {
00238         i__1 = nm1;
00239         for (m = l1; m <= i__1; ++m) {
00240             tst = (r__1 = e[m], dabs(r__1));
00241             if (tst == 0.f) {
00242                 goto L30;
00243             }
00244             if (tst <= sqrt((r__1 = d__[m], dabs(r__1))) * sqrt((r__2 = d__[m 
00245                     + 1], dabs(r__2))) * eps) {
00246                 e[m] = 0.f;
00247                 goto L30;
00248             }
00249 /* L20: */
00250         }
00251     }
00252     m = *n;
00253 
00254 L30:
00255     l = l1;
00256     lsv = l;
00257     lend = m;
00258     lendsv = lend;
00259     l1 = m + 1;
00260     if (lend == l) {
00261         goto L10;
00262     }
00263 
00264 /*     Scale submatrix in rows and columns L to LEND */
00265 
00266     i__1 = lend - l + 1;
00267     anorm = slanst_("I", &i__1, &d__[l], &e[l]);
00268     iscale = 0;
00269     if (anorm == 0.f) {
00270         goto L10;
00271     }
00272     if (anorm > ssfmax) {
00273         iscale = 1;
00274         i__1 = lend - l + 1;
00275         slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, 
00276                 info);
00277         i__1 = lend - l;
00278         slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, 
00279                 info);
00280     } else if (anorm < ssfmin) {
00281         iscale = 2;
00282         i__1 = lend - l + 1;
00283         slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, 
00284                 info);
00285         i__1 = lend - l;
00286         slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, 
00287                 info);
00288     }
00289 
00290 /*     Choose between QL and QR iteration */
00291 
00292     if ((r__1 = d__[lend], dabs(r__1)) < (r__2 = d__[l], dabs(r__2))) {
00293         lend = lsv;
00294         l = lendsv;
00295     }
00296 
00297     if (lend > l) {
00298 
00299 /*        QL Iteration */
00300 
00301 /*        Look for small subdiagonal element. */
00302 
00303 L40:
00304         if (l != lend) {
00305             lendm1 = lend - 1;
00306             i__1 = lendm1;
00307             for (m = l; m <= i__1; ++m) {
00308 /* Computing 2nd power */
00309                 r__2 = (r__1 = e[m], dabs(r__1));
00310                 tst = r__2 * r__2;
00311                 if (tst <= eps2 * (r__1 = d__[m], dabs(r__1)) * (r__2 = d__[m 
00312                         + 1], dabs(r__2)) + safmin) {
00313                     goto L60;
00314                 }
00315 /* L50: */
00316             }
00317         }
00318 
00319         m = lend;
00320 
00321 L60:
00322         if (m < lend) {
00323             e[m] = 0.f;
00324         }
00325         p = d__[l];
00326         if (m == l) {
00327             goto L80;
00328         }
00329 
00330 /*        If remaining matrix is 2-by-2, use SLAE2 or SLAEV2 */
00331 /*        to compute its eigensystem. */
00332 
00333         if (m == l + 1) {
00334             if (icompz > 0) {
00335                 slaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s);
00336                 work[l] = c__;
00337                 work[*n - 1 + l] = s;
00338                 slasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], &
00339                         z__[l * z_dim1 + 1], ldz);
00340             } else {
00341                 slae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2);
00342             }
00343             d__[l] = rt1;
00344             d__[l + 1] = rt2;
00345             e[l] = 0.f;
00346             l += 2;
00347             if (l <= lend) {
00348                 goto L40;
00349             }
00350             goto L140;
00351         }
00352 
00353         if (jtot == nmaxit) {
00354             goto L140;
00355         }
00356         ++jtot;
00357 
00358 /*        Form shift. */
00359 
00360         g = (d__[l + 1] - p) / (e[l] * 2.f);
00361         r__ = slapy2_(&g, &c_b10);
00362         g = d__[m] - p + e[l] / (g + r_sign(&r__, &g));
00363 
00364         s = 1.f;
00365         c__ = 1.f;
00366         p = 0.f;
00367 
00368 /*        Inner loop */
00369 
00370         mm1 = m - 1;
00371         i__1 = l;
00372         for (i__ = mm1; i__ >= i__1; --i__) {
00373             f = s * e[i__];
00374             b = c__ * e[i__];
00375             slartg_(&g, &f, &c__, &s, &r__);
00376             if (i__ != m - 1) {
00377                 e[i__ + 1] = r__;
00378             }
00379             g = d__[i__ + 1] - p;
00380             r__ = (d__[i__] - g) * s + c__ * 2.f * b;
00381             p = s * r__;
00382             d__[i__ + 1] = g + p;
00383             g = c__ * r__ - b;
00384 
00385 /*           If eigenvectors are desired, then save rotations. */
00386 
00387             if (icompz > 0) {
00388                 work[i__] = c__;
00389                 work[*n - 1 + i__] = -s;
00390             }
00391 
00392 /* L70: */
00393         }
00394 
00395 /*        If eigenvectors are desired, then apply saved rotations. */
00396 
00397         if (icompz > 0) {
00398             mm = m - l + 1;
00399             slasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l 
00400                     * z_dim1 + 1], ldz);
00401         }
00402 
00403         d__[l] -= p;
00404         e[l] = g;
00405         goto L40;
00406 
00407 /*        Eigenvalue found. */
00408 
00409 L80:
00410         d__[l] = p;
00411 
00412         ++l;
00413         if (l <= lend) {
00414             goto L40;
00415         }
00416         goto L140;
00417 
00418     } else {
00419 
00420 /*        QR Iteration */
00421 
00422 /*        Look for small superdiagonal element. */
00423 
00424 L90:
00425         if (l != lend) {
00426             lendp1 = lend + 1;
00427             i__1 = lendp1;
00428             for (m = l; m >= i__1; --m) {
00429 /* Computing 2nd power */
00430                 r__2 = (r__1 = e[m - 1], dabs(r__1));
00431                 tst = r__2 * r__2;
00432                 if (tst <= eps2 * (r__1 = d__[m], dabs(r__1)) * (r__2 = d__[m 
00433                         - 1], dabs(r__2)) + safmin) {
00434                     goto L110;
00435                 }
00436 /* L100: */
00437             }
00438         }
00439 
00440         m = lend;
00441 
00442 L110:
00443         if (m > lend) {
00444             e[m - 1] = 0.f;
00445         }
00446         p = d__[l];
00447         if (m == l) {
00448             goto L130;
00449         }
00450 
00451 /*        If remaining matrix is 2-by-2, use SLAE2 or SLAEV2 */
00452 /*        to compute its eigensystem. */
00453 
00454         if (m == l - 1) {
00455             if (icompz > 0) {
00456                 slaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s)
00457                         ;
00458                 work[m] = c__;
00459                 work[*n - 1 + m] = s;
00460                 slasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], &
00461                         z__[(l - 1) * z_dim1 + 1], ldz);
00462             } else {
00463                 slae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2);
00464             }
00465             d__[l - 1] = rt1;
00466             d__[l] = rt2;
00467             e[l - 1] = 0.f;
00468             l += -2;
00469             if (l >= lend) {
00470                 goto L90;
00471             }
00472             goto L140;
00473         }
00474 
00475         if (jtot == nmaxit) {
00476             goto L140;
00477         }
00478         ++jtot;
00479 
00480 /*        Form shift. */
00481 
00482         g = (d__[l - 1] - p) / (e[l - 1] * 2.f);
00483         r__ = slapy2_(&g, &c_b10);
00484         g = d__[m] - p + e[l - 1] / (g + r_sign(&r__, &g));
00485 
00486         s = 1.f;
00487         c__ = 1.f;
00488         p = 0.f;
00489 
00490 /*        Inner loop */
00491 
00492         lm1 = l - 1;
00493         i__1 = lm1;
00494         for (i__ = m; i__ <= i__1; ++i__) {
00495             f = s * e[i__];
00496             b = c__ * e[i__];
00497             slartg_(&g, &f, &c__, &s, &r__);
00498             if (i__ != m) {
00499                 e[i__ - 1] = r__;
00500             }
00501             g = d__[i__] - p;
00502             r__ = (d__[i__ + 1] - g) * s + c__ * 2.f * b;
00503             p = s * r__;
00504             d__[i__] = g + p;
00505             g = c__ * r__ - b;
00506 
00507 /*           If eigenvectors are desired, then save rotations. */
00508 
00509             if (icompz > 0) {
00510                 work[i__] = c__;
00511                 work[*n - 1 + i__] = s;
00512             }
00513 
00514 /* L120: */
00515         }
00516 
00517 /*        If eigenvectors are desired, then apply saved rotations. */
00518 
00519         if (icompz > 0) {
00520             mm = l - m + 1;
00521             slasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m 
00522                     * z_dim1 + 1], ldz);
00523         }
00524 
00525         d__[l] -= p;
00526         e[lm1] = g;
00527         goto L90;
00528 
00529 /*        Eigenvalue found. */
00530 
00531 L130:
00532         d__[l] = p;
00533 
00534         --l;
00535         if (l >= lend) {
00536             goto L90;
00537         }
00538         goto L140;
00539 
00540     }
00541 
00542 /*     Undo scaling if necessary */
00543 
00544 L140:
00545     if (iscale == 1) {
00546         i__1 = lendsv - lsv + 1;
00547         slascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], 
00548                 n, info);
00549         i__1 = lendsv - lsv;
00550         slascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, 
00551                 info);
00552     } else if (iscale == 2) {
00553         i__1 = lendsv - lsv + 1;
00554         slascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], 
00555                 n, info);
00556         i__1 = lendsv - lsv;
00557         slascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, 
00558                 info);
00559     }
00560 
00561 /*     Check for no convergence to an eigenvalue after a total */
00562 /*     of N*MAXIT iterations. */
00563 
00564     if (jtot < nmaxit) {
00565         goto L10;
00566     }
00567     i__1 = *n - 1;
00568     for (i__ = 1; i__ <= i__1; ++i__) {
00569         if (e[i__] != 0.f) {
00570             ++(*info);
00571         }
00572 /* L150: */
00573     }
00574     goto L190;
00575 
00576 /*     Order eigenvalues and eigenvectors. */
00577 
00578 L160:
00579     if (icompz == 0) {
00580 
00581 /*        Use Quick Sort */
00582 
00583         slasrt_("I", n, &d__[1], info);
00584 
00585     } else {
00586 
00587 /*        Use Selection Sort to minimize swaps of eigenvectors */
00588 
00589         i__1 = *n;
00590         for (ii = 2; ii <= i__1; ++ii) {
00591             i__ = ii - 1;
00592             k = i__;
00593             p = d__[i__];
00594             i__2 = *n;
00595             for (j = ii; j <= i__2; ++j) {
00596                 if (d__[j] < p) {
00597                     k = j;
00598                     p = d__[j];
00599                 }
00600 /* L170: */
00601             }
00602             if (k != i__) {
00603                 d__[k] = d__[i__];
00604                 d__[i__] = p;
00605                 sswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], 
00606                          &c__1);
00607             }
00608 /* L180: */
00609         }
00610     }
00611 
00612 L190:
00613     return 0;
00614 
00615 /*     End of SSTEQR */
00616 
00617 } /* ssteqr_ */


swiftnav
Author(s):
autogenerated on Sat Jun 8 2019 18:56:14