00001 /* zhpevd.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__1 = 1; 00019 00020 /* Subroutine */ int zhpevd_(char *jobz, char *uplo, integer *n, 00021 doublecomplex *ap, doublereal *w, doublecomplex *z__, integer *ldz, 00022 doublecomplex *work, integer *lwork, doublereal *rwork, integer * 00023 lrwork, integer *iwork, integer *liwork, integer *info) 00024 { 00025 /* System generated locals */ 00026 integer z_dim1, z_offset, i__1; 00027 doublereal d__1; 00028 00029 /* Builtin functions */ 00030 double sqrt(doublereal); 00031 00032 /* Local variables */ 00033 doublereal eps; 00034 integer inde; 00035 doublereal anrm; 00036 integer imax; 00037 doublereal rmin, rmax; 00038 extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, 00039 integer *); 00040 doublereal sigma; 00041 extern logical lsame_(char *, char *); 00042 integer iinfo, lwmin, llrwk, llwrk; 00043 logical wantz; 00044 extern doublereal dlamch_(char *); 00045 integer iscale; 00046 doublereal safmin; 00047 extern /* Subroutine */ int xerbla_(char *, integer *), zdscal_( 00048 integer *, doublereal *, doublecomplex *, integer *); 00049 doublereal bignum; 00050 integer indtau; 00051 extern /* Subroutine */ int dsterf_(integer *, doublereal *, doublereal *, 00052 integer *); 00053 extern doublereal zlanhp_(char *, char *, integer *, doublecomplex *, 00054 doublereal *); 00055 extern /* Subroutine */ int zstedc_(char *, integer *, doublereal *, 00056 doublereal *, doublecomplex *, integer *, doublecomplex *, 00057 integer *, doublereal *, integer *, integer *, integer *, integer 00058 *); 00059 integer indrwk, indwrk, liwmin, lrwmin; 00060 doublereal smlnum; 00061 extern /* Subroutine */ int zhptrd_(char *, integer *, doublecomplex *, 00062 doublereal *, doublereal *, doublecomplex *, integer *); 00063 logical lquery; 00064 extern /* Subroutine */ int zupmtr_(char *, char *, char *, integer *, 00065 integer *, doublecomplex *, doublecomplex *, doublecomplex *, 00066 integer *, doublecomplex *, integer *); 00067 00068 00069 /* -- LAPACK driver routine (version 3.2) -- */ 00070 /* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ 00071 /* November 2006 */ 00072 00073 /* .. Scalar Arguments .. */ 00074 /* .. */ 00075 /* .. Array Arguments .. */ 00076 /* .. */ 00077 00078 /* Purpose */ 00079 /* ======= */ 00080 00081 /* ZHPEVD computes all the eigenvalues and, optionally, eigenvectors of */ 00082 /* a complex Hermitian matrix A in packed storage. If eigenvectors are */ 00083 /* desired, it uses a divide and conquer algorithm. */ 00084 00085 /* The divide and conquer algorithm makes very mild assumptions about */ 00086 /* floating point arithmetic. It will work on machines with a guard */ 00087 /* digit in add/subtract, or on those binary machines without guard */ 00088 /* digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or */ 00089 /* Cray-2. It could conceivably fail on hexadecimal or decimal machines */ 00090 /* without guard digits, but we know of none. */ 00091 00092 /* Arguments */ 00093 /* ========= */ 00094 00095 /* JOBZ (input) CHARACTER*1 */ 00096 /* = 'N': Compute eigenvalues only; */ 00097 /* = 'V': Compute eigenvalues and eigenvectors. */ 00098 00099 /* UPLO (input) CHARACTER*1 */ 00100 /* = 'U': Upper triangle of A is stored; */ 00101 /* = 'L': Lower triangle of A is stored. */ 00102 00103 /* N (input) INTEGER */ 00104 /* The order of the matrix A. N >= 0. */ 00105 00106 /* AP (input/output) COMPLEX*16 array, dimension (N*(N+1)/2) */ 00107 /* On entry, the upper or lower triangle of the Hermitian matrix */ 00108 /* A, packed columnwise in a linear array. The j-th column of A */ 00109 /* is stored in the array AP as follows: */ 00110 /* if UPLO = 'U', AP(i + (j-1)*j/2) = A(i,j) for 1<=i<=j; */ 00111 /* if UPLO = 'L', AP(i + (j-1)*(2*n-j)/2) = A(i,j) for j<=i<=n. */ 00112 00113 /* On exit, AP is overwritten by values generated during the */ 00114 /* reduction to tridiagonal form. If UPLO = 'U', the diagonal */ 00115 /* and first superdiagonal of the tridiagonal matrix T overwrite */ 00116 /* the corresponding elements of A, and if UPLO = 'L', the */ 00117 /* diagonal and first subdiagonal of T overwrite the */ 00118 /* corresponding elements of A. */ 00119 00120 /* W (output) DOUBLE PRECISION array, dimension (N) */ 00121 /* If INFO = 0, the eigenvalues in ascending order. */ 00122 00123 /* Z (output) COMPLEX*16 array, dimension (LDZ, N) */ 00124 /* If JOBZ = 'V', then if INFO = 0, Z contains the orthonormal */ 00125 /* eigenvectors of the matrix A, with the i-th column of Z */ 00126 /* holding the eigenvector associated with W(i). */ 00127 /* If JOBZ = 'N', then Z is not referenced. */ 00128 00129 /* LDZ (input) INTEGER */ 00130 /* The leading dimension of the array Z. LDZ >= 1, and if */ 00131 /* JOBZ = 'V', LDZ >= max(1,N). */ 00132 00133 /* WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) */ 00134 /* On exit, if INFO = 0, WORK(1) returns the required LWORK. */ 00135 00136 /* LWORK (input) INTEGER */ 00137 /* The dimension of array WORK. */ 00138 /* If N <= 1, LWORK must be at least 1. */ 00139 /* If JOBZ = 'N' and N > 1, LWORK must be at least N. */ 00140 /* If JOBZ = 'V' and N > 1, LWORK must be at least 2*N. */ 00141 00142 /* If LWORK = -1, then a workspace query is assumed; the routine */ 00143 /* only calculates the required sizes of the WORK, RWORK and */ 00144 /* IWORK arrays, returns these values as the first entries of */ 00145 /* the WORK, RWORK and IWORK arrays, and no error message */ 00146 /* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ 00147 00148 /* RWORK (workspace/output) DOUBLE PRECISION array, */ 00149 /* dimension (LRWORK) */ 00150 /* On exit, if INFO = 0, RWORK(1) returns the required LRWORK. */ 00151 00152 /* LRWORK (input) INTEGER */ 00153 /* The dimension of array RWORK. */ 00154 /* If N <= 1, LRWORK must be at least 1. */ 00155 /* If JOBZ = 'N' and N > 1, LRWORK must be at least N. */ 00156 /* If JOBZ = 'V' and N > 1, LRWORK must be at least */ 00157 /* 1 + 5*N + 2*N**2. */ 00158 00159 /* If LRWORK = -1, then a workspace query is assumed; the */ 00160 /* routine only calculates the required sizes of the WORK, RWORK */ 00161 /* and IWORK arrays, returns these values as the first entries */ 00162 /* of the WORK, RWORK and IWORK arrays, and no error message */ 00163 /* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ 00164 00165 /* IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) */ 00166 /* On exit, if INFO = 0, IWORK(1) returns the required LIWORK. */ 00167 00168 /* LIWORK (input) INTEGER */ 00169 /* The dimension of array IWORK. */ 00170 /* If JOBZ = 'N' or N <= 1, LIWORK must be at least 1. */ 00171 /* If JOBZ = 'V' and N > 1, LIWORK must be at least 3 + 5*N. */ 00172 00173 /* If LIWORK = -1, then a workspace query is assumed; the */ 00174 /* routine only calculates the required sizes of the WORK, RWORK */ 00175 /* and IWORK arrays, returns these values as the first entries */ 00176 /* of the WORK, RWORK and IWORK arrays, and no error message */ 00177 /* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ 00178 00179 /* INFO (output) INTEGER */ 00180 /* = 0: successful exit */ 00181 /* < 0: if INFO = -i, the i-th argument had an illegal value. */ 00182 /* > 0: if INFO = i, the algorithm failed to converge; i */ 00183 /* off-diagonal elements of an intermediate tridiagonal */ 00184 /* form did not converge to zero. */ 00185 00186 /* ===================================================================== */ 00187 00188 /* .. Parameters .. */ 00189 /* .. */ 00190 /* .. Local Scalars .. */ 00191 /* .. */ 00192 /* .. External Functions .. */ 00193 /* .. */ 00194 /* .. External Subroutines .. */ 00195 /* .. */ 00196 /* .. Intrinsic Functions .. */ 00197 /* .. */ 00198 /* .. Executable Statements .. */ 00199 00200 /* Test the input parameters. */ 00201 00202 /* Parameter adjustments */ 00203 --ap; 00204 --w; 00205 z_dim1 = *ldz; 00206 z_offset = 1 + z_dim1; 00207 z__ -= z_offset; 00208 --work; 00209 --rwork; 00210 --iwork; 00211 00212 /* Function Body */ 00213 wantz = lsame_(jobz, "V"); 00214 lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1; 00215 00216 *info = 0; 00217 if (! (wantz || lsame_(jobz, "N"))) { 00218 *info = -1; 00219 } else if (! (lsame_(uplo, "L") || lsame_(uplo, 00220 "U"))) { 00221 *info = -2; 00222 } else if (*n < 0) { 00223 *info = -3; 00224 } else if (*ldz < 1 || wantz && *ldz < *n) { 00225 *info = -7; 00226 } 00227 00228 if (*info == 0) { 00229 if (*n <= 1) { 00230 lwmin = 1; 00231 liwmin = 1; 00232 lrwmin = 1; 00233 } else { 00234 if (wantz) { 00235 lwmin = *n << 1; 00236 /* Computing 2nd power */ 00237 i__1 = *n; 00238 lrwmin = *n * 5 + 1 + (i__1 * i__1 << 1); 00239 liwmin = *n * 5 + 3; 00240 } else { 00241 lwmin = *n; 00242 lrwmin = *n; 00243 liwmin = 1; 00244 } 00245 } 00246 work[1].r = (doublereal) lwmin, work[1].i = 0.; 00247 rwork[1] = (doublereal) lrwmin; 00248 iwork[1] = liwmin; 00249 00250 if (*lwork < lwmin && ! lquery) { 00251 *info = -9; 00252 } else if (*lrwork < lrwmin && ! lquery) { 00253 *info = -11; 00254 } else if (*liwork < liwmin && ! lquery) { 00255 *info = -13; 00256 } 00257 } 00258 00259 if (*info != 0) { 00260 i__1 = -(*info); 00261 xerbla_("ZHPEVD", &i__1); 00262 return 0; 00263 } else if (lquery) { 00264 return 0; 00265 } 00266 00267 /* Quick return if possible */ 00268 00269 if (*n == 0) { 00270 return 0; 00271 } 00272 00273 if (*n == 1) { 00274 w[1] = ap[1].r; 00275 if (wantz) { 00276 i__1 = z_dim1 + 1; 00277 z__[i__1].r = 1., z__[i__1].i = 0.; 00278 } 00279 return 0; 00280 } 00281 00282 /* Get machine constants. */ 00283 00284 safmin = dlamch_("Safe minimum"); 00285 eps = dlamch_("Precision"); 00286 smlnum = safmin / eps; 00287 bignum = 1. / smlnum; 00288 rmin = sqrt(smlnum); 00289 rmax = sqrt(bignum); 00290 00291 /* Scale matrix to allowable range, if necessary. */ 00292 00293 anrm = zlanhp_("M", uplo, n, &ap[1], &rwork[1]); 00294 iscale = 0; 00295 if (anrm > 0. && anrm < rmin) { 00296 iscale = 1; 00297 sigma = rmin / anrm; 00298 } else if (anrm > rmax) { 00299 iscale = 1; 00300 sigma = rmax / anrm; 00301 } 00302 if (iscale == 1) { 00303 i__1 = *n * (*n + 1) / 2; 00304 zdscal_(&i__1, &sigma, &ap[1], &c__1); 00305 } 00306 00307 /* Call ZHPTRD to reduce Hermitian packed matrix to tridiagonal form. */ 00308 00309 inde = 1; 00310 indtau = 1; 00311 indrwk = inde + *n; 00312 indwrk = indtau + *n; 00313 llwrk = *lwork - indwrk + 1; 00314 llrwk = *lrwork - indrwk + 1; 00315 zhptrd_(uplo, n, &ap[1], &w[1], &rwork[inde], &work[indtau], &iinfo); 00316 00317 /* For eigenvalues only, call DSTERF. For eigenvectors, first call */ 00318 /* ZUPGTR to generate the orthogonal matrix, then call ZSTEDC. */ 00319 00320 if (! wantz) { 00321 dsterf_(n, &w[1], &rwork[inde], info); 00322 } else { 00323 zstedc_("I", n, &w[1], &rwork[inde], &z__[z_offset], ldz, &work[ 00324 indwrk], &llwrk, &rwork[indrwk], &llrwk, &iwork[1], liwork, 00325 info); 00326 zupmtr_("L", uplo, "N", n, n, &ap[1], &work[indtau], &z__[z_offset], 00327 ldz, &work[indwrk], &iinfo); 00328 } 00329 00330 /* If matrix was scaled, then rescale eigenvalues appropriately. */ 00331 00332 if (iscale == 1) { 00333 if (*info == 0) { 00334 imax = *n; 00335 } else { 00336 imax = *info - 1; 00337 } 00338 d__1 = 1. / sigma; 00339 dscal_(&imax, &d__1, &w[1], &c__1); 00340 } 00341 00342 work[1].r = (doublereal) lwmin, work[1].i = 0.; 00343 rwork[1] = (doublereal) lrwmin; 00344 iwork[1] = liwmin; 00345 return 0; 00346 00347 /* End of ZHPEVD */ 00348 00349 } /* zhpevd_ */