/* Subroutine */ int sstevd_(char *jobz, integer *n, real *d, real *e, real * z, integer *ldz, real *work, integer *lwork, integer *iwork, integer * liwork, integer *info) { /* -- LAPACK driver routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 Purpose ======= SSTEVD computes all eigenvalues and, optionally, eigenvectors of a real symmetric tridiagonal matrix. If eigenvectors are desired, it uses a divide and conquer algorithm. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Arguments ========= JOBZ (input) CHARACTER*1 = 'N': Compute eigenvalues only; = 'V': Compute eigenvalues and eigenvectors. N (input) INTEGER The order of the matrix. N >= 0. D (input/output) REAL array, dimension (N) On entry, the n diagonal elements of the tridiagonal matrix A. On exit, if INFO = 0, the eigenvalues in ascending order. E (input/output) REAL array, dimension (N) On entry, the (n-1) subdiagonal elements of the tridiagonal matrix A, stored in elements 1 to N-1 of E; E(N) need not be set, but is used by the routine. On exit, the contents of E are destroyed. Z (output) REAL array, dimension (LDZ, N) If JOBZ = 'V', then if INFO = 0, Z contains the orthonormal eigenvectors of the matrix A, with the i-th column of Z holding the eigenvector associated with D(i). If JOBZ = 'N', then Z is not referenced. LDZ (input) INTEGER The leading dimension of the array Z. LDZ >= 1, and if JOBZ = 'V', LDZ >= max(1,N). WORK (workspace/output) REAL array, dimension (LWORK) On exit, if LWORK > 0, WORK(1) returns the optimal LWORK. LWORK (input) INTEGER The dimension of the array WORK. If JOBZ = 'N' or N <= 1 then LWORK must be at least 1. If JOBZ = 'V' and N > 1 then LWORK must be at least ( 1 + 3*N + 2*N*lg N + 2*N**2 ), where lg( N ) = smallest integer k such that 2**k >= N. IWORK (workspace/output) INTEGER array, dimension (LIWORK) On exit, if LIWORK > 0, IWORK(1) returns the optimal LIWORK. LIWORK (input) INTEGER The dimension of the array IWORK. If JOBZ = 'N' or N <= 1 then LIWORK must be at least 1. If JOBZ = 'V' and N > 1 then LIWORK must be at least 2+5*N. INFO (output) INTEGER = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value > 0: if INFO = i, the algorithm failed to converge; i off-diagonal elements of E did not converge to zero. ===================================================================== Test the input parameters. Parameter adjustments Function Body */ /* Table of constant values */ static integer c__2 = 2; static integer c__1 = 1; /* System generated locals */ integer z_dim1, z_offset, i__1; real r__1; /* Builtin functions */ double log(doublereal); integer pow_ii(integer *, integer *); double sqrt(doublereal); /* Local variables */ static real rmin, rmax, tnrm, sigma; extern logical lsame_(char *, char *); extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); static integer lwmin; static logical wantz; static integer iscale; extern doublereal slamch_(char *); static real safmin; extern /* Subroutine */ int xerbla_(char *, integer *); static real bignum; extern /* Subroutine */ int sstedc_(char *, integer *, real *, real *, real *, integer *, real *, integer *, integer *, integer *, integer *); static integer liwmin; extern doublereal slanst_(char *, integer *, real *, real *); extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); static real smlnum; static integer lgn; static real eps; #define D(I) d[(I)-1] #define E(I) e[(I)-1] #define WORK(I) work[(I)-1] #define IWORK(I) iwork[(I)-1] #define Z(I,J) z[(I)-1 + ((J)-1)* ( *ldz)] wantz = lsame_(jobz, "V"); *info = 0; liwmin = 1; lwmin = 1; if (! (wantz || lsame_(jobz, "N"))) { *info = -1; } else if (*n < 0) { *info = -2; } else if (*ldz < 1 || wantz && *ldz < *n) { *info = -6; } else if (*n > 1 && wantz) { lgn = (integer) (log((real) (*n)) / log(2.f)); if (pow_ii(&c__2, &lgn) < *n) { ++lgn; } if (pow_ii(&c__2, &lgn) < *n) { ++lgn; } /* Computing 2nd power */ i__1 = *n; lwmin = *n * 3 + 1 + (*n << 1) * lgn + (i__1 * i__1 << 1); liwmin = *n * 5 + 2; if (*lwork < lwmin) { *info = -8; } else if (*liwork < liwmin) { *info = -10; } } else if (*lwork < 1) { *info = -8; } else if (*liwork < 1) { *info = -10; } if (*info != 0) { i__1 = -(*info); xerbla_("SSTEVD", &i__1); goto L10; } /* Quick return if possible */ if (*n == 0) { goto L10; } if (*n == 1) { if (wantz) { Z(1,1) = 1.f; } goto L10; } /* Get machine constants. */ safmin = slamch_("Safe minimum"); eps = slamch_("Precision"); smlnum = safmin / eps; bignum = 1.f / smlnum; rmin = sqrt(smlnum); rmax = sqrt(bignum); /* Scale matrix to allowable range, if necessary. */ iscale = 0; tnrm = slanst_("M", n, &D(1), &E(1)); if (tnrm > 0.f && tnrm < rmin) { iscale = 1; sigma = rmin / tnrm; } else if (tnrm > rmax) { iscale = 1; sigma = rmax / tnrm; } if (iscale == 1) { sscal_(n, &sigma, &D(1), &c__1); i__1 = *n - 1; sscal_(&i__1, &sigma, &E(1), &c__1); } /* For eigenvalues only, call SSTERF. For eigenvalues and eigenvectors, call SSTEDC. */ if (! wantz) { ssterf_(n, &D(1), &E(1), info); } else { sstedc_("I", n, &D(1), &E(1), &Z(1,1), ldz, &WORK(1), lwork, & IWORK(1), liwork, info); } /* If matrix was scaled, then rescale eigenvalues appropriately. */ if (iscale == 1) { r__1 = 1.f / sigma; sscal_(n, &r__1, &D(1), &c__1); } L10: if (*lwork > 0) { WORK(1) = (real) lwmin; } if (*liwork > 0) { IWORK(1) = liwmin; } return 0; /* End of SSTEVD */ } /* sstevd_ */
/* Subroutine */ int sspevd_(char *jobz, char *uplo, integer *n, real *ap, real *w, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info, ftnlen jobz_len, ftnlen uplo_len) { /* System generated locals */ integer z_dim1, z_offset, i__1; real r__1; /* Builtin functions */ double sqrt(doublereal); /* Local variables */ static real eps; static integer inde; static real anrm, rmin, rmax, sigma; extern logical lsame_(char *, char *, ftnlen, ftnlen); static integer iinfo; extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); static integer lwmin; static logical wantz; static integer iscale; extern doublereal slamch_(char *, ftnlen); static real safmin; extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); static real bignum; static integer indtau; extern /* Subroutine */ int sstedc_(char *, integer *, real *, real *, real *, integer *, real *, integer *, integer *, integer *, integer *, ftnlen); static integer indwrk, liwmin; extern doublereal slansp_(char *, char *, integer *, real *, real *, ftnlen, ftnlen); extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); static integer llwork; static real smlnum; extern /* Subroutine */ int ssptrd_(char *, integer *, real *, real *, real *, real *, integer *, ftnlen); static logical lquery; extern /* Subroutine */ int sopmtr_(char *, char *, char *, integer *, integer *, real *, real *, real *, integer *, real *, integer *, ftnlen, ftnlen, ftnlen); /* -- LAPACK driver routine (version 3.0) -- */ /* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ /* Courant Institute, Argonne National Lab, and Rice University */ /* June 30, 1999 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* Purpose */ /* ======= */ /* SSPEVD computes all the eigenvalues and, optionally, eigenvectors */ /* of a real symmetric matrix A in packed storage. If eigenvectors are */ /* desired, it uses a divide and conquer algorithm. */ /* The divide and conquer algorithm makes very mild assumptions about */ /* floating point arithmetic. It will work on machines with a guard */ /* digit in add/subtract, or on those binary machines without guard */ /* digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or */ /* Cray-2. It could conceivably fail on hexadecimal or decimal machines */ /* without guard digits, but we know of none. */ /* Arguments */ /* ========= */ /* JOBZ (input) CHARACTER*1 */ /* = 'N': Compute eigenvalues only; */ /* = 'V': Compute eigenvalues and eigenvectors. */ /* UPLO (input) CHARACTER*1 */ /* = 'U': Upper triangle of A is stored; */ /* = 'L': Lower triangle of A is stored. */ /* N (input) INTEGER */ /* The order of the matrix A. N >= 0. */ /* AP (input/output) REAL array, dimension (N*(N+1)/2) */ /* On entry, the upper or lower triangle of the symmetric matrix */ /* A, packed columnwise in a linear array. The j-th column of A */ /* is stored in the array AP as follows: */ /* if UPLO = 'U', AP(i + (j-1)*j/2) = A(i,j) for 1<=i<=j; */ /* if UPLO = 'L', AP(i + (j-1)*(2*n-j)/2) = A(i,j) for j<=i<=n. */ /* On exit, AP is overwritten by values generated during the */ /* reduction to tridiagonal form. If UPLO = 'U', the diagonal */ /* and first superdiagonal of the tridiagonal matrix T overwrite */ /* the corresponding elements of A, and if UPLO = 'L', the */ /* diagonal and first subdiagonal of T overwrite the */ /* corresponding elements of A. */ /* W (output) REAL array, dimension (N) */ /* If INFO = 0, the eigenvalues in ascending order. */ /* Z (output) REAL array, dimension (LDZ, N) */ /* If JOBZ = 'V', then if INFO = 0, Z contains the orthonormal */ /* eigenvectors of the matrix A, with the i-th column of Z */ /* holding the eigenvector associated with W(i). */ /* If JOBZ = 'N', then Z is not referenced. */ /* LDZ (input) INTEGER */ /* The leading dimension of the array Z. LDZ >= 1, and if */ /* JOBZ = 'V', LDZ >= max(1,N). */ /* WORK (workspace/output) REAL array, */ /* dimension (LWORK) */ /* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */ /* LWORK (input) INTEGER */ /* The dimension of the array WORK. */ /* If N <= 1, LWORK must be at least 1. */ /* If JOBZ = 'N' and N > 1, LWORK must be at least 2*N. */ /* If JOBZ = 'V' and N > 1, LWORK must be at least */ /* 1 + 6*N + N**2. */ /* If LWORK = -1, then a workspace query is assumed; the routine */ /* only calculates the optimal size of the WORK array, returns */ /* this value as the first entry of the WORK array, and no error */ /* message related to LWORK is issued by XERBLA. */ /* IWORK (workspace/output) INTEGER array, dimension (LIWORK) */ /* On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. */ /* LIWORK (input) INTEGER */ /* The dimension of the array IWORK. */ /* If JOBZ = 'N' or N <= 1, LIWORK must be at least 1. */ /* If JOBZ = 'V' and N > 1, LIWORK must be at least 3 + 5*N. */ /* If LIWORK = -1, then a workspace query is assumed; the */ /* routine only calculates the optimal size of the IWORK array, */ /* returns this value as the first entry of the IWORK array, and */ /* no error message related to LIWORK is issued by XERBLA. */ /* INFO (output) INTEGER */ /* = 0: successful exit */ /* < 0: if INFO = -i, the i-th argument had an illegal value. */ /* > 0: if INFO = i, the algorithm failed to converge; i */ /* off-diagonal elements of an intermediate tridiagonal */ /* form did not converge to zero. */ /* ===================================================================== */ /* .. Parameters .. */ /* .. */ /* .. Local Scalars .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Intrinsic Functions .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ --ap; --w; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --work; --iwork; /* Function Body */ wantz = lsame_(jobz, "V", (ftnlen)1, (ftnlen)1); lquery = *lwork == -1 || *liwork == -1; *info = 0; if (*n <= 1) { liwmin = 1; lwmin = 1; } else { if (wantz) { liwmin = *n * 5 + 3; /* Computing 2nd power */ i__1 = *n; lwmin = *n * 6 + 1 + i__1 * i__1; } else { liwmin = 1; lwmin = *n << 1; } } if (! (wantz || lsame_(jobz, "N", (ftnlen)1, (ftnlen)1))) { *info = -1; } else if (! (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) || lsame_(uplo, "L", (ftnlen)1, (ftnlen)1))) { *info = -2; } else if (*n < 0) { *info = -3; } else if (*ldz < 1 || wantz && *ldz < *n) { *info = -7; } else if (*lwork < lwmin && ! lquery) { *info = -9; } else if (*liwork < liwmin && ! lquery) { *info = -11; } if (*info == 0) { work[1] = (real) lwmin; iwork[1] = liwmin; } if (*info != 0) { i__1 = -(*info); xerbla_("SSPEVD", &i__1, (ftnlen)6); return 0; } else if (lquery) { return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { w[1] = ap[1]; if (wantz) { z__[z_dim1 + 1] = 1.f; } return 0; } /* Get machine constants. */ safmin = slamch_("Safe minimum", (ftnlen)12); eps = slamch_("Precision", (ftnlen)9); smlnum = safmin / eps; bignum = 1.f / smlnum; rmin = sqrt(smlnum); rmax = sqrt(bignum); /* Scale matrix to allowable range, if necessary. */ anrm = slansp_("M", uplo, n, &ap[1], &work[1], (ftnlen)1, (ftnlen)1); iscale = 0; if (anrm > 0.f && anrm < rmin) { iscale = 1; sigma = rmin / anrm; } else if (anrm > rmax) { iscale = 1; sigma = rmax / anrm; } if (iscale == 1) { i__1 = *n * (*n + 1) / 2; sscal_(&i__1, &sigma, &ap[1], &c__1); } /* Call SSPTRD to reduce symmetric packed matrix to tridiagonal form. */ inde = 1; indtau = inde + *n; ssptrd_(uplo, n, &ap[1], &w[1], &work[inde], &work[indtau], &iinfo, ( ftnlen)1); /* For eigenvalues only, call SSTERF. For eigenvectors, first call */ /* SSTEDC to generate the eigenvector matrix, WORK(INDWRK), of the */ /* tridiagonal matrix, then call SOPMTR to multiply it by the */ /* Householder transformations represented in AP. */ if (! wantz) { ssterf_(n, &w[1], &work[inde], info); } else { indwrk = indtau + *n; llwork = *lwork - indwrk + 1; sstedc_("I", n, &w[1], &work[inde], &z__[z_offset], ldz, &work[indwrk] , &llwork, &iwork[1], liwork, info, (ftnlen)1); sopmtr_("L", uplo, "N", n, n, &ap[1], &work[indtau], &z__[z_offset], ldz, &work[indwrk], &iinfo, (ftnlen)1, (ftnlen)1, (ftnlen)1); } /* If matrix was scaled, then rescale eigenvalues appropriately. */ if (iscale == 1) { r__1 = 1.f / sigma; sscal_(n, &r__1, &w[1], &c__1); } work[1] = (real) lwmin; iwork[1] = liwmin; return 0; /* End of SSPEVD */ } /* sspevd_ */
/* Subroutine */ int ssyevd_(char *jobz, char *uplo, integer *n, real *a, integer *lda, real *w, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info) { /* -- LAPACK driver routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University June 30, 1999 Purpose ======= SSYEVD computes all eigenvalues and, optionally, eigenvectors of a real symmetric matrix A. If eigenvectors are desired, it uses a divide and conquer algorithm. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Because of large use of BLAS of level 3, SSYEVD needs N**2 more workspace than SSYEVX. Arguments ========= JOBZ (input) CHARACTER*1 = 'N': Compute eigenvalues only; = 'V': Compute eigenvalues and eigenvectors. UPLO (input) CHARACTER*1 = 'U': Upper triangle of A is stored; = 'L': Lower triangle of A is stored. N (input) INTEGER The order of the matrix A. N >= 0. A (input/output) REAL array, dimension (LDA, N) On entry, the symmetric matrix A. If UPLO = 'U', the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If UPLO = 'L', the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if JOBZ = 'V', then if INFO = 0, A contains the orthonormal eigenvectors of the matrix A. If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') or the upper triangle (if UPLO='U') of A, including the diagonal, is destroyed. LDA (input) INTEGER The leading dimension of the array A. LDA >= max(1,N). W (output) REAL array, dimension (N) If INFO = 0, the eigenvalues in ascending order. WORK (workspace/output) REAL array, dimension (LWORK) On exit, if INFO = 0, WORK(1) returns the optimal LWORK. LWORK (input) INTEGER The dimension of the array WORK. If N <= 1, LWORK must be at least 1. If JOBZ = 'N' and N > 1, LWORK must be at least 2*N+1. If JOBZ = 'V' and N > 1, LWORK must be at least 1 + 6*N + 2*N**2. If LWORK = -1, then a workspace query is assumed; the routine only calculates the optimal size of the WORK array, returns this value as the first entry of the WORK array, and no error message related to LWORK is issued by XERBLA. IWORK (workspace/output) INTEGER array, dimension (LIWORK) On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. LIWORK (input) INTEGER The dimension of the array IWORK. If N <= 1, LIWORK must be at least 1. If JOBZ = 'N' and N > 1, LIWORK must be at least 1. If JOBZ = 'V' and N > 1, LIWORK must be at least 3 + 5*N. If LIWORK = -1, then a workspace query is assumed; the routine only calculates the optimal size of the IWORK array, returns this value as the first entry of the IWORK array, and no error message related to LIWORK is issued by XERBLA. INFO (output) INTEGER = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value > 0: if INFO = i, the algorithm failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero. Further Details =============== Based on contributions by Jeff Rutter, Computer Science Division, University of California at Berkeley, USA Modified by Francoise Tisseur, University of Tennessee. ===================================================================== Test the input parameters. Parameter adjustments */ /* Table of constant values */ static integer c__0 = 0; static real c_b12 = 1.f; static integer c__1 = 1; /* System generated locals */ integer a_dim1, a_offset, i__1, i__2, i__3; real r__1; /* Builtin functions */ double sqrt(doublereal); /* Local variables */ static integer inde; static real anrm, rmin, rmax; static integer lopt; static real sigma; extern logical lsame_(char *, char *); static integer iinfo; extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); static integer lwmin, liopt; static logical lower, wantz; static integer indwk2, llwrk2, iscale; extern doublereal slamch_(char *); static real safmin; extern /* Subroutine */ int xerbla_(char *, integer *); static real bignum; extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, real *, integer *, integer *, real *, integer *, integer *); static integer indtau; extern /* Subroutine */ int sstedc_(char *, integer *, real *, real *, real *, integer *, real *, integer *, integer *, integer *, integer *), slacpy_(char *, integer *, integer *, real *, integer *, real *, integer *); static integer indwrk, liwmin; extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); extern doublereal slansy_(char *, char *, integer *, real *, integer *, real *); static integer llwork; static real smlnum; static logical lquery; extern /* Subroutine */ int sormtr_(char *, char *, char *, integer *, integer *, real *, integer *, real *, real *, integer *, real *, integer *, integer *), ssytrd_(char *, integer *, real *, integer *, real *, real *, real *, real *, integer *, integer *); static real eps; #define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1] a_dim1 = *lda; a_offset = 1 + a_dim1 * 1; a -= a_offset; --w; --work; --iwork; /* Function Body */ wantz = lsame_(jobz, "V"); lower = lsame_(uplo, "L"); lquery = *lwork == -1 || *liwork == -1; *info = 0; if (*n <= 1) { liwmin = 1; lwmin = 1; lopt = lwmin; liopt = liwmin; } else { if (wantz) { liwmin = *n * 5 + 3; /* Computing 2nd power */ i__1 = *n; lwmin = *n * 6 + 1 + (i__1 * i__1 << 1); } else { liwmin = 1; lwmin = (*n << 1) + 1; } lopt = lwmin; liopt = liwmin; } if (! (wantz || lsame_(jobz, "N"))) { *info = -1; } else if (! (lower || lsame_(uplo, "U"))) { *info = -2; } else if (*n < 0) { *info = -3; } else if (*lda < max(1,*n)) { *info = -5; } else if (*lwork < lwmin && ! lquery) { *info = -8; } else if (*liwork < liwmin && ! lquery) { *info = -10; } if (*info == 0) { work[1] = (real) lopt; iwork[1] = liopt; } if (*info != 0) { i__1 = -(*info); xerbla_("SSYEVD", &i__1); return 0; } else if (lquery) { return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { w[1] = a_ref(1, 1); if (wantz) { a_ref(1, 1) = 1.f; } return 0; } /* Get machine constants. */ safmin = slamch_("Safe minimum"); eps = slamch_("Precision"); smlnum = safmin / eps; bignum = 1.f / smlnum; rmin = sqrt(smlnum); rmax = sqrt(bignum); /* Scale matrix to allowable range, if necessary. */ anrm = slansy_("M", uplo, n, &a[a_offset], lda, &work[1]); iscale = 0; if (anrm > 0.f && anrm < rmin) { iscale = 1; sigma = rmin / anrm; } else if (anrm > rmax) { iscale = 1; sigma = rmax / anrm; } if (iscale == 1) { slascl_(uplo, &c__0, &c__0, &c_b12, &sigma, n, n, &a[a_offset], lda, info); } /* Call SSYTRD to reduce symmetric matrix to tridiagonal form. */ inde = 1; indtau = inde + *n; indwrk = indtau + *n; llwork = *lwork - indwrk + 1; indwk2 = indwrk + *n * *n; llwrk2 = *lwork - indwk2 + 1; ssytrd_(uplo, n, &a[a_offset], lda, &w[1], &work[inde], &work[indtau], & work[indwrk], &llwork, &iinfo); lopt = (*n << 1) + work[indwrk]; /* For eigenvalues only, call SSTERF. For eigenvectors, first call SSTEDC to generate the eigenvector matrix, WORK(INDWRK), of the tridiagonal matrix, then call SORMTR to multiply it by the Householder transformations stored in A. */ if (! wantz) { ssterf_(n, &w[1], &work[inde], info); } else { sstedc_("I", n, &w[1], &work[inde], &work[indwrk], n, &work[indwk2], & llwrk2, &iwork[1], liwork, info); sormtr_("L", uplo, "N", n, n, &a[a_offset], lda, &work[indtau], &work[ indwrk], n, &work[indwk2], &llwrk2, &iinfo); slacpy_("A", n, n, &work[indwrk], n, &a[a_offset], lda); /* Computing MAX Computing 2nd power */ i__3 = *n; i__1 = lopt, i__2 = *n * 6 + 1 + (i__3 * i__3 << 1); lopt = max(i__1,i__2); } /* If matrix was scaled, then rescale eigenvalues appropriately. */ if (iscale == 1) { r__1 = 1.f / sigma; sscal_(n, &r__1, &w[1], &c__1); } work[1] = (real) lopt; iwork[1] = liopt; return 0; /* End of SSYEVD */ } /* ssyevd_ */
/* Subroutine */ int cstedc_(char *compz, integer *n, real *d__, real *e, complex *z__, integer *ldz, complex *work, integer *lwork, real * rwork, integer *lrwork, integer *iwork, integer *liwork, integer * info) { /* System generated locals */ integer z_dim1, z_offset, i__1, i__2, i__3, i__4; real r__1, r__2; /* Local variables */ integer i__, j, k, m; real p; integer ii, ll, lgn; real eps, tiny; integer lwmin; integer start; integer finish; integer liwmin, icompz; real orgnrm; integer lrwmin; logical lquery; integer smlsiz; /* -- LAPACK routine (version 3.2) -- */ /* November 2006 */ /* Purpose */ /* ======= */ /* CSTEDC computes all eigenvalues and, optionally, eigenvectors of a */ /* symmetric tridiagonal matrix using the divide and conquer method. */ /* The eigenvectors of a full or band complex Hermitian matrix can also */ /* be found if CHETRD or CHPTRD or CHBTRD has been used to reduce this */ /* matrix to tridiagonal form. */ /* This code makes very mild assumptions about floating point */ /* arithmetic. It will work on machines with a guard digit in */ /* add/subtract, or on those binary machines without guard digits */ /* which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. */ /* It could conceivably fail on hexadecimal or decimal machines */ /* without guard digits, but we know of none. See SLAED3 for details. */ /* Arguments */ /* ========= */ /* COMPZ (input) CHARACTER*1 */ /* = 'N': Compute eigenvalues only. */ /* = 'I': Compute eigenvectors of tridiagonal matrix also. */ /* = 'V': Compute eigenvectors of original Hermitian matrix */ /* also. On entry, Z contains the unitary matrix used */ /* to reduce the original matrix to tridiagonal form. */ /* N (input) INTEGER */ /* The dimension of the symmetric tridiagonal matrix. N >= 0. */ /* D (input/output) REAL array, dimension (N) */ /* On entry, the diagonal elements of the tridiagonal matrix. */ /* On exit, if INFO = 0, the eigenvalues in ascending order. */ /* E (input/output) REAL array, dimension (N-1) */ /* On entry, the subdiagonal elements of the tridiagonal matrix. */ /* On exit, E has been destroyed. */ /* Z (input/output) COMPLEX array, dimension (LDZ,N) */ /* On entry, if COMPZ = 'V', then Z contains the unitary */ /* matrix used in the reduction to tridiagonal form. */ /* On exit, if INFO = 0, then if COMPZ = 'V', Z contains the */ /* orthonormal eigenvectors of the original Hermitian matrix, */ /* and if COMPZ = 'I', Z contains the orthonormal eigenvectors */ /* of the symmetric tridiagonal matrix. */ /* If COMPZ = 'N', then Z is not referenced. */ /* LDZ (input) INTEGER */ /* The leading dimension of the array Z. LDZ >= 1. */ /* If eigenvectors are desired, then LDZ >= max(1,N). */ /* WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) */ /* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */ /* LWORK (input) INTEGER */ /* The dimension of the array WORK. */ /* If COMPZ = 'N' or 'I', or N <= 1, LWORK must be at least 1. */ /* If COMPZ = 'V' and N > 1, LWORK must be at least N*N. */ /* Note that for COMPZ = 'V', then if N is less than or */ /* equal to the minimum divide size, usually 25, then LWORK need */ /* only be 1. */ /* If LWORK = -1, then a workspace query is assumed; the routine */ /* only calculates the optimal sizes of the WORK, RWORK and */ /* IWORK arrays, returns these values as the first entries of */ /* the WORK, RWORK and IWORK arrays, and no error message */ /* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ /* RWORK (workspace/output) REAL array, dimension (MAX(1,LRWORK)) */ /* On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK. */ /* LRWORK (input) INTEGER */ /* The dimension of the array RWORK. */ /* If COMPZ = 'N' or N <= 1, LRWORK must be at least 1. */ /* If COMPZ = 'V' and N > 1, LRWORK must be at least */ /* 1 + 3*N + 2*N*lg N + 3*N**2 , */ /* where lg( N ) = smallest integer k such */ /* that 2**k >= N. */ /* If COMPZ = 'I' and N > 1, LRWORK must be at least */ /* 1 + 4*N + 2*N**2 . */ /* Note that for COMPZ = 'I' or 'V', then if N is less than or */ /* equal to the minimum divide size, usually 25, then LRWORK */ /* need only be max(1,2*(N-1)). */ /* If LRWORK = -1, then a workspace query is assumed; the */ /* routine only calculates the optimal sizes of the WORK, RWORK */ /* and IWORK arrays, returns these values as the first entries */ /* of the WORK, RWORK and IWORK arrays, and no error message */ /* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ /* IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) */ /* On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. */ /* LIWORK (input) INTEGER */ /* The dimension of the array IWORK. */ /* If COMPZ = 'N' or N <= 1, LIWORK must be at least 1. */ /* If COMPZ = 'V' or N > 1, LIWORK must be at least */ /* 6 + 6*N + 5*N*lg N. */ /* If COMPZ = 'I' or N > 1, LIWORK must be at least */ /* 3 + 5*N . */ /* Note that for COMPZ = 'I' or 'V', then if N is less than or */ /* equal to the minimum divide size, usually 25, then LIWORK */ /* need only be 1. */ /* If LIWORK = -1, then a workspace query is assumed; the */ /* routine only calculates the optimal sizes of the WORK, RWORK */ /* and IWORK arrays, returns these values as the first entries */ /* of the WORK, RWORK and IWORK arrays, and no error message */ /* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ /* INFO (output) INTEGER */ /* = 0: successful exit. */ /* < 0: if INFO = -i, the i-th argument had an illegal value. */ /* > 0: The algorithm failed to compute an eigenvalue while */ /* working on the submatrix lying in rows and columns */ /* INFO/(N+1) through mod(INFO,N+1). */ /* Further Details */ /* =============== */ /* Based on contributions by */ /* Jeff Rutter, Computer Science Division, University of California */ /* at Berkeley, USA */ /* ===================================================================== */ /* Test the input parameters. */ /* Parameter adjustments */ --d__; --e; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --work; --rwork; --iwork; /* Function Body */ *info = 0; lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1; if (lsame_(compz, "N")) { icompz = 0; } else if (lsame_(compz, "V")) { icompz = 1; } else if (lsame_(compz, "I")) { icompz = 2; } else { icompz = -1; } if (icompz < 0) { *info = -1; } else if (*n < 0) { *info = -2; } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { *info = -6; } if (*info == 0) { /* Compute the workspace requirements */ smlsiz = ilaenv_(&c__9, "CSTEDC", " ", &c__0, &c__0, &c__0, &c__0); if (*n <= 1 || icompz == 0) { lwmin = 1; liwmin = 1; lrwmin = 1; } else if (*n <= smlsiz) { lwmin = 1; liwmin = 1; lrwmin = *n - 1 << 1; } else if (icompz == 1) { lgn = (integer) (log((real) (*n)) / log(2.f)); if (pow_ii(&c__2, &lgn) < *n) { ++lgn; } if (pow_ii(&c__2, &lgn) < *n) { ++lgn; } lwmin = *n * *n; /* Computing 2nd power */ i__1 = *n; lrwmin = *n * 3 + 1 + (*n << 1) * lgn + i__1 * i__1 * 3; liwmin = *n * 6 + 6 + *n * 5 * lgn; } else if (icompz == 2) { lwmin = 1; /* Computing 2nd power */ i__1 = *n; lrwmin = (*n << 2) + 1 + (i__1 * i__1 << 1); liwmin = *n * 5 + 3; } work[1].r = (real) lwmin, work[1].i = 0.f; rwork[1] = (real) lrwmin; iwork[1] = liwmin; if (*lwork < lwmin && ! lquery) { *info = -8; } else if (*lrwork < lrwmin && ! lquery) { *info = -10; } else if (*liwork < liwmin && ! lquery) { *info = -12; } } if (*info != 0) { i__1 = -(*info); xerbla_("CSTEDC", &i__1); return 0; } else if (lquery) { return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { if (icompz != 0) { i__1 = z_dim1 + 1; z__[i__1].r = 1.f, z__[i__1].i = 0.f; } return 0; } /* If the following conditional clause is removed, then the routine */ /* will use the Divide and Conquer routine to compute only the */ /* eigenvalues, which requires (3N + 3N**2) real workspace and */ /* (2 + 5N + 2N lg(N)) integer workspace. */ /* Since on many architectures SSTERF is much faster than any other */ /* algorithm for finding eigenvalues only, it is used here */ /* as the default. If the conditional clause is removed, then */ /* information on the size of workspace needs to be changed. */ /* If COMPZ = 'N', use SSTERF to compute the eigenvalues. */ if (icompz == 0) { ssterf_(n, &d__[1], &e[1], info); goto L70; } /* If N is smaller than the minimum divide size (SMLSIZ+1), then */ /* solve the problem with another solver. */ if (*n <= smlsiz) { csteqr_(compz, n, &d__[1], &e[1], &z__[z_offset], ldz, &rwork[1], info); } else { /* If COMPZ = 'I', we simply call SSTEDC instead. */ if (icompz == 2) { slaset_("Full", n, n, &c_b17, &c_b18, &rwork[1], n); ll = *n * *n + 1; i__1 = *lrwork - ll + 1; sstedc_("I", n, &d__[1], &e[1], &rwork[1], n, &rwork[ll], &i__1, & iwork[1], liwork, info); i__1 = *n; for (j = 1; j <= i__1; ++j) { i__2 = *n; for (i__ = 1; i__ <= i__2; ++i__) { i__3 = i__ + j * z_dim1; i__4 = (j - 1) * *n + i__; z__[i__3].r = rwork[i__4], z__[i__3].i = 0.f; } } goto L70; } /* From now on, only option left to be handled is COMPZ = 'V', */ /* i.e. ICOMPZ = 1. */ /* Scale. */ orgnrm = slanst_("M", n, &d__[1], &e[1]); if (orgnrm == 0.f) { goto L70; } eps = slamch_("Epsilon"); start = 1; /* while ( START <= N ) */ L30: if (start <= *n) { /* Let FINISH be the position of the next subdiagonal entry */ /* such that E( FINISH ) <= TINY or FINISH = N if no such */ /* subdiagonal exists. The matrix identified by the elements */ /* between START and FINISH constitutes an independent */ /* sub-problem. */ finish = start; L40: if (finish < *n) { tiny = eps * sqrt((r__1 = d__[finish], dabs(r__1))) * sqrt(( r__2 = d__[finish + 1], dabs(r__2))); if ((r__1 = e[finish], dabs(r__1)) > tiny) { ++finish; goto L40; } } /* (Sub) Problem determined. Compute its size and solve it. */ m = finish - start + 1; if (m > smlsiz) { /* Scale. */ orgnrm = slanst_("M", &m, &d__[start], &e[start]); slascl_("G", &c__0, &c__0, &orgnrm, &c_b18, &m, &c__1, &d__[ start], &m, info); i__1 = m - 1; i__2 = m - 1; slascl_("G", &c__0, &c__0, &orgnrm, &c_b18, &i__1, &c__1, &e[ start], &i__2, info); claed0_(n, &m, &d__[start], &e[start], &z__[start * z_dim1 + 1], ldz, &work[1], n, &rwork[1], &iwork[1], info); if (*info > 0) { *info = (*info / (m + 1) + start - 1) * (*n + 1) + *info % (m + 1) + start - 1; goto L70; } /* Scale back. */ slascl_("G", &c__0, &c__0, &c_b18, &orgnrm, &m, &c__1, &d__[ start], &m, info); } else { ssteqr_("I", &m, &d__[start], &e[start], &rwork[1], &m, & rwork[m * m + 1], info); clacrm_(n, &m, &z__[start * z_dim1 + 1], ldz, &rwork[1], &m, & work[1], n, &rwork[m * m + 1]); clacpy_("A", n, &m, &work[1], n, &z__[start * z_dim1 + 1], ldz); if (*info > 0) { *info = start * (*n + 1) + finish; goto L70; } } start = finish + 1; goto L30; } /* endwhile */ /* If the problem split any number of times, then the eigenvalues */ /* will not be properly ordered. Here we permute the eigenvalues */ /* (and the associated eigenvectors) into ascending order. */ if (m != *n) { /* Use Selection Sort to minimize swaps of eigenvectors */ i__1 = *n; for (ii = 2; ii <= i__1; ++ii) { i__ = ii - 1; k = i__; p = d__[i__]; i__2 = *n; for (j = ii; j <= i__2; ++j) { if (d__[j] < p) { k = j; p = d__[j]; } } if (k != i__) { d__[k] = d__[i__]; d__[i__] = p; cswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], &c__1); } } } } L70: work[1].r = (real) lwmin, work[1].i = 0.f; rwork[1] = (real) lrwmin; iwork[1] = liwmin; return 0; /* End of CSTEDC */ } /* cstedc_ */
/* Subroutine */ int sstevd_(char *jobz, integer *n, real *d__, real *e, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info) { /* -- LAPACK driver routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University June 30, 1999 Purpose ======= SSTEVD computes all eigenvalues and, optionally, eigenvectors of a real symmetric tridiagonal matrix. If eigenvectors are desired, it uses a divide and conquer algorithm. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Arguments ========= JOBZ (input) CHARACTER*1 = 'N': Compute eigenvalues only; = 'V': Compute eigenvalues and eigenvectors. N (input) INTEGER The order of the matrix. N >= 0. D (input/output) REAL array, dimension (N) On entry, the n diagonal elements of the tridiagonal matrix A. On exit, if INFO = 0, the eigenvalues in ascending order. E (input/output) REAL array, dimension (N) On entry, the (n-1) subdiagonal elements of the tridiagonal matrix A, stored in elements 1 to N-1 of E; E(N) need not be set, but is used by the routine. On exit, the contents of E are destroyed. Z (output) REAL array, dimension (LDZ, N) If JOBZ = 'V', then if INFO = 0, Z contains the orthonormal eigenvectors of the matrix A, with the i-th column of Z holding the eigenvector associated with D(i). If JOBZ = 'N', then Z is not referenced. LDZ (input) INTEGER The leading dimension of the array Z. LDZ >= 1, and if JOBZ = 'V', LDZ >= max(1,N). WORK (workspace/output) REAL array, dimension (LWORK) On exit, if INFO = 0, WORK(1) returns the optimal LWORK. LWORK (input) INTEGER The dimension of the array WORK. If JOBZ = 'N' or N <= 1 then LWORK must be at least 1. If JOBZ = 'V' and N > 1 then LWORK must be at least ( 1 + 4*N + N**2 ). If LWORK = -1, then a workspace query is assumed; the routine only calculates the optimal size of the WORK array, returns this value as the first entry of the WORK array, and no error message related to LWORK is issued by XERBLA. IWORK (workspace/output) INTEGER array, dimension (LIWORK) On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. LIWORK (input) INTEGER The dimension of the array IWORK. If JOBZ = 'N' or N <= 1 then LIWORK must be at least 1. If JOBZ = 'V' and N > 1 then LIWORK must be at least 3+5*N. If LIWORK = -1, then a workspace query is assumed; the routine only calculates the optimal size of the IWORK array, returns this value as the first entry of the IWORK array, and no error message related to LIWORK is issued by XERBLA. INFO (output) INTEGER = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value > 0: if INFO = i, the algorithm failed to converge; i off-diagonal elements of E did not converge to zero. ===================================================================== Test the input parameters. Parameter adjustments */ /* Table of constant values */ static integer c__1 = 1; /* System generated locals */ integer z_dim1, z_offset, i__1; real r__1; /* Builtin functions */ double sqrt(doublereal); /* Local variables */ static real rmin, rmax, tnrm, sigma; extern logical lsame_(char *, char *); extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); static integer lwmin; static logical wantz; static integer iscale; extern doublereal slamch_(char *); static real safmin; extern /* Subroutine */ int xerbla_(char *, integer *); static real bignum; extern /* Subroutine */ int sstedc_(char *, integer *, real *, real *, real *, integer *, real *, integer *, integer *, integer *, integer *); static integer liwmin; extern doublereal slanst_(char *, integer *, real *, real *); extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); static real smlnum; static logical lquery; static real eps; #define z___ref(a_1,a_2) z__[(a_2)*z_dim1 + a_1] --d__; --e; z_dim1 = *ldz; z_offset = 1 + z_dim1 * 1; z__ -= z_offset; --work; --iwork; /* Function Body */ wantz = lsame_(jobz, "V"); lquery = *lwork == -1 || *liwork == -1; *info = 0; liwmin = 1; lwmin = 1; if (*n > 1 && wantz) { /* Computing 2nd power */ i__1 = *n; lwmin = (*n << 2) + 1 + i__1 * i__1; liwmin = *n * 5 + 3; } if (! (wantz || lsame_(jobz, "N"))) { *info = -1; } else if (*n < 0) { *info = -2; } else if (*ldz < 1 || wantz && *ldz < *n) { *info = -6; } else if (*lwork < lwmin && ! lquery) { *info = -8; } else if (*liwork < liwmin && ! lquery) { *info = -10; } if (*info == 0) { work[1] = (real) lwmin; iwork[1] = liwmin; } if (*info != 0) { i__1 = -(*info); xerbla_("SSTEVD", &i__1); return 0; } else if (lquery) { return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { if (wantz) { z___ref(1, 1) = 1.f; } return 0; } /* Get machine constants. */ safmin = slamch_("Safe minimum"); eps = slamch_("Precision"); smlnum = safmin / eps; bignum = 1.f / smlnum; rmin = sqrt(smlnum); rmax = sqrt(bignum); /* Scale matrix to allowable range, if necessary. */ iscale = 0; tnrm = slanst_("M", n, &d__[1], &e[1]); if (tnrm > 0.f && tnrm < rmin) { iscale = 1; sigma = rmin / tnrm; } else if (tnrm > rmax) { iscale = 1; sigma = rmax / tnrm; } if (iscale == 1) { sscal_(n, &sigma, &d__[1], &c__1); i__1 = *n - 1; sscal_(&i__1, &sigma, &e[1], &c__1); } /* For eigenvalues only, call SSTERF. For eigenvalues and eigenvectors, call SSTEDC. */ if (! wantz) { ssterf_(n, &d__[1], &e[1], info); } else { sstedc_("I", n, &d__[1], &e[1], &z__[z_offset], ldz, &work[1], lwork, &iwork[1], liwork, info); } /* If matrix was scaled, then rescale eigenvalues appropriately. */ if (iscale == 1) { r__1 = 1.f / sigma; sscal_(n, &r__1, &d__[1], &c__1); } work[1] = (real) lwmin; iwork[1] = liwmin; return 0; /* End of SSTEVD */ } /* sstevd_ */
int ssbgvd_(char *jobz, char *uplo, int *n, int *ka, int *kb, float *ab, int *ldab, float *bb, int *ldbb, float * w, float *z__, int *ldz, float *work, int *lwork, int * iwork, int *liwork, int *info) { /* System generated locals */ int ab_dim1, ab_offset, bb_dim1, bb_offset, z_dim1, z_offset, i__1; /* Local variables */ int inde; char vect[1]; extern int lsame_(char *, char *); int iinfo; extern int sgemm_(char *, char *, int *, int *, int *, float *, float *, int *, float *, int *, float *, float *, int *); int lwmin; int upper, wantz; int indwk2, llwrk2; extern int xerbla_(char *, int *), sstedc_( char *, int *, float *, float *, float *, int *, float *, int *, int *, int *, int *), slacpy_(char *, int *, int *, float *, int *, float *, int *); int indwrk, liwmin; extern int spbstf_(char *, int *, int *, float *, int *, int *), ssbtrd_(char *, char *, int *, int *, float *, int *, float *, float *, float *, int *, float *, int *), ssbgst_(char *, char *, int *, int *, int *, float *, int *, float *, int *, float *, int *, float *, int *), ssterf_(int *, float *, float *, int *); int lquery; /* -- LAPACK driver routine (version 3.2) -- */ /* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ /* November 2006 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* Purpose */ /* ======= */ /* SSBGVD computes all the eigenvalues, and optionally, the eigenvectors */ /* of a float generalized symmetric-definite banded eigenproblem, of the */ /* form A*x=(lambda)*B*x. Here A and B are assumed to be symmetric and */ /* banded, and B is also positive definite. If eigenvectors are */ /* desired, it uses a divide and conquer algorithm. */ /* The divide and conquer algorithm makes very mild assumptions about */ /* floating point arithmetic. It will work on machines with a guard */ /* digit in add/subtract, or on those binary machines without guard */ /* digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or */ /* Cray-2. It could conceivably fail on hexadecimal or decimal machines */ /* without guard digits, but we know of none. */ /* Arguments */ /* ========= */ /* JOBZ (input) CHARACTER*1 */ /* = 'N': Compute eigenvalues only; */ /* = 'V': Compute eigenvalues and eigenvectors. */ /* UPLO (input) CHARACTER*1 */ /* = 'U': Upper triangles of A and B are stored; */ /* = 'L': Lower triangles of A and B are stored. */ /* N (input) INTEGER */ /* The order of the matrices A and B. N >= 0. */ /* KA (input) INTEGER */ /* The number of superdiagonals of the matrix A if UPLO = 'U', */ /* or the number of subdiagonals if UPLO = 'L'. KA >= 0. */ /* KB (input) INTEGER */ /* The number of superdiagonals of the matrix B if UPLO = 'U', */ /* or the number of subdiagonals if UPLO = 'L'. KB >= 0. */ /* AB (input/output) REAL array, dimension (LDAB, N) */ /* On entry, the upper or lower triangle of the symmetric band */ /* matrix A, stored in the first ka+1 rows of the array. The */ /* j-th column of A is stored in the j-th column of the array AB */ /* as follows: */ /* if UPLO = 'U', AB(ka+1+i-j,j) = A(i,j) for MAX(1,j-ka)<=i<=j; */ /* if UPLO = 'L', AB(1+i-j,j) = A(i,j) for j<=i<=MIN(n,j+ka). */ /* On exit, the contents of AB are destroyed. */ /* LDAB (input) INTEGER */ /* The leading dimension of the array AB. LDAB >= KA+1. */ /* BB (input/output) REAL array, dimension (LDBB, N) */ /* On entry, the upper or lower triangle of the symmetric band */ /* matrix B, stored in the first kb+1 rows of the array. The */ /* j-th column of B is stored in the j-th column of the array BB */ /* as follows: */ /* if UPLO = 'U', BB(ka+1+i-j,j) = B(i,j) for MAX(1,j-kb)<=i<=j; */ /* if UPLO = 'L', BB(1+i-j,j) = B(i,j) for j<=i<=MIN(n,j+kb). */ /* On exit, the factor S from the split Cholesky factorization */ /* B = S**T*S, as returned by SPBSTF. */ /* LDBB (input) INTEGER */ /* The leading dimension of the array BB. LDBB >= KB+1. */ /* W (output) REAL array, dimension (N) */ /* If INFO = 0, the eigenvalues in ascending order. */ /* Z (output) REAL array, dimension (LDZ, N) */ /* If JOBZ = 'V', then if INFO = 0, Z contains the matrix Z of */ /* eigenvectors, with the i-th column of Z holding the */ /* eigenvector associated with W(i). The eigenvectors are */ /* normalized so Z**T*B*Z = I. */ /* If JOBZ = 'N', then Z is not referenced. */ /* LDZ (input) INTEGER */ /* The leading dimension of the array Z. LDZ >= 1, and if */ /* JOBZ = 'V', LDZ >= MAX(1,N). */ /* WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) */ /* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */ /* LWORK (input) INTEGER */ /* The dimension of the array WORK. */ /* If N <= 1, LWORK >= 1. */ /* If JOBZ = 'N' and N > 1, LWORK >= 3*N. */ /* If JOBZ = 'V' and N > 1, LWORK >= 1 + 5*N + 2*N**2. */ /* If LWORK = -1, then a workspace query is assumed; the routine */ /* only calculates the optimal sizes of the WORK and IWORK */ /* arrays, returns these values as the first entries of the WORK */ /* and IWORK arrays, and no error message related to LWORK or */ /* LIWORK is issued by XERBLA. */ /* IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) */ /* On exit, if LIWORK > 0, IWORK(1) returns the optimal LIWORK. */ /* LIWORK (input) INTEGER */ /* The dimension of the array IWORK. */ /* If JOBZ = 'N' or N <= 1, LIWORK >= 1. */ /* If JOBZ = 'V' and N > 1, LIWORK >= 3 + 5*N. */ /* If LIWORK = -1, then a workspace query is assumed; the */ /* routine only calculates the optimal sizes of the WORK and */ /* IWORK arrays, returns these values as the first entries of */ /* the WORK and IWORK arrays, and no error message related to */ /* LWORK or LIWORK is issued by XERBLA. */ /* INFO (output) INTEGER */ /* = 0: successful exit */ /* < 0: if INFO = -i, the i-th argument had an illegal value */ /* > 0: if INFO = i, and i is: */ /* <= N: the algorithm failed to converge: */ /* i off-diagonal elements of an intermediate */ /* tridiagonal form did not converge to zero; */ /* > N: if INFO = N + i, for 1 <= i <= N, then SPBSTF */ /* returned INFO = i: B is not positive definite. */ /* The factorization of B could not be completed and */ /* no eigenvalues or eigenvectors were computed. */ /* Further Details */ /* =============== */ /* Based on contributions by */ /* Mark Fahey, Department of Mathematics, Univ. of Kentucky, USA */ /* ===================================================================== */ /* .. Parameters .. */ /* .. */ /* .. Local Scalars .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ ab_dim1 = *ldab; ab_offset = 1 + ab_dim1; ab -= ab_offset; bb_dim1 = *ldbb; bb_offset = 1 + bb_dim1; bb -= bb_offset; --w; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --work; --iwork; /* Function Body */ wantz = lsame_(jobz, "V"); upper = lsame_(uplo, "U"); lquery = *lwork == -1 || *liwork == -1; *info = 0; if (*n <= 1) { liwmin = 1; lwmin = 1; } else if (wantz) { liwmin = *n * 5 + 3; /* Computing 2nd power */ i__1 = *n; lwmin = *n * 5 + 1 + (i__1 * i__1 << 1); } else { liwmin = 1; lwmin = *n << 1; } if (! (wantz || lsame_(jobz, "N"))) { *info = -1; } else if (! (upper || lsame_(uplo, "L"))) { *info = -2; } else if (*n < 0) { *info = -3; } else if (*ka < 0) { *info = -4; } else if (*kb < 0 || *kb > *ka) { *info = -5; } else if (*ldab < *ka + 1) { *info = -7; } else if (*ldbb < *kb + 1) { *info = -9; } else if (*ldz < 1 || wantz && *ldz < *n) { *info = -12; } if (*info == 0) { work[1] = (float) lwmin; iwork[1] = liwmin; if (*lwork < lwmin && ! lquery) { *info = -14; } else if (*liwork < liwmin && ! lquery) { *info = -16; } } if (*info != 0) { i__1 = -(*info); xerbla_("SSBGVD", &i__1); return 0; } else if (lquery) { return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } /* Form a split Cholesky factorization of B. */ spbstf_(uplo, n, kb, &bb[bb_offset], ldbb, info); if (*info != 0) { *info = *n + *info; return 0; } /* Transform problem to standard eigenvalue problem. */ inde = 1; indwrk = inde + *n; indwk2 = indwrk + *n * *n; llwrk2 = *lwork - indwk2 + 1; ssbgst_(jobz, uplo, n, ka, kb, &ab[ab_offset], ldab, &bb[bb_offset], ldbb, &z__[z_offset], ldz, &work[indwrk], &iinfo) ; /* Reduce to tridiagonal form. */ if (wantz) { *(unsigned char *)vect = 'U'; } else { *(unsigned char *)vect = 'N'; } ssbtrd_(vect, uplo, n, ka, &ab[ab_offset], ldab, &w[1], &work[inde], &z__[ z_offset], ldz, &work[indwrk], &iinfo); /* For eigenvalues only, call SSTERF. For eigenvectors, call SSTEDC. */ if (! wantz) { ssterf_(n, &w[1], &work[inde], info); } else { sstedc_("I", n, &w[1], &work[inde], &work[indwrk], n, &work[indwk2], & llwrk2, &iwork[1], liwork, info); sgemm_("N", "N", n, n, n, &c_b12, &z__[z_offset], ldz, &work[indwrk], n, &c_b13, &work[indwk2], n); slacpy_("A", n, n, &work[indwk2], n, &z__[z_offset], ldz); } work[1] = (float) lwmin; iwork[1] = liwmin; return 0; /* End of SSBGVD */ } /* ssbgvd_ */