zstedc.c
Go to the documentation of this file.
00001 /* zstedc.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 integer c__9 = 9;
00019 static integer c__0 = 0;
00020 static integer c__2 = 2;
00021 static doublereal c_b17 = 0.;
00022 static doublereal c_b18 = 1.;
00023 static integer c__1 = 1;
00024 
00025 /* Subroutine */ int zstedc_(char *compz, integer *n, doublereal *d__, 
00026         doublereal *e, doublecomplex *z__, integer *ldz, doublecomplex *work, 
00027         integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, 
00028         integer *liwork, integer *info)
00029 {
00030     /* System generated locals */
00031     integer z_dim1, z_offset, i__1, i__2, i__3, i__4;
00032     doublereal d__1, d__2;
00033 
00034     /* Builtin functions */
00035     double log(doublereal);
00036     integer pow_ii(integer *, integer *);
00037     double sqrt(doublereal);
00038 
00039     /* Local variables */
00040     integer i__, j, k, m;
00041     doublereal p;
00042     integer ii, ll, lgn;
00043     doublereal eps, tiny;
00044     extern logical lsame_(char *, char *);
00045     integer lwmin, start;
00046     extern /* Subroutine */ int zswap_(integer *, doublecomplex *, integer *, 
00047             doublecomplex *, integer *), zlaed0_(integer *, integer *, 
00048             doublereal *, doublereal *, doublecomplex *, integer *, 
00049             doublecomplex *, integer *, doublereal *, integer *, integer *);
00050     extern doublereal dlamch_(char *);
00051     extern /* Subroutine */ int dlascl_(char *, integer *, integer *, 
00052             doublereal *, doublereal *, integer *, integer *, doublereal *, 
00053             integer *, integer *), dstedc_(char *, integer *, 
00054             doublereal *, doublereal *, doublereal *, integer *, doublereal *, 
00055              integer *, integer *, integer *, integer *), dlaset_(
00056             char *, integer *, integer *, doublereal *, doublereal *, 
00057             doublereal *, integer *), xerbla_(char *, integer *);
00058     extern integer ilaenv_(integer *, char *, char *, integer *, integer *, 
00059             integer *, integer *);
00060     integer finish;
00061     extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *);
00062     extern /* Subroutine */ int dsterf_(integer *, doublereal *, doublereal *, 
00063              integer *), zlacrm_(integer *, integer *, doublecomplex *, 
00064             integer *, doublereal *, integer *, doublecomplex *, integer *, 
00065             doublereal *);
00066     integer liwmin, icompz;
00067     extern /* Subroutine */ int dsteqr_(char *, integer *, doublereal *, 
00068             doublereal *, doublereal *, integer *, doublereal *, integer *), zlacpy_(char *, integer *, integer *, doublecomplex *, 
00069             integer *, doublecomplex *, integer *);
00070     doublereal orgnrm;
00071     integer lrwmin;
00072     logical lquery;
00073     integer smlsiz;
00074     extern /* Subroutine */ int zsteqr_(char *, integer *, doublereal *, 
00075             doublereal *, doublecomplex *, integer *, doublereal *, integer *);
00076 
00077 
00078 /*  -- LAPACK routine (version 3.2) -- */
00079 /*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
00080 /*     November 2006 */
00081 
00082 /*     .. Scalar Arguments .. */
00083 /*     .. */
00084 /*     .. Array Arguments .. */
00085 /*     .. */
00086 
00087 /*  Purpose */
00088 /*  ======= */
00089 
00090 /*  ZSTEDC computes all eigenvalues and, optionally, eigenvectors of a */
00091 /*  symmetric tridiagonal matrix using the divide and conquer method. */
00092 /*  The eigenvectors of a full or band complex Hermitian matrix can also */
00093 /*  be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this */
00094 /*  matrix to tridiagonal form. */
00095 
00096 /*  This code makes very mild assumptions about floating point */
00097 /*  arithmetic. It will work on machines with a guard digit in */
00098 /*  add/subtract, or on those binary machines without guard digits */
00099 /*  which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. */
00100 /*  It could conceivably fail on hexadecimal or decimal machines */
00101 /*  without guard digits, but we know of none.  See DLAED3 for details. */
00102 
00103 /*  Arguments */
00104 /*  ========= */
00105 
00106 /*  COMPZ   (input) CHARACTER*1 */
00107 /*          = 'N':  Compute eigenvalues only. */
00108 /*          = 'I':  Compute eigenvectors of tridiagonal matrix also. */
00109 /*          = 'V':  Compute eigenvectors of original Hermitian matrix */
00110 /*                  also.  On entry, Z contains the unitary matrix used */
00111 /*                  to reduce the original matrix to tridiagonal form. */
00112 
00113 /*  N       (input) INTEGER */
00114 /*          The dimension of the symmetric tridiagonal matrix.  N >= 0. */
00115 
00116 /*  D       (input/output) DOUBLE PRECISION array, dimension (N) */
00117 /*          On entry, the diagonal elements of the tridiagonal matrix. */
00118 /*          On exit, if INFO = 0, the eigenvalues in ascending order. */
00119 
00120 /*  E       (input/output) DOUBLE PRECISION array, dimension (N-1) */
00121 /*          On entry, the subdiagonal elements of the tridiagonal matrix. */
00122 /*          On exit, E has been destroyed. */
00123 
00124 /*  Z       (input/output) COMPLEX*16 array, dimension (LDZ,N) */
00125 /*          On entry, if COMPZ = 'V', then Z contains the unitary */
00126 /*          matrix used in the reduction to tridiagonal form. */
00127 /*          On exit, if INFO = 0, then if COMPZ = 'V', Z contains the */
00128 /*          orthonormal eigenvectors of the original Hermitian matrix, */
00129 /*          and if COMPZ = 'I', Z contains the orthonormal eigenvectors */
00130 /*          of the symmetric tridiagonal matrix. */
00131 /*          If  COMPZ = 'N', then Z is not referenced. */
00132 
00133 /*  LDZ     (input) INTEGER */
00134 /*          The leading dimension of the array Z.  LDZ >= 1. */
00135 /*          If eigenvectors are desired, then LDZ >= max(1,N). */
00136 
00137 /*  WORK    (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) */
00138 /*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */
00139 
00140 /*  LWORK   (input) INTEGER */
00141 /*          The dimension of the array WORK. */
00142 /*          If COMPZ = 'N' or 'I', or N <= 1, LWORK must be at least 1. */
00143 /*          If COMPZ = 'V' and N > 1, LWORK must be at least N*N. */
00144 /*          Note that for COMPZ = 'V', then if N is less than or */
00145 /*          equal to the minimum divide size, usually 25, then LWORK need */
00146 /*          only be 1. */
00147 
00148 /*          If LWORK = -1, then a workspace query is assumed; the routine */
00149 /*          only calculates the optimal sizes of the WORK, RWORK and */
00150 /*          IWORK arrays, returns these values as the first entries of */
00151 /*          the WORK, RWORK and IWORK arrays, and no error message */
00152 /*          related to LWORK or LRWORK or LIWORK is issued by XERBLA. */
00153 
00154 /*  RWORK   (workspace/output) DOUBLE PRECISION array, */
00155 /*                                         dimension (LRWORK) */
00156 /*          On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK. */
00157 
00158 /*  LRWORK  (input) INTEGER */
00159 /*          The dimension of the array RWORK. */
00160 /*          If COMPZ = 'N' or N <= 1, LRWORK must be at least 1. */
00161 /*          If COMPZ = 'V' and N > 1, LRWORK must be at least */
00162 /*                         1 + 3*N + 2*N*lg N + 3*N**2 , */
00163 /*                         where lg( N ) = smallest integer k such */
00164 /*                         that 2**k >= N. */
00165 /*          If COMPZ = 'I' and N > 1, LRWORK must be at least */
00166 /*                         1 + 4*N + 2*N**2 . */
00167 /*          Note that for COMPZ = 'I' or 'V', then if N is less than or */
00168 /*          equal to the minimum divide size, usually 25, then LRWORK */
00169 /*          need only be max(1,2*(N-1)). */
00170 
00171 /*          If LRWORK = -1, then a workspace query is assumed; the */
00172 /*          routine only calculates the optimal sizes of the WORK, RWORK */
00173 /*          and IWORK arrays, returns these values as the first entries */
00174 /*          of the WORK, RWORK and IWORK arrays, and no error message */
00175 /*          related to LWORK or LRWORK or LIWORK is issued by XERBLA. */
00176 
00177 /*  IWORK   (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) */
00178 /*          On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. */
00179 
00180 /*  LIWORK  (input) INTEGER */
00181 /*          The dimension of the array IWORK. */
00182 /*          If COMPZ = 'N' or N <= 1, LIWORK must be at least 1. */
00183 /*          If COMPZ = 'V' or N > 1,  LIWORK must be at least */
00184 /*                                    6 + 6*N + 5*N*lg N. */
00185 /*          If COMPZ = 'I' or N > 1,  LIWORK must be at least */
00186 /*                                    3 + 5*N . */
00187 /*          Note that for COMPZ = 'I' or 'V', then if N is less than or */
00188 /*          equal to the minimum divide size, usually 25, then LIWORK */
00189 /*          need only be 1. */
00190 
00191 /*          If LIWORK = -1, then a workspace query is assumed; the */
00192 /*          routine only calculates the optimal sizes of the WORK, RWORK */
00193 /*          and IWORK arrays, returns these values as the first entries */
00194 /*          of the WORK, RWORK and IWORK arrays, and no error message */
00195 /*          related to LWORK or LRWORK or LIWORK is issued by XERBLA. */
00196 
00197 /*  INFO    (output) INTEGER */
00198 /*          = 0:  successful exit. */
00199 /*          < 0:  if INFO = -i, the i-th argument had an illegal value. */
00200 /*          > 0:  The algorithm failed to compute an eigenvalue while */
00201 /*                working on the submatrix lying in rows and columns */
00202 /*                INFO/(N+1) through mod(INFO,N+1). */
00203 
00204 /*  Further Details */
00205 /*  =============== */
00206 
00207 /*  Based on contributions by */
00208 /*     Jeff Rutter, Computer Science Division, University of California */
00209 /*     at Berkeley, USA */
00210 
00211 /*  ===================================================================== */
00212 
00213 /*     .. Parameters .. */
00214 /*     .. */
00215 /*     .. Local Scalars .. */
00216 /*     .. */
00217 /*     .. External Functions .. */
00218 /*     .. */
00219 /*     .. External Subroutines .. */
00220 /*     .. */
00221 /*     .. Intrinsic Functions .. */
00222 /*     .. */
00223 /*     .. Executable Statements .. */
00224 
00225 /*     Test the input parameters. */
00226 
00227     /* Parameter adjustments */
00228     --d__;
00229     --e;
00230     z_dim1 = *ldz;
00231     z_offset = 1 + z_dim1;
00232     z__ -= z_offset;
00233     --work;
00234     --rwork;
00235     --iwork;
00236 
00237     /* Function Body */
00238     *info = 0;
00239     lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1;
00240 
00241     if (lsame_(compz, "N")) {
00242         icompz = 0;
00243     } else if (lsame_(compz, "V")) {
00244         icompz = 1;
00245     } else if (lsame_(compz, "I")) {
00246         icompz = 2;
00247     } else {
00248         icompz = -1;
00249     }
00250     if (icompz < 0) {
00251         *info = -1;
00252     } else if (*n < 0) {
00253         *info = -2;
00254     } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) {
00255         *info = -6;
00256     }
00257 
00258     if (*info == 0) {
00259 
00260 /*        Compute the workspace requirements */
00261 
00262         smlsiz = ilaenv_(&c__9, "ZSTEDC", " ", &c__0, &c__0, &c__0, &c__0);
00263         if (*n <= 1 || icompz == 0) {
00264             lwmin = 1;
00265             liwmin = 1;
00266             lrwmin = 1;
00267         } else if (*n <= smlsiz) {
00268             lwmin = 1;
00269             liwmin = 1;
00270             lrwmin = *n - 1 << 1;
00271         } else if (icompz == 1) {
00272             lgn = (integer) (log((doublereal) (*n)) / log(2.));
00273             if (pow_ii(&c__2, &lgn) < *n) {
00274                 ++lgn;
00275             }
00276             if (pow_ii(&c__2, &lgn) < *n) {
00277                 ++lgn;
00278             }
00279             lwmin = *n * *n;
00280 /* Computing 2nd power */
00281             i__1 = *n;
00282             lrwmin = *n * 3 + 1 + (*n << 1) * lgn + i__1 * i__1 * 3;
00283             liwmin = *n * 6 + 6 + *n * 5 * lgn;
00284         } else if (icompz == 2) {
00285             lwmin = 1;
00286 /* Computing 2nd power */
00287             i__1 = *n;
00288             lrwmin = (*n << 2) + 1 + (i__1 * i__1 << 1);
00289             liwmin = *n * 5 + 3;
00290         }
00291         work[1].r = (doublereal) lwmin, work[1].i = 0.;
00292         rwork[1] = (doublereal) lrwmin;
00293         iwork[1] = liwmin;
00294 
00295         if (*lwork < lwmin && ! lquery) {
00296             *info = -8;
00297         } else if (*lrwork < lrwmin && ! lquery) {
00298             *info = -10;
00299         } else if (*liwork < liwmin && ! lquery) {
00300             *info = -12;
00301         }
00302     }
00303 
00304     if (*info != 0) {
00305         i__1 = -(*info);
00306         xerbla_("ZSTEDC", &i__1);
00307         return 0;
00308     } else if (lquery) {
00309         return 0;
00310     }
00311 
00312 /*     Quick return if possible */
00313 
00314     if (*n == 0) {
00315         return 0;
00316     }
00317     if (*n == 1) {
00318         if (icompz != 0) {
00319             i__1 = z_dim1 + 1;
00320             z__[i__1].r = 1., z__[i__1].i = 0.;
00321         }
00322         return 0;
00323     }
00324 
00325 /*     If the following conditional clause is removed, then the routine */
00326 /*     will use the Divide and Conquer routine to compute only the */
00327 /*     eigenvalues, which requires (3N + 3N**2) real workspace and */
00328 /*     (2 + 5N + 2N lg(N)) integer workspace. */
00329 /*     Since on many architectures DSTERF is much faster than any other */
00330 /*     algorithm for finding eigenvalues only, it is used here */
00331 /*     as the default. If the conditional clause is removed, then */
00332 /*     information on the size of workspace needs to be changed. */
00333 
00334 /*     If COMPZ = 'N', use DSTERF to compute the eigenvalues. */
00335 
00336     if (icompz == 0) {
00337         dsterf_(n, &d__[1], &e[1], info);
00338         goto L70;
00339     }
00340 
00341 /*     If N is smaller than the minimum divide size (SMLSIZ+1), then */
00342 /*     solve the problem with another solver. */
00343 
00344     if (*n <= smlsiz) {
00345 
00346         zsteqr_(compz, n, &d__[1], &e[1], &z__[z_offset], ldz, &rwork[1], 
00347                 info);
00348 
00349     } else {
00350 
00351 /*        If COMPZ = 'I', we simply call DSTEDC instead. */
00352 
00353         if (icompz == 2) {
00354             dlaset_("Full", n, n, &c_b17, &c_b18, &rwork[1], n);
00355             ll = *n * *n + 1;
00356             i__1 = *lrwork - ll + 1;
00357             dstedc_("I", n, &d__[1], &e[1], &rwork[1], n, &rwork[ll], &i__1, &
00358                     iwork[1], liwork, info);
00359             i__1 = *n;
00360             for (j = 1; j <= i__1; ++j) {
00361                 i__2 = *n;
00362                 for (i__ = 1; i__ <= i__2; ++i__) {
00363                     i__3 = i__ + j * z_dim1;
00364                     i__4 = (j - 1) * *n + i__;
00365                     z__[i__3].r = rwork[i__4], z__[i__3].i = 0.;
00366 /* L10: */
00367                 }
00368 /* L20: */
00369             }
00370             goto L70;
00371         }
00372 
00373 /*        From now on, only option left to be handled is COMPZ = 'V', */
00374 /*        i.e. ICOMPZ = 1. */
00375 
00376 /*        Scale. */
00377 
00378         orgnrm = dlanst_("M", n, &d__[1], &e[1]);
00379         if (orgnrm == 0.) {
00380             goto L70;
00381         }
00382 
00383         eps = dlamch_("Epsilon");
00384 
00385         start = 1;
00386 
00387 /*        while ( START <= N ) */
00388 
00389 L30:
00390         if (start <= *n) {
00391 
00392 /*           Let FINISH be the position of the next subdiagonal entry */
00393 /*           such that E( FINISH ) <= TINY or FINISH = N if no such */
00394 /*           subdiagonal exists.  The matrix identified by the elements */
00395 /*           between START and FINISH constitutes an independent */
00396 /*           sub-problem. */
00397 
00398             finish = start;
00399 L40:
00400             if (finish < *n) {
00401                 tiny = eps * sqrt((d__1 = d__[finish], abs(d__1))) * sqrt((
00402                         d__2 = d__[finish + 1], abs(d__2)));
00403                 if ((d__1 = e[finish], abs(d__1)) > tiny) {
00404                     ++finish;
00405                     goto L40;
00406                 }
00407             }
00408 
00409 /*           (Sub) Problem determined.  Compute its size and solve it. */
00410 
00411             m = finish - start + 1;
00412             if (m > smlsiz) {
00413 
00414 /*              Scale. */
00415 
00416                 orgnrm = dlanst_("M", &m, &d__[start], &e[start]);
00417                 dlascl_("G", &c__0, &c__0, &orgnrm, &c_b18, &m, &c__1, &d__[
00418                         start], &m, info);
00419                 i__1 = m - 1;
00420                 i__2 = m - 1;
00421                 dlascl_("G", &c__0, &c__0, &orgnrm, &c_b18, &i__1, &c__1, &e[
00422                         start], &i__2, info);
00423 
00424                 zlaed0_(n, &m, &d__[start], &e[start], &z__[start * z_dim1 + 
00425                         1], ldz, &work[1], n, &rwork[1], &iwork[1], info);
00426                 if (*info > 0) {
00427                     *info = (*info / (m + 1) + start - 1) * (*n + 1) + *info %
00428                              (m + 1) + start - 1;
00429                     goto L70;
00430                 }
00431 
00432 /*              Scale back. */
00433 
00434                 dlascl_("G", &c__0, &c__0, &c_b18, &orgnrm, &m, &c__1, &d__[
00435                         start], &m, info);
00436 
00437             } else {
00438                 dsteqr_("I", &m, &d__[start], &e[start], &rwork[1], &m, &
00439                         rwork[m * m + 1], info);
00440                 zlacrm_(n, &m, &z__[start * z_dim1 + 1], ldz, &rwork[1], &m, &
00441                         work[1], n, &rwork[m * m + 1]);
00442                 zlacpy_("A", n, &m, &work[1], n, &z__[start * z_dim1 + 1], 
00443                         ldz);
00444                 if (*info > 0) {
00445                     *info = start * (*n + 1) + finish;
00446                     goto L70;
00447                 }
00448             }
00449 
00450             start = finish + 1;
00451             goto L30;
00452         }
00453 
00454 /*        endwhile */
00455 
00456 /*        If the problem split any number of times, then the eigenvalues */
00457 /*        will not be properly ordered.  Here we permute the eigenvalues */
00458 /*        (and the associated eigenvectors) into ascending order. */
00459 
00460         if (m != *n) {
00461 
00462 /*           Use Selection Sort to minimize swaps of eigenvectors */
00463 
00464             i__1 = *n;
00465             for (ii = 2; ii <= i__1; ++ii) {
00466                 i__ = ii - 1;
00467                 k = i__;
00468                 p = d__[i__];
00469                 i__2 = *n;
00470                 for (j = ii; j <= i__2; ++j) {
00471                     if (d__[j] < p) {
00472                         k = j;
00473                         p = d__[j];
00474                     }
00475 /* L50: */
00476                 }
00477                 if (k != i__) {
00478                     d__[k] = d__[i__];
00479                     d__[i__] = p;
00480                     zswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 
00481                             + 1], &c__1);
00482                 }
00483 /* L60: */
00484             }
00485         }
00486     }
00487 
00488 L70:
00489     work[1].r = (doublereal) lwmin, work[1].i = 0.;
00490     rwork[1] = (doublereal) lrwmin;
00491     iwork[1] = liwmin;
00492 
00493     return 0;
00494 
00495 /*     End of ZSTEDC */
00496 
00497 } /* zstedc_ */


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