ssyevd.c
Go to the documentation of this file.
00001 /* ssyevd.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 static integer c_n1 = -1;
00020 static integer c__0 = 0;
00021 static real c_b17 = 1.f;
00022 
00023 /* Subroutine */ int ssyevd_(char *jobz, char *uplo, integer *n, real *a, 
00024         integer *lda, real *w, real *work, integer *lwork, integer *iwork, 
00025         integer *liwork, integer *info)
00026 {
00027     /* System generated locals */
00028     integer a_dim1, a_offset, i__1, i__2;
00029     real r__1;
00030 
00031     /* Builtin functions */
00032     double sqrt(doublereal);
00033 
00034     /* Local variables */
00035     real eps;
00036     integer inde;
00037     real anrm, rmin, rmax;
00038     integer lopt;
00039     real sigma;
00040     extern logical lsame_(char *, char *);
00041     integer iinfo;
00042     extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *);
00043     integer lwmin, liopt;
00044     logical lower, wantz;
00045     integer indwk2, llwrk2, iscale;
00046     extern doublereal slamch_(char *);
00047     real safmin;
00048     extern integer ilaenv_(integer *, char *, char *, integer *, integer *, 
00049             integer *, integer *);
00050     extern /* Subroutine */ int xerbla_(char *, integer *);
00051     real bignum;
00052     extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, 
00053             real *, integer *, integer *, real *, integer *, integer *);
00054     integer indtau;
00055     extern /* Subroutine */ int sstedc_(char *, integer *, real *, real *, 
00056             real *, integer *, real *, integer *, integer *, integer *, 
00057             integer *), slacpy_(char *, integer *, integer *, real *, 
00058             integer *, real *, integer *);
00059     integer indwrk, liwmin;
00060     extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *);
00061     extern doublereal slansy_(char *, char *, integer *, real *, integer *, 
00062             real *);
00063     integer llwork;
00064     real smlnum;
00065     logical lquery;
00066     extern /* Subroutine */ int sormtr_(char *, char *, char *, integer *, 
00067             integer *, real *, integer *, real *, real *, integer *, real *, 
00068             integer *, integer *), ssytrd_(char *, 
00069             integer *, real *, integer *, real *, real *, real *, real *, 
00070             integer *, integer *);
00071 
00072 
00073 /*  -- LAPACK driver routine (version 3.2) -- */
00074 /*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
00075 /*     November 2006 */
00076 
00077 /*     .. Scalar Arguments .. */
00078 /*     .. */
00079 /*     .. Array Arguments .. */
00080 /*     .. */
00081 
00082 /*  Purpose */
00083 /*  ======= */
00084 
00085 /*  SSYEVD computes all eigenvalues and, optionally, eigenvectors of a */
00086 /*  real symmetric matrix A. If eigenvectors are desired, it uses a */
00087 /*  divide and conquer algorithm. */
00088 
00089 /*  The divide and conquer algorithm makes very mild assumptions about */
00090 /*  floating point arithmetic. It will work on machines with a guard */
00091 /*  digit in add/subtract, or on those binary machines without guard */
00092 /*  digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or */
00093 /*  Cray-2. It could conceivably fail on hexadecimal or decimal machines */
00094 /*  without guard digits, but we know of none. */
00095 
00096 /*  Because of large use of BLAS of level 3, SSYEVD needs N**2 more */
00097 /*  workspace than SSYEVX. */
00098 
00099 /*  Arguments */
00100 /*  ========= */
00101 
00102 /*  JOBZ    (input) CHARACTER*1 */
00103 /*          = 'N':  Compute eigenvalues only; */
00104 /*          = 'V':  Compute eigenvalues and eigenvectors. */
00105 
00106 /*  UPLO    (input) CHARACTER*1 */
00107 /*          = 'U':  Upper triangle of A is stored; */
00108 /*          = 'L':  Lower triangle of A is stored. */
00109 
00110 /*  N       (input) INTEGER */
00111 /*          The order of the matrix A.  N >= 0. */
00112 
00113 /*  A       (input/output) REAL array, dimension (LDA, N) */
00114 /*          On entry, the symmetric matrix A.  If UPLO = 'U', the */
00115 /*          leading N-by-N upper triangular part of A contains the */
00116 /*          upper triangular part of the matrix A.  If UPLO = 'L', */
00117 /*          the leading N-by-N lower triangular part of A contains */
00118 /*          the lower triangular part of the matrix A. */
00119 /*          On exit, if JOBZ = 'V', then if INFO = 0, A contains the */
00120 /*          orthonormal eigenvectors of the matrix A. */
00121 /*          If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') */
00122 /*          or the upper triangle (if UPLO='U') of A, including the */
00123 /*          diagonal, is destroyed. */
00124 
00125 /*  LDA     (input) INTEGER */
00126 /*          The leading dimension of the array A.  LDA >= max(1,N). */
00127 
00128 /*  W       (output) REAL array, dimension (N) */
00129 /*          If INFO = 0, the eigenvalues in ascending order. */
00130 
00131 /*  WORK    (workspace/output) REAL array, */
00132 /*                                         dimension (LWORK) */
00133 /*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */
00134 
00135 /*  LWORK   (input) INTEGER */
00136 /*          The dimension of the array WORK. */
00137 /*          If N <= 1,               LWORK must be at least 1. */
00138 /*          If JOBZ = 'N' and N > 1, LWORK must be at least 2*N+1. */
00139 /*          If JOBZ = 'V' and N > 1, LWORK must be at least */
00140 /*                                                1 + 6*N + 2*N**2. */
00141 
00142 /*          If LWORK = -1, then a workspace query is assumed; the routine */
00143 /*          only calculates the optimal sizes of the WORK and IWORK */
00144 /*          arrays, returns these values as the first entries of the WORK */
00145 /*          and IWORK arrays, and no error message related to LWORK or */
00146 /*          LIWORK is issued by XERBLA. */
00147 
00148 /*  IWORK   (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) */
00149 /*          On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. */
00150 
00151 /*  LIWORK  (input) INTEGER */
00152 /*          The dimension of the array IWORK. */
00153 /*          If N <= 1,                LIWORK must be at least 1. */
00154 /*          If JOBZ  = 'N' and N > 1, LIWORK must be at least 1. */
00155 /*          If JOBZ  = 'V' and N > 1, LIWORK must be at least 3 + 5*N. */
00156 
00157 /*          If LIWORK = -1, then a workspace query is assumed; the */
00158 /*          routine only calculates the optimal sizes of the WORK and */
00159 /*          IWORK arrays, returns these values as the first entries of */
00160 /*          the WORK and IWORK arrays, and no error message related to */
00161 /*          LWORK or LIWORK is issued by XERBLA. */
00162 
00163 /*  INFO    (output) INTEGER */
00164 /*          = 0:  successful exit */
00165 /*          < 0:  if INFO = -i, the i-th argument had an illegal value */
00166 /*          > 0:  if INFO = i and JOBZ = 'N', then the algorithm failed */
00167 /*                to converge; i off-diagonal elements of an intermediate */
00168 /*                tridiagonal form did not converge to zero; */
00169 /*                if INFO = i and JOBZ = 'V', then the algorithm failed */
00170 /*                to compute an eigenvalue while working on the submatrix */
00171 /*                lying in rows and columns INFO/(N+1) through */
00172 /*                mod(INFO,N+1). */
00173 
00174 /*  Further Details */
00175 /*  =============== */
00176 
00177 /*  Based on contributions by */
00178 /*     Jeff Rutter, Computer Science Division, University of California */
00179 /*     at Berkeley, USA */
00180 /*  Modified by Francoise Tisseur, University of Tennessee. */
00181 
00182 /*  Modified description of INFO. Sven, 16 Feb 05. */
00183 /*  ===================================================================== */
00184 
00185 /*     .. Parameters .. */
00186 /*     .. */
00187 /*     .. Local Scalars .. */
00188 
00189 /*     .. */
00190 /*     .. External Functions .. */
00191 /*     .. */
00192 /*     .. External Subroutines .. */
00193 /*     .. */
00194 /*     .. Intrinsic Functions .. */
00195 /*     .. */
00196 /*     .. Executable Statements .. */
00197 
00198 /*     Test the input parameters. */
00199 
00200     /* Parameter adjustments */
00201     a_dim1 = *lda;
00202     a_offset = 1 + a_dim1;
00203     a -= a_offset;
00204     --w;
00205     --work;
00206     --iwork;
00207 
00208     /* Function Body */
00209     wantz = lsame_(jobz, "V");
00210     lower = lsame_(uplo, "L");
00211     lquery = *lwork == -1 || *liwork == -1;
00212 
00213     *info = 0;
00214     if (! (wantz || lsame_(jobz, "N"))) {
00215         *info = -1;
00216     } else if (! (lower || lsame_(uplo, "U"))) {
00217         *info = -2;
00218     } else if (*n < 0) {
00219         *info = -3;
00220     } else if (*lda < max(1,*n)) {
00221         *info = -5;
00222     }
00223 
00224     if (*info == 0) {
00225         if (*n <= 1) {
00226             liwmin = 1;
00227             lwmin = 1;
00228             lopt = lwmin;
00229             liopt = liwmin;
00230         } else {
00231             if (wantz) {
00232                 liwmin = *n * 5 + 3;
00233 /* Computing 2nd power */
00234                 i__1 = *n;
00235                 lwmin = *n * 6 + 1 + (i__1 * i__1 << 1);
00236             } else {
00237                 liwmin = 1;
00238                 lwmin = (*n << 1) + 1;
00239             }
00240 /* Computing MAX */
00241             i__1 = lwmin, i__2 = (*n << 1) + ilaenv_(&c__1, "SSYTRD", uplo, n, 
00242                      &c_n1, &c_n1, &c_n1);
00243             lopt = max(i__1,i__2);
00244             liopt = liwmin;
00245         }
00246         work[1] = (real) lopt;
00247         iwork[1] = liopt;
00248 
00249         if (*lwork < lwmin && ! lquery) {
00250             *info = -8;
00251         } else if (*liwork < liwmin && ! lquery) {
00252             *info = -10;
00253         }
00254     }
00255 
00256     if (*info != 0) {
00257         i__1 = -(*info);
00258         xerbla_("SSYEVD", &i__1);
00259         return 0;
00260     } else if (lquery) {
00261         return 0;
00262     }
00263 
00264 /*     Quick return if possible */
00265 
00266     if (*n == 0) {
00267         return 0;
00268     }
00269 
00270     if (*n == 1) {
00271         w[1] = a[a_dim1 + 1];
00272         if (wantz) {
00273             a[a_dim1 + 1] = 1.f;
00274         }
00275         return 0;
00276     }
00277 
00278 /*     Get machine constants. */
00279 
00280     safmin = slamch_("Safe minimum");
00281     eps = slamch_("Precision");
00282     smlnum = safmin / eps;
00283     bignum = 1.f / smlnum;
00284     rmin = sqrt(smlnum);
00285     rmax = sqrt(bignum);
00286 
00287 /*     Scale matrix to allowable range, if necessary. */
00288 
00289     anrm = slansy_("M", uplo, n, &a[a_offset], lda, &work[1]);
00290     iscale = 0;
00291     if (anrm > 0.f && anrm < rmin) {
00292         iscale = 1;
00293         sigma = rmin / anrm;
00294     } else if (anrm > rmax) {
00295         iscale = 1;
00296         sigma = rmax / anrm;
00297     }
00298     if (iscale == 1) {
00299         slascl_(uplo, &c__0, &c__0, &c_b17, &sigma, n, n, &a[a_offset], lda, 
00300                 info);
00301     }
00302 
00303 /*     Call SSYTRD to reduce symmetric matrix to tridiagonal form. */
00304 
00305     inde = 1;
00306     indtau = inde + *n;
00307     indwrk = indtau + *n;
00308     llwork = *lwork - indwrk + 1;
00309     indwk2 = indwrk + *n * *n;
00310     llwrk2 = *lwork - indwk2 + 1;
00311 
00312     ssytrd_(uplo, n, &a[a_offset], lda, &w[1], &work[inde], &work[indtau], &
00313             work[indwrk], &llwork, &iinfo);
00314 
00315 /*     For eigenvalues only, call SSTERF.  For eigenvectors, first call */
00316 /*     SSTEDC to generate the eigenvector matrix, WORK(INDWRK), of the */
00317 /*     tridiagonal matrix, then call SORMTR to multiply it by the */
00318 /*     Householder transformations stored in A. */
00319 
00320     if (! wantz) {
00321         ssterf_(n, &w[1], &work[inde], info);
00322     } else {
00323         sstedc_("I", n, &w[1], &work[inde], &work[indwrk], n, &work[indwk2], &
00324                 llwrk2, &iwork[1], liwork, info);
00325         sormtr_("L", uplo, "N", n, n, &a[a_offset], lda, &work[indtau], &work[
00326                 indwrk], n, &work[indwk2], &llwrk2, &iinfo);
00327         slacpy_("A", n, n, &work[indwrk], n, &a[a_offset], lda);
00328     }
00329 
00330 /*     If matrix was scaled, then rescale eigenvalues appropriately. */
00331 
00332     if (iscale == 1) {
00333         r__1 = 1.f / sigma;
00334         sscal_(n, &r__1, &w[1], &c__1);
00335     }
00336 
00337     work[1] = (real) lopt;
00338     iwork[1] = liopt;
00339 
00340     return 0;
00341 
00342 /*     End of SSYEVD */
00343 
00344 } /* ssyevd_ */


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