zlaed0.c
Go to the documentation of this file.
00001 /* zlaed0.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 integer c__1 = 1;
00022 
00023 /* Subroutine */ int zlaed0_(integer *qsiz, integer *n, doublereal *d__, 
00024         doublereal *e, doublecomplex *q, integer *ldq, doublecomplex *qstore, 
00025         integer *ldqs, doublereal *rwork, integer *iwork, integer *info)
00026 {
00027     /* System generated locals */
00028     integer q_dim1, q_offset, qstore_dim1, qstore_offset, i__1, i__2;
00029     doublereal d__1;
00030 
00031     /* Builtin functions */
00032     double log(doublereal);
00033     integer pow_ii(integer *, integer *);
00034 
00035     /* Local variables */
00036     integer i__, j, k, ll, iq, lgn, msd2, smm1, spm1, spm2;
00037     doublereal temp;
00038     integer curr, iperm;
00039     extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, 
00040             doublereal *, integer *);
00041     integer indxq, iwrem, iqptr, tlvls;
00042     extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, 
00043             doublecomplex *, integer *), zlaed7_(integer *, integer *, 
00044             integer *, integer *, integer *, integer *, doublereal *, 
00045             doublecomplex *, integer *, doublereal *, integer *, doublereal *, 
00046              integer *, integer *, integer *, integer *, integer *, 
00047             doublereal *, doublecomplex *, doublereal *, integer *, integer *)
00048             ;
00049     integer igivcl;
00050     extern /* Subroutine */ int xerbla_(char *, integer *);
00051     extern integer ilaenv_(integer *, char *, char *, integer *, integer *, 
00052             integer *, integer *);
00053     extern /* Subroutine */ int zlacrm_(integer *, integer *, doublecomplex *, 
00054              integer *, doublereal *, integer *, doublecomplex *, integer *, 
00055             doublereal *);
00056     integer igivnm, submat, curprb, subpbs, igivpt;
00057     extern /* Subroutine */ int dsteqr_(char *, integer *, doublereal *, 
00058             doublereal *, doublereal *, integer *, doublereal *, integer *);
00059     integer curlvl, matsiz, iprmpt, smlsiz;
00060 
00061 
00062 /*  -- LAPACK routine (version 3.2) -- */
00063 /*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
00064 /*     November 2006 */
00065 
00066 /*     .. Scalar Arguments .. */
00067 /*     .. */
00068 /*     .. Array Arguments .. */
00069 /*     .. */
00070 
00071 /*  Purpose */
00072 /*  ======= */
00073 
00074 /*  Using the divide and conquer method, ZLAED0 computes all eigenvalues */
00075 /*  of a symmetric tridiagonal matrix which is one diagonal block of */
00076 /*  those from reducing a dense or band Hermitian matrix and */
00077 /*  corresponding eigenvectors of the dense or band matrix. */
00078 
00079 /*  Arguments */
00080 /*  ========= */
00081 
00082 /*  QSIZ   (input) INTEGER */
00083 /*         The dimension of the unitary matrix used to reduce */
00084 /*         the full matrix to tridiagonal form.  QSIZ >= N if ICOMPQ = 1. */
00085 
00086 /*  N      (input) INTEGER */
00087 /*         The dimension of the symmetric tridiagonal matrix.  N >= 0. */
00088 
00089 /*  D      (input/output) DOUBLE PRECISION array, dimension (N) */
00090 /*         On entry, the diagonal elements of the tridiagonal matrix. */
00091 /*         On exit, the eigenvalues in ascending order. */
00092 
00093 /*  E      (input/output) DOUBLE PRECISION array, dimension (N-1) */
00094 /*         On entry, the off-diagonal elements of the tridiagonal matrix. */
00095 /*         On exit, E has been destroyed. */
00096 
00097 /*  Q      (input/output) COMPLEX*16 array, dimension (LDQ,N) */
00098 /*         On entry, Q must contain an QSIZ x N matrix whose columns */
00099 /*         unitarily orthonormal. It is a part of the unitary matrix */
00100 /*         that reduces the full dense Hermitian matrix to a */
00101 /*         (reducible) symmetric tridiagonal matrix. */
00102 
00103 /*  LDQ    (input) INTEGER */
00104 /*         The leading dimension of the array Q.  LDQ >= max(1,N). */
00105 
00106 /*  IWORK  (workspace) INTEGER array, */
00107 /*         the dimension of IWORK must be at least */
00108 /*                      6 + 6*N + 5*N*lg N */
00109 /*                      ( lg( N ) = smallest integer k */
00110 /*                                  such that 2^k >= N ) */
00111 
00112 /*  RWORK  (workspace) DOUBLE PRECISION array, */
00113 /*                               dimension (1 + 3*N + 2*N*lg N + 3*N**2) */
00114 /*                        ( lg( N ) = smallest integer k */
00115 /*                                    such that 2^k >= N ) */
00116 
00117 /*  QSTORE (workspace) COMPLEX*16 array, dimension (LDQS, N) */
00118 /*         Used to store parts of */
00119 /*         the eigenvector matrix when the updating matrix multiplies */
00120 /*         take place. */
00121 
00122 /*  LDQS   (input) INTEGER */
00123 /*         The leading dimension of the array QSTORE. */
00124 /*         LDQS >= max(1,N). */
00125 
00126 /*  INFO   (output) INTEGER */
00127 /*          = 0:  successful exit. */
00128 /*          < 0:  if INFO = -i, the i-th argument had an illegal value. */
00129 /*          > 0:  The algorithm failed to compute an eigenvalue while */
00130 /*                working on the submatrix lying in rows and columns */
00131 /*                INFO/(N+1) through mod(INFO,N+1). */
00132 
00133 /*  ===================================================================== */
00134 
00135 /*  Warning:      N could be as big as QSIZ! */
00136 
00137 /*     .. Parameters .. */
00138 /*     .. */
00139 /*     .. Local Scalars .. */
00140 /*     .. */
00141 /*     .. External Subroutines .. */
00142 /*     .. */
00143 /*     .. External Functions .. */
00144 /*     .. */
00145 /*     .. Intrinsic Functions .. */
00146 /*     .. */
00147 /*     .. Executable Statements .. */
00148 
00149 /*     Test the input parameters. */
00150 
00151     /* Parameter adjustments */
00152     --d__;
00153     --e;
00154     q_dim1 = *ldq;
00155     q_offset = 1 + q_dim1;
00156     q -= q_offset;
00157     qstore_dim1 = *ldqs;
00158     qstore_offset = 1 + qstore_dim1;
00159     qstore -= qstore_offset;
00160     --rwork;
00161     --iwork;
00162 
00163     /* Function Body */
00164     *info = 0;
00165 
00166 /*     IF( ICOMPQ .LT. 0 .OR. ICOMPQ .GT. 2 ) THEN */
00167 /*        INFO = -1 */
00168 /*     ELSE IF( ( ICOMPQ .EQ. 1 ) .AND. ( QSIZ .LT. MAX( 0, N ) ) ) */
00169 /*    $        THEN */
00170     if (*qsiz < max(0,*n)) {
00171         *info = -1;
00172     } else if (*n < 0) {
00173         *info = -2;
00174     } else if (*ldq < max(1,*n)) {
00175         *info = -6;
00176     } else if (*ldqs < max(1,*n)) {
00177         *info = -8;
00178     }
00179     if (*info != 0) {
00180         i__1 = -(*info);
00181         xerbla_("ZLAED0", &i__1);
00182         return 0;
00183     }
00184 
00185 /*     Quick return if possible */
00186 
00187     if (*n == 0) {
00188         return 0;
00189     }
00190 
00191     smlsiz = ilaenv_(&c__9, "ZLAED0", " ", &c__0, &c__0, &c__0, &c__0);
00192 
00193 /*     Determine the size and placement of the submatrices, and save in */
00194 /*     the leading elements of IWORK. */
00195 
00196     iwork[1] = *n;
00197     subpbs = 1;
00198     tlvls = 0;
00199 L10:
00200     if (iwork[subpbs] > smlsiz) {
00201         for (j = subpbs; j >= 1; --j) {
00202             iwork[j * 2] = (iwork[j] + 1) / 2;
00203             iwork[(j << 1) - 1] = iwork[j] / 2;
00204 /* L20: */
00205         }
00206         ++tlvls;
00207         subpbs <<= 1;
00208         goto L10;
00209     }
00210     i__1 = subpbs;
00211     for (j = 2; j <= i__1; ++j) {
00212         iwork[j] += iwork[j - 1];
00213 /* L30: */
00214     }
00215 
00216 /*     Divide the matrix into SUBPBS submatrices of size at most SMLSIZ+1 */
00217 /*     using rank-1 modifications (cuts). */
00218 
00219     spm1 = subpbs - 1;
00220     i__1 = spm1;
00221     for (i__ = 1; i__ <= i__1; ++i__) {
00222         submat = iwork[i__] + 1;
00223         smm1 = submat - 1;
00224         d__[smm1] -= (d__1 = e[smm1], abs(d__1));
00225         d__[submat] -= (d__1 = e[smm1], abs(d__1));
00226 /* L40: */
00227     }
00228 
00229     indxq = (*n << 2) + 3;
00230 
00231 /*     Set up workspaces for eigenvalues only/accumulate new vectors */
00232 /*     routine */
00233 
00234     temp = log((doublereal) (*n)) / log(2.);
00235     lgn = (integer) temp;
00236     if (pow_ii(&c__2, &lgn) < *n) {
00237         ++lgn;
00238     }
00239     if (pow_ii(&c__2, &lgn) < *n) {
00240         ++lgn;
00241     }
00242     iprmpt = indxq + *n + 1;
00243     iperm = iprmpt + *n * lgn;
00244     iqptr = iperm + *n * lgn;
00245     igivpt = iqptr + *n + 2;
00246     igivcl = igivpt + *n * lgn;
00247 
00248     igivnm = 1;
00249     iq = igivnm + (*n << 1) * lgn;
00250 /* Computing 2nd power */
00251     i__1 = *n;
00252     iwrem = iq + i__1 * i__1 + 1;
00253 /*     Initialize pointers */
00254     i__1 = subpbs;
00255     for (i__ = 0; i__ <= i__1; ++i__) {
00256         iwork[iprmpt + i__] = 1;
00257         iwork[igivpt + i__] = 1;
00258 /* L50: */
00259     }
00260     iwork[iqptr] = 1;
00261 
00262 /*     Solve each submatrix eigenproblem at the bottom of the divide and */
00263 /*     conquer tree. */
00264 
00265     curr = 0;
00266     i__1 = spm1;
00267     for (i__ = 0; i__ <= i__1; ++i__) {
00268         if (i__ == 0) {
00269             submat = 1;
00270             matsiz = iwork[1];
00271         } else {
00272             submat = iwork[i__] + 1;
00273             matsiz = iwork[i__ + 1] - iwork[i__];
00274         }
00275         ll = iq - 1 + iwork[iqptr + curr];
00276         dsteqr_("I", &matsiz, &d__[submat], &e[submat], &rwork[ll], &matsiz, &
00277                 rwork[1], info);
00278         zlacrm_(qsiz, &matsiz, &q[submat * q_dim1 + 1], ldq, &rwork[ll], &
00279                 matsiz, &qstore[submat * qstore_dim1 + 1], ldqs, &rwork[iwrem]
00280 );
00281 /* Computing 2nd power */
00282         i__2 = matsiz;
00283         iwork[iqptr + curr + 1] = iwork[iqptr + curr] + i__2 * i__2;
00284         ++curr;
00285         if (*info > 0) {
00286             *info = submat * (*n + 1) + submat + matsiz - 1;
00287             return 0;
00288         }
00289         k = 1;
00290         i__2 = iwork[i__ + 1];
00291         for (j = submat; j <= i__2; ++j) {
00292             iwork[indxq + j] = k;
00293             ++k;
00294 /* L60: */
00295         }
00296 /* L70: */
00297     }
00298 
00299 /*     Successively merge eigensystems of adjacent submatrices */
00300 /*     into eigensystem for the corresponding larger matrix. */
00301 
00302 /*     while ( SUBPBS > 1 ) */
00303 
00304     curlvl = 1;
00305 L80:
00306     if (subpbs > 1) {
00307         spm2 = subpbs - 2;
00308         i__1 = spm2;
00309         for (i__ = 0; i__ <= i__1; i__ += 2) {
00310             if (i__ == 0) {
00311                 submat = 1;
00312                 matsiz = iwork[2];
00313                 msd2 = iwork[1];
00314                 curprb = 0;
00315             } else {
00316                 submat = iwork[i__] + 1;
00317                 matsiz = iwork[i__ + 2] - iwork[i__];
00318                 msd2 = matsiz / 2;
00319                 ++curprb;
00320             }
00321 
00322 /*     Merge lower order eigensystems (of size MSD2 and MATSIZ - MSD2) */
00323 /*     into an eigensystem of size MATSIZ.  ZLAED7 handles the case */
00324 /*     when the eigenvectors of a full or band Hermitian matrix (which */
00325 /*     was reduced to tridiagonal form) are desired. */
00326 
00327 /*     I am free to use Q as a valuable working space until Loop 150. */
00328 
00329             zlaed7_(&matsiz, &msd2, qsiz, &tlvls, &curlvl, &curprb, &d__[
00330                     submat], &qstore[submat * qstore_dim1 + 1], ldqs, &e[
00331                     submat + msd2 - 1], &iwork[indxq + submat], &rwork[iq], &
00332                     iwork[iqptr], &iwork[iprmpt], &iwork[iperm], &iwork[
00333                     igivpt], &iwork[igivcl], &rwork[igivnm], &q[submat * 
00334                     q_dim1 + 1], &rwork[iwrem], &iwork[subpbs + 1], info);
00335             if (*info > 0) {
00336                 *info = submat * (*n + 1) + submat + matsiz - 1;
00337                 return 0;
00338             }
00339             iwork[i__ / 2 + 1] = iwork[i__ + 2];
00340 /* L90: */
00341         }
00342         subpbs /= 2;
00343         ++curlvl;
00344         goto L80;
00345     }
00346 
00347 /*     end while */
00348 
00349 /*     Re-merge the eigenvalues/vectors which were deflated at the final */
00350 /*     merge step. */
00351 
00352     i__1 = *n;
00353     for (i__ = 1; i__ <= i__1; ++i__) {
00354         j = iwork[indxq + i__];
00355         rwork[i__] = d__[j];
00356         zcopy_(qsiz, &qstore[j * qstore_dim1 + 1], &c__1, &q[i__ * q_dim1 + 1]
00357 , &c__1);
00358 /* L100: */
00359     }
00360     dcopy_(n, &rwork[1], &c__1, &d__[1], &c__1);
00361 
00362     return 0;
00363 
00364 /*     End of ZLAED0 */
00365 
00366 } /* zlaed0_ */


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