/* Subroutine */ HYPRE_Int dsterf_(integer *n, doublereal *d__, doublereal *e, integer *info) { /* -- LAPACK 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 ======= DSTERF computes all eigenvalues of a symmetric tridiagonal matrix using the Pal-Walker-Kahan variant of the QL or QR algorithm. Arguments ========= N (input) INTEGER The order of the matrix. N >= 0. D (input/output) DOUBLE PRECISION array, dimension (N) On entry, the n diagonal elements of the tridiagonal matrix. On exit, if INFO = 0, the eigenvalues in ascending order. E (input/output) DOUBLE PRECISION array, dimension (N-1) On entry, the (n-1) subdiagonal elements of the tridiagonal matrix. On exit, E has been destroyed. INFO (output) INTEGER = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value > 0: the algorithm failed to find all of the eigenvalues in a total of 30*N iterations; if INFO = i, then i elements of E have not converged to zero. ===================================================================== Test the input parameters. Parameter adjustments */ /* Table of constant values */ static integer c__0 = 0; static integer c__1 = 1; static doublereal c_b32 = 1.; /* System generated locals */ integer i__1; doublereal d__1, d__2, d__3; /* Builtin functions */ HYPRE_Real sqrt(doublereal), d_sign(doublereal *, doublereal *); /* Local variables */ static doublereal oldc; static integer lend, jtot; extern /* Subroutine */ HYPRE_Int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); static doublereal c__; static integer i__, l, m; static doublereal p, gamma, r__, s, alpha, sigma, anorm; static integer l1; extern doublereal dlapy2_(doublereal *, doublereal *); static doublereal bb; extern doublereal dlamch_(const char *); static integer iscale; extern /* Subroutine */ HYPRE_Int dlascl_(const char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *); static doublereal oldgam, safmin; extern /* Subroutine */ HYPRE_Int xerbla_(const char *, integer *); static doublereal safmax; extern doublereal dlanst_(const char *, integer *, doublereal *, doublereal *); extern /* Subroutine */ HYPRE_Int dlasrt_(const char *, integer *, doublereal *, integer *); static integer lendsv; static doublereal ssfmin; static integer nmaxit; static doublereal ssfmax, rt1, rt2, eps, rte; static integer lsv; static doublereal eps2; --e; --d__; /* Function Body */ *info = 0; /* Quick return if possible */ if (*n < 0) { *info = -1; i__1 = -(*info); xerbla_("DSTERF", &i__1); return 0; } if (*n <= 1) { return 0; } /* Determine the unit roundoff for this environment. */ eps = dlamch_("E"); /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; safmin = dlamch_("S"); safmax = 1. / safmin; ssfmax = sqrt(safmax) / 3.; ssfmin = sqrt(safmin) / eps2; /* Compute the eigenvalues of the tridiagonal matrix. */ nmaxit = *n * 30; sigma = 0.; jtot = 0; /* Determine where the matrix splits and choose QL or QR iteration for each block, according to whether top or bottom diagonal element is smaller. */ l1 = 1; L10: if (l1 > *n) { goto L170; } if (l1 > 1) { e[l1 - 1] = 0.; } i__1 = *n - 1; for (m = l1; m <= i__1; ++m) { if ((d__3 = e[m], abs(d__3)) <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m + 1], abs(d__2))) * eps) { e[m] = 0.; goto L30; } /* L20: */ } m = *n; L30: l = l1; lsv = l; lend = m; lendsv = lend; l1 = m + 1; if (lend == l) { goto L10; } /* Scale submatrix in rows and columns L to LEND */ i__1 = lend - l + 1; anorm = dlanst_("I", &i__1, &d__[l], &e[l]); iscale = 0; if (anorm > ssfmax) { iscale = 1; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, info); } else if (anorm < ssfmin) { iscale = 2; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, info); } i__1 = lend - 1; for (i__ = l; i__ <= i__1; ++i__) { /* Computing 2nd power */ d__1 = e[i__]; e[i__] = d__1 * d__1; /* L40: */ } /* Choose between QL and QR iteration */ if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { lend = lsv; l = lendsv; } if (lend >= l) { /* QL Iteration Look for small subdiagonal element. */ L50: if (l != lend) { i__1 = lend - 1; for (m = l; m <= i__1; ++m) { if ((d__2 = e[m], abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m + 1], abs(d__1))) { goto L70; } /* L60: */ } } m = lend; L70: if (m < lend) { e[m] = 0.; } p = d__[l]; if (m == l) { goto L90; } /* If remaining matrix is 2 by 2, use DLAE2 to compute its eigenvalues. */ if (m == l + 1) { rte = sqrt(e[l]); dlae2_(&d__[l], &rte, &d__[l + 1], &rt1, &rt2); d__[l] = rt1; d__[l + 1] = rt2; e[l] = 0.; l += 2; if (l <= lend) { goto L50; } goto L150; } if (jtot == nmaxit) { goto L150; } ++jtot; /* Form shift. */ rte = sqrt(e[l]); sigma = (d__[l + 1] - p) / (rte * 2.); r__ = dlapy2_(&sigma, &c_b32); sigma = p - rte / (sigma + d_sign(&r__, &sigma)); c__ = 1.; s = 0.; gamma = d__[m] - sigma; p = gamma * gamma; /* Inner loop */ i__1 = l; for (i__ = m - 1; i__ >= i__1; --i__) { bb = e[i__]; r__ = p + bb; if (i__ != m - 1) { e[i__ + 1] = s * r__; } oldc = c__; c__ = p / r__; s = bb / r__; oldgam = gamma; alpha = d__[i__]; gamma = c__ * (alpha - sigma) - s * oldgam; d__[i__ + 1] = oldgam + (alpha - gamma); if (c__ != 0.) { p = gamma * gamma / c__; } else { p = oldc * bb; } /* L80: */ } e[l] = s * p; d__[l] = sigma + gamma; goto L50; /* Eigenvalue found. */ L90: d__[l] = p; ++l; if (l <= lend) { goto L50; } goto L150; } else { /* QR Iteration Look for small superdiagonal element. */ L100: i__1 = lend + 1; for (m = l; m >= i__1; --m) { if ((d__2 = e[m - 1], abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m - 1], abs(d__1))) { goto L120; } /* L110: */ } m = lend; L120: if (m > lend) { e[m - 1] = 0.; } p = d__[l]; if (m == l) { goto L140; } /* If remaining matrix is 2 by 2, use DLAE2 to compute its eigenvalues. */ if (m == l - 1) { rte = sqrt(e[l - 1]); dlae2_(&d__[l], &rte, &d__[l - 1], &rt1, &rt2); d__[l] = rt1; d__[l - 1] = rt2; e[l - 1] = 0.; l += -2; if (l >= lend) { goto L100; } goto L150; } if (jtot == nmaxit) { goto L150; } ++jtot; /* Form shift. */ rte = sqrt(e[l - 1]); sigma = (d__[l - 1] - p) / (rte * 2.); r__ = dlapy2_(&sigma, &c_b32); sigma = p - rte / (sigma + d_sign(&r__, &sigma)); c__ = 1.; s = 0.; gamma = d__[m] - sigma; p = gamma * gamma; /* Inner loop */ i__1 = l - 1; for (i__ = m; i__ <= i__1; ++i__) { bb = e[i__]; r__ = p + bb; if (i__ != m) { e[i__ - 1] = s * r__; } oldc = c__; c__ = p / r__; s = bb / r__; oldgam = gamma; alpha = d__[i__ + 1]; gamma = c__ * (alpha - sigma) - s * oldgam; d__[i__] = oldgam + (alpha - gamma); if (c__ != 0.) { p = gamma * gamma / c__; } else { p = oldc * bb; } /* L130: */ } e[l - 1] = s * p; d__[l] = sigma + gamma; goto L100; /* Eigenvalue found. */ L140: d__[l] = p; --l; if (l >= lend) { goto L100; } goto L150; } /* Undo scaling if necessary */ L150: if (iscale == 1) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], n, info); } if (iscale == 2) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], n, info); } /* Check for no convergence to an eigenvalue after a total of N*MAXIT iterations. */ if (jtot < nmaxit) { goto L10; } i__1 = *n - 1; for (i__ = 1; i__ <= i__1; ++i__) { if (e[i__] != 0.) { ++(*info); } /* L160: */ } goto L180; /* Sort eigenvalues in increasing order. */ L170: dlasrt_("I", n, &d__[1], info); L180: return 0; /* End of DSTERF */ } /* dsterf_ */
/* Subroutine */ int dsterf_(integer *n, doublereal *d__, doublereal *e, integer *info) { /* System generated locals */ integer i__1; doublereal d__1, d__2, d__3; /* Builtin functions */ double sqrt(doublereal), d_sign(doublereal *, doublereal *); /* Local variables */ doublereal c__; integer i__, l, m; doublereal p, r__, s; integer l1; doublereal bb, rt1, rt2, eps, rte; integer lsv; doublereal eps2, oldc; integer lend; doublereal rmax; integer jtot; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal gamma, alpha, sigma, anorm; extern doublereal dlapy2_(doublereal *, doublereal *), dlamch_(char *); integer iscale; extern /* Subroutine */ int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *); doublereal oldgam, safmin; extern /* Subroutine */ int xerbla_(char *, integer *); doublereal safmax; extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, integer *); integer lendsv; doublereal ssfmin; integer nmaxit; doublereal ssfmax; /* -- LAPACK computational routine (version 3.4.0) -- */ /* -- LAPACK is a software package provided by Univ. of Tennessee, -- */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ /* November 2011 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* ===================================================================== */ /* .. Parameters .. */ /* .. */ /* .. Local Scalars .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Intrinsic Functions .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ --e; --d__; /* Function Body */ *info = 0; /* Quick return if possible */ if (*n < 0) { *info = -1; i__1 = -(*info); xerbla_("DSTERF", &i__1); return 0; } if (*n <= 1) { return 0; } /* Determine the unit roundoff for this environment. */ eps = dlamch_("E"); /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; safmin = dlamch_("S"); safmax = 1. / safmin; ssfmax = sqrt(safmax) / 3.; ssfmin = sqrt(safmin) / eps2; rmax = dlamch_("O"); /* Compute the eigenvalues of the tridiagonal matrix. */ nmaxit = *n * 30; sigma = 0.; jtot = 0; /* Determine where the matrix splits and choose QL or QR iteration */ /* for each block, according to whether top or bottom diagonal */ /* element is smaller. */ l1 = 1; L10: if (l1 > *n) { goto L170; } if (l1 > 1) { e[l1 - 1] = 0.; } i__1 = *n - 1; for (m = l1; m <= i__1; ++m) { if ((d__3 = e[m], f2c_abs(d__3)) <= sqrt((d__1 = d__[m], f2c_abs(d__1))) * sqrt((d__2 = d__[m + 1], f2c_abs(d__2))) * eps) { e[m] = 0.; goto L30; } /* L20: */ } m = *n; L30: l = l1; lsv = l; lend = m; lendsv = lend; l1 = m + 1; if (lend == l) { goto L10; } /* Scale submatrix in rows and columns L to LEND */ i__1 = lend - l + 1; anorm = dlanst_("M", &i__1, &d__[l], &e[l]); iscale = 0; if (anorm == 0.) { goto L10; } if (anorm > ssfmax) { iscale = 1; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, info); } else if (anorm < ssfmin) { iscale = 2; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, info); } i__1 = lend - 1; for (i__ = l; i__ <= i__1; ++i__) { /* Computing 2nd power */ d__1 = e[i__]; e[i__] = d__1 * d__1; /* L40: */ } /* Choose between QL and QR iteration */ if ((d__1 = d__[lend], f2c_abs(d__1)) < (d__2 = d__[l], f2c_abs(d__2))) { lend = lsv; l = lendsv; } if (lend >= l) { /* QL Iteration */ /* Look for small subdiagonal element. */ L50: if (l != lend) { i__1 = lend - 1; for (m = l; m <= i__1; ++m) { if ((d__2 = e[m], f2c_abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m + 1], f2c_abs(d__1))) { goto L70; } /* L60: */ } } m = lend; L70: if (m < lend) { e[m] = 0.; } p = d__[l]; if (m == l) { goto L90; } /* If remaining matrix is 2 by 2, use DLAE2 to compute its */ /* eigenvalues. */ if (m == l + 1) { rte = sqrt(e[l]); dlae2_(&d__[l], &rte, &d__[l + 1], &rt1, &rt2); d__[l] = rt1; d__[l + 1] = rt2; e[l] = 0.; l += 2; if (l <= lend) { goto L50; } goto L150; } if (jtot == nmaxit) { goto L150; } ++jtot; /* Form shift. */ rte = sqrt(e[l]); sigma = (d__[l + 1] - p) / (rte * 2.); r__ = dlapy2_(&sigma, &c_b33); sigma = p - rte / (sigma + d_sign(&r__, &sigma)); c__ = 1.; s = 0.; gamma = d__[m] - sigma; p = gamma * gamma; /* Inner loop */ i__1 = l; for (i__ = m - 1; i__ >= i__1; --i__) { bb = e[i__]; r__ = p + bb; if (i__ != m - 1) { e[i__ + 1] = s * r__; } oldc = c__; c__ = p / r__; s = bb / r__; oldgam = gamma; alpha = d__[i__]; gamma = c__ * (alpha - sigma) - s * oldgam; d__[i__ + 1] = oldgam + (alpha - gamma); if (c__ != 0.) { p = gamma * gamma / c__; } else { p = oldc * bb; } /* L80: */ } e[l] = s * p; d__[l] = sigma + gamma; goto L50; /* Eigenvalue found. */ L90: d__[l] = p; ++l; if (l <= lend) { goto L50; } goto L150; } else { /* QR Iteration */ /* Look for small superdiagonal element. */ L100: i__1 = lend + 1; for (m = l; m >= i__1; --m) { if ((d__2 = e[m - 1], f2c_abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m - 1], f2c_abs(d__1))) { goto L120; } /* L110: */ } m = lend; L120: if (m > lend) { e[m - 1] = 0.; } p = d__[l]; if (m == l) { goto L140; } /* If remaining matrix is 2 by 2, use DLAE2 to compute its */ /* eigenvalues. */ if (m == l - 1) { rte = sqrt(e[l - 1]); dlae2_(&d__[l], &rte, &d__[l - 1], &rt1, &rt2); d__[l] = rt1; d__[l - 1] = rt2; e[l - 1] = 0.; l += -2; if (l >= lend) { goto L100; } goto L150; } if (jtot == nmaxit) { goto L150; } ++jtot; /* Form shift. */ rte = sqrt(e[l - 1]); sigma = (d__[l - 1] - p) / (rte * 2.); r__ = dlapy2_(&sigma, &c_b33); sigma = p - rte / (sigma + d_sign(&r__, &sigma)); c__ = 1.; s = 0.; gamma = d__[m] - sigma; p = gamma * gamma; /* Inner loop */ i__1 = l - 1; for (i__ = m; i__ <= i__1; ++i__) { bb = e[i__]; r__ = p + bb; if (i__ != m) { e[i__ - 1] = s * r__; } oldc = c__; c__ = p / r__; s = bb / r__; oldgam = gamma; alpha = d__[i__ + 1]; gamma = c__ * (alpha - sigma) - s * oldgam; d__[i__] = oldgam + (alpha - gamma); if (c__ != 0.) { p = gamma * gamma / c__; } else { p = oldc * bb; } /* L130: */ } e[l - 1] = s * p; d__[l] = sigma + gamma; goto L100; /* Eigenvalue found. */ L140: d__[l] = p; --l; if (l >= lend) { goto L100; } goto L150; } /* Undo scaling if necessary */ L150: if (iscale == 1) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], n, info); } if (iscale == 2) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], n, info); } /* Check for no convergence to an eigenvalue after a total */ /* of N*MAXIT iterations. */ if (jtot < nmaxit) { goto L10; } i__1 = *n - 1; for (i__ = 1; i__ <= i__1; ++i__) { if (e[i__] != 0.) { ++(*info); } /* L160: */ } goto L180; /* Sort eigenvalues in increasing order. */ L170: dlasrt_("I", n, &d__[1], info); L180: return 0; /* End of DSTERF */ }
/*< SUBROUTINE DSTEQR( COMPZ, N, D, E, Z, LDZ, WORK, INFO ) >*/ /* Subroutine */ int dsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublereal *z__, integer *ldz, doublereal *work, integer *info, ftnlen compz_len) { /* System generated locals */ integer z_dim1, z_offset, i__1, i__2; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal), d_sign(doublereal *, doublereal *); /* Local variables */ doublereal b, c__, f, g; integer i__, j, k, l, m; doublereal p, r__, s; integer l1, ii, mm, lm1, mm1, nm1; doublereal rt1, rt2, eps; integer lsv; doublereal tst, eps2; integer lend, jtot; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); extern logical lsame_(const char *, const char *, ftnlen, ftnlen); extern /* Subroutine */ int dlasr_(char *, char *, char *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, ftnlen, ftnlen, ftnlen); doublereal anorm; extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, doublereal *, integer *), dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); integer lendm1, lendp1; extern doublereal dlapy2_(doublereal *, doublereal *), dlamch_(char *, ftnlen); integer iscale; extern /* Subroutine */ int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *, ftnlen), dlaset_(char *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, ftnlen); doublereal safmin; extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal safmax; extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *, ftnlen); extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, integer *, ftnlen); integer lendsv; doublereal ssfmin; integer nmaxit, icompz; doublereal ssfmax; /* -- LAPACK routine (version 3.2) -- */ /* -- LAPACK is a software package provided by Univ. of Tennessee, -- */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ /* November 2006 */ /* .. Scalar Arguments .. */ /*< CHARACTER COMPZ >*/ /*< INTEGER INFO, LDZ, N >*/ /* .. */ /* .. Array Arguments .. */ /*< DOUBLE PRECISION D( * ), E( * ), WORK( * ), Z( LDZ, * ) >*/ /* .. */ /* Purpose */ /* ======= */ /* DSTEQR computes all eigenvalues and, optionally, eigenvectors of a */ /* symmetric tridiagonal matrix using the implicit QL or QR method. */ /* The eigenvectors of a full or band symmetric matrix can also be found */ /* if DSYTRD or DSPTRD or DSBTRD has been used to reduce this matrix to */ /* tridiagonal form. */ /* Arguments */ /* ========= */ /* COMPZ (input) CHARACTER*1 */ /* = 'N': Compute eigenvalues only. */ /* = 'V': Compute eigenvalues and eigenvectors of the original */ /* symmetric matrix. On entry, Z must contain the */ /* orthogonal matrix used to reduce the original matrix */ /* to tridiagonal form. */ /* = 'I': Compute eigenvalues and eigenvectors of the */ /* tridiagonal matrix. Z is initialized to the identity */ /* matrix. */ /* N (input) INTEGER */ /* The order of the matrix. N >= 0. */ /* D (input/output) DOUBLE PRECISION 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) DOUBLE PRECISION array, dimension (N-1) */ /* On entry, the (n-1) subdiagonal elements of the tridiagonal */ /* matrix. */ /* On exit, E has been destroyed. */ /* Z (input/output) DOUBLE PRECISION array, dimension (LDZ, N) */ /* On entry, if COMPZ = 'V', then Z contains the orthogonal */ /* 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 symmetric 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, and if */ /* eigenvectors are desired, then LDZ >= max(1,N). */ /* WORK (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2)) */ /* If COMPZ = 'N', then WORK is not referenced. */ /* INFO (output) INTEGER */ /* = 0: successful exit */ /* < 0: if INFO = -i, the i-th argument had an illegal value */ /* > 0: the algorithm has failed to find all the eigenvalues in */ /* a total of 30*N iterations; if INFO = i, then i */ /* elements of E have not converged to zero; on exit, D */ /* and E contain the elements of a symmetric tridiagonal */ /* matrix which is orthogonally similar to the original */ /* matrix. */ /* ===================================================================== */ /* .. Parameters .. */ /*< DOUBLE PRECISION ZERO, ONE, TWO, THREE >*/ /*< >*/ /*< INTEGER MAXIT >*/ /*< PARAMETER ( MAXIT = 30 ) >*/ /* .. */ /* .. Local Scalars .. */ /*< >*/ /*< >*/ /* .. */ /* .. External Functions .. */ /*< LOGICAL LSAME >*/ /*< DOUBLE PRECISION DLAMCH, DLANST, DLAPY2 >*/ /*< EXTERNAL LSAME, DLAMCH, DLANST, DLAPY2 >*/ /* .. */ /* .. External Subroutines .. */ /*< >*/ /* .. */ /* .. Intrinsic Functions .. */ /*< INTRINSIC ABS, MAX, SIGN, SQRT >*/ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /*< INFO = 0 >*/ /* Parameter adjustments */ --d__; --e; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --work; /* Function Body */ *info = 0; /*< IF( LSAME( COMPZ, 'N' ) ) THEN >*/ if (lsame_(compz, "N", (ftnlen)1, (ftnlen)1)) { /*< ICOMPZ = 0 >*/ icompz = 0; /*< ELSE IF( LSAME( COMPZ, 'V' ) ) THEN >*/ } else if (lsame_(compz, "V", (ftnlen)1, (ftnlen)1)) { /*< ICOMPZ = 1 >*/ icompz = 1; /*< ELSE IF( LSAME( COMPZ, 'I' ) ) THEN >*/ } else if (lsame_(compz, "I", (ftnlen)1, (ftnlen)1)) { /*< ICOMPZ = 2 >*/ icompz = 2; /*< ELSE >*/ } else { /*< ICOMPZ = -1 >*/ icompz = -1; /*< END IF >*/ } /*< IF( ICOMPZ.LT.0 ) THEN >*/ if (icompz < 0) { /*< INFO = -1 >*/ *info = -1; /*< ELSE IF( N.LT.0 ) THEN >*/ } else if (*n < 0) { /*< INFO = -2 >*/ *info = -2; /*< >*/ } else if (*ldz < 1 || (icompz > 0 && *ldz < max(1,*n))) { /*< INFO = -6 >*/ *info = -6; /*< END IF >*/ } /*< IF( INFO.NE.0 ) THEN >*/ if (*info != 0) { /*< CALL XERBLA( 'DSTEQR', -INFO ) >*/ i__1 = -(*info); xerbla_("DSTEQR", &i__1, (ftnlen)6); /*< RETURN >*/ return 0; /*< END IF >*/ } /* Quick return if possible */ /*< >*/ if (*n == 0) { return 0; } /*< IF( N.EQ.1 ) THEN >*/ if (*n == 1) { /*< >*/ if (icompz == 2) { z__[z_dim1 + 1] = 1.; } /*< RETURN >*/ return 0; /*< END IF >*/ } /* Determine the unit roundoff and over/underflow thresholds. */ /*< EPS = DLAMCH( 'E' ) >*/ eps = dlamch_("E", (ftnlen)1); /*< EPS2 = EPS**2 >*/ /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; /*< SAFMIN = DLAMCH( 'S' ) >*/ safmin = dlamch_("S", (ftnlen)1); /*< SAFMAX = ONE / SAFMIN >*/ safmax = 1. / safmin; /*< SSFMAX = SQRT( SAFMAX ) / THREE >*/ ssfmax = sqrt(safmax) / 3.; /*< SSFMIN = SQRT( SAFMIN ) / EPS2 >*/ ssfmin = sqrt(safmin) / eps2; /* Compute the eigenvalues and eigenvectors of the tridiagonal */ /* matrix. */ /*< >*/ if (icompz == 2) { dlaset_("Full", n, n, &c_b9, &c_b10, &z__[z_offset], ldz, (ftnlen)4); } /*< NMAXIT = N*MAXIT >*/ nmaxit = *n * 30; /*< JTOT = 0 >*/ jtot = 0; /* Determine where the matrix splits and choose QL or QR iteration */ /* for each block, according to whether top or bottom diagonal */ /* element is smaller. */ /*< L1 = 1 >*/ l1 = 1; /*< NM1 = N - 1 >*/ nm1 = *n - 1; /*< 10 CONTINUE >*/ L10: /*< >*/ if (l1 > *n) { goto L160; } /*< >*/ if (l1 > 1) { e[l1 - 1] = 0.; } /*< IF( L1.LE.NM1 ) THEN >*/ if (l1 <= nm1) { /*< DO 20 M = L1, NM1 >*/ i__1 = nm1; for (m = l1; m <= i__1; ++m) { /*< TST = ABS( E( M ) ) >*/ tst = (d__1 = e[m], abs(d__1)); /*< >*/ if (tst == 0.) { goto L30; } /*< >*/ if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m + 1], abs(d__2))) * eps) { /*< E( M ) = ZERO >*/ e[m] = 0.; /*< GO TO 30 >*/ goto L30; /*< END IF >*/ } /*< 20 CONTINUE >*/ /* L20: */ } /*< END IF >*/ } /*< M = N >*/ m = *n; /*< 30 CONTINUE >*/ L30: /*< L = L1 >*/ l = l1; /*< LSV = L >*/ lsv = l; /*< LEND = M >*/ lend = m; /*< LENDSV = LEND >*/ lendsv = lend; /*< L1 = M + 1 >*/ l1 = m + 1; /*< >*/ if (lend == l) { goto L10; } /* Scale submatrix in rows and columns L to LEND */ /*< ANORM = DLANST( 'I', LEND-L+1, D( L ), E( L ) ) >*/ i__1 = lend - l + 1; anorm = dlanst_("I", &i__1, &d__[l], &e[l], (ftnlen)1); /*< ISCALE = 0 >*/ iscale = 0; /*< >*/ if (anorm == 0.) { goto L10; } /*< IF( ANORM.GT.SSFMAX ) THEN >*/ if (anorm > ssfmax) { /*< ISCALE = 1 >*/ iscale = 1; /*< >*/ i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, info, (ftnlen)1); /*< >*/ i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, info, (ftnlen)1); /*< ELSE IF( ANORM.LT.SSFMIN ) THEN >*/ } else if (anorm < ssfmin) { /*< ISCALE = 2 >*/ iscale = 2; /*< >*/ i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, info, (ftnlen)1); /*< >*/ i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, info, (ftnlen)1); /*< END IF >*/ } /* Choose between QL and QR iteration */ /*< IF( ABS( D( LEND ) ).LT.ABS( D( L ) ) ) THEN >*/ if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { /*< LEND = LSV >*/ lend = lsv; /*< L = LENDSV >*/ l = lendsv; /*< END IF >*/ } /*< IF( LEND.GT.L ) THEN >*/ if (lend > l) { /* QL Iteration */ /* Look for small subdiagonal element. */ /*< 40 CONTINUE >*/ L40: /*< IF( L.NE.LEND ) THEN >*/ if (l != lend) { /*< LENDM1 = LEND - 1 >*/ lendm1 = lend - 1; /*< DO 50 M = L, LENDM1 >*/ i__1 = lendm1; for (m = l; m <= i__1; ++m) { /*< TST = ABS( E( M ) )**2 >*/ /* Computing 2nd power */ d__2 = (d__1 = e[m], abs(d__1)); tst = d__2 * d__2; /*< >*/ if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + 1], abs(d__2)) + safmin) { goto L60; } /*< 50 CONTINUE >*/ /* L50: */ } /*< END IF >*/ } /*< M = LEND >*/ m = lend; /*< 60 CONTINUE >*/ L60: /*< >*/ if (m < lend) { e[m] = 0.; } /*< P = D( L ) >*/ p = d__[l]; /*< >*/ if (m == l) { goto L80; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 */ /* to compute its eigensystem. */ /*< IF( M.EQ.L+1 ) THEN >*/ if (m == l + 1) { /*< IF( ICOMPZ.GT.0 ) THEN >*/ if (icompz > 0) { /*< CALL DLAEV2( D( L ), E( L ), D( L+1 ), RT1, RT2, C, S ) >*/ dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); /*< WORK( L ) = C >*/ work[l] = c__; /*< WORK( N-1+L ) = S >*/ work[*n - 1 + l] = s; /*< >*/ dlasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], & z__[l * z_dim1 + 1], ldz, (ftnlen)1, (ftnlen)1, ( ftnlen)1); /*< ELSE >*/ } else { /*< CALL DLAE2( D( L ), E( L ), D( L+1 ), RT1, RT2 ) >*/ dlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); /*< END IF >*/ } /*< D( L ) = RT1 >*/ d__[l] = rt1; /*< D( L+1 ) = RT2 >*/ d__[l + 1] = rt2; /*< E( L ) = ZERO >*/ e[l] = 0.; /*< L = L + 2 >*/ l += 2; /*< >*/ if (l <= lend) { goto L40; } /*< GO TO 140 >*/ goto L140; /*< END IF >*/ } /*< >*/ if (jtot == nmaxit) { goto L140; } /*< JTOT = JTOT + 1 >*/ ++jtot; /* Form shift. */ /*< G = ( D( L+1 )-P ) / ( TWO*E( L ) ) >*/ g = (d__[l + 1] - p) / (e[l] * 2.); /*< R = DLAPY2( G, ONE ) >*/ r__ = dlapy2_(&g, &c_b10); /*< G = D( M ) - P + ( E( L ) / ( G+SIGN( R, G ) ) ) >*/ g = d__[m] - p + e[l] / (g + d_sign(&r__, &g)); /*< S = ONE >*/ s = 1.; /*< C = ONE >*/ c__ = 1.; /*< P = ZERO >*/ p = 0.; /* Inner loop */ /*< MM1 = M - 1 >*/ mm1 = m - 1; /*< DO 70 I = MM1, L, -1 >*/ i__1 = l; for (i__ = mm1; i__ >= i__1; --i__) { /*< F = S*E( I ) >*/ f = s * e[i__]; /*< B = C*E( I ) >*/ b = c__ * e[i__]; /*< CALL DLARTG( G, F, C, S, R ) >*/ dlartg_(&g, &f, &c__, &s, &r__); /*< >*/ if (i__ != m - 1) { e[i__ + 1] = r__; } /*< G = D( I+1 ) - P >*/ g = d__[i__ + 1] - p; /*< R = ( D( I )-G )*S + TWO*C*B >*/ r__ = (d__[i__] - g) * s + c__ * 2. * b; /*< P = S*R >*/ p = s * r__; /*< D( I+1 ) = G + P >*/ d__[i__ + 1] = g + p; /*< G = C*R - B >*/ g = c__ * r__ - b; /* If eigenvectors are desired, then save rotations. */ /*< IF( ICOMPZ.GT.0 ) THEN >*/ if (icompz > 0) { /*< WORK( I ) = C >*/ work[i__] = c__; /*< WORK( N-1+I ) = -S >*/ work[*n - 1 + i__] = -s; /*< END IF >*/ } /*< 70 CONTINUE >*/ /* L70: */ } /* If eigenvectors are desired, then apply saved rotations. */ /*< IF( ICOMPZ.GT.0 ) THEN >*/ if (icompz > 0) { /*< MM = M - L + 1 >*/ mm = m - l + 1; /*< >*/ dlasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l * z_dim1 + 1], ldz, (ftnlen)1, (ftnlen)1, (ftnlen)1); /*< END IF >*/ } /*< D( L ) = D( L ) - P >*/ d__[l] -= p; /*< E( L ) = G >*/ e[l] = g; /*< GO TO 40 >*/ goto L40; /* Eigenvalue found. */ /*< 80 CONTINUE >*/ L80: /*< D( L ) = P >*/ d__[l] = p; /*< L = L + 1 >*/ ++l; /*< >*/ if (l <= lend) { goto L40; } /*< GO TO 140 >*/ goto L140; /*< ELSE >*/ } else { /* QR Iteration */ /* Look for small superdiagonal element. */ /*< 90 CONTINUE >*/ L90: /*< IF( L.NE.LEND ) THEN >*/ if (l != lend) { /*< LENDP1 = LEND + 1 >*/ lendp1 = lend + 1; /*< DO 100 M = L, LENDP1, -1 >*/ i__1 = lendp1; for (m = l; m >= i__1; --m) { /*< TST = ABS( E( M-1 ) )**2 >*/ /* Computing 2nd power */ d__2 = (d__1 = e[m - 1], abs(d__1)); tst = d__2 * d__2; /*< >*/ if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m - 1], abs(d__2)) + safmin) { goto L110; } /*< 100 CONTINUE >*/ /* L100: */ } /*< END IF >*/ } /*< M = LEND >*/ m = lend; /*< 110 CONTINUE >*/ L110: /*< >*/ if (m > lend) { e[m - 1] = 0.; } /*< P = D( L ) >*/ p = d__[l]; /*< >*/ if (m == l) { goto L130; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 */ /* to compute its eigensystem. */ /*< IF( M.EQ.L-1 ) THEN >*/ if (m == l - 1) { /*< IF( ICOMPZ.GT.0 ) THEN >*/ if (icompz > 0) { /*< CALL DLAEV2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2, C, S ) >*/ dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) ; /*< WORK( M ) = C >*/ work[m] = c__; /*< WORK( N-1+M ) = S >*/ work[*n - 1 + m] = s; /*< >*/ dlasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], & z__[(l - 1) * z_dim1 + 1], ldz, (ftnlen)1, (ftnlen)1, (ftnlen)1); /*< ELSE >*/ } else { /*< CALL DLAE2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2 ) >*/ dlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); /*< END IF >*/ } /*< D( L-1 ) = RT1 >*/ d__[l - 1] = rt1; /*< D( L ) = RT2 >*/ d__[l] = rt2; /*< E( L-1 ) = ZERO >*/ e[l - 1] = 0.; /*< L = L - 2 >*/ l += -2; /*< >*/ if (l >= lend) { goto L90; } /*< GO TO 140 >*/ goto L140; /*< END IF >*/ } /*< >*/ if (jtot == nmaxit) { goto L140; } /*< JTOT = JTOT + 1 >*/ ++jtot; /* Form shift. */ /*< G = ( D( L-1 )-P ) / ( TWO*E( L-1 ) ) >*/ g = (d__[l - 1] - p) / (e[l - 1] * 2.); /*< R = DLAPY2( G, ONE ) >*/ r__ = dlapy2_(&g, &c_b10); /*< G = D( M ) - P + ( E( L-1 ) / ( G+SIGN( R, G ) ) ) >*/ g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g)); /*< S = ONE >*/ s = 1.; /*< C = ONE >*/ c__ = 1.; /*< P = ZERO >*/ p = 0.; /* Inner loop */ /*< LM1 = L - 1 >*/ lm1 = l - 1; /*< DO 120 I = M, LM1 >*/ i__1 = lm1; for (i__ = m; i__ <= i__1; ++i__) { /*< F = S*E( I ) >*/ f = s * e[i__]; /*< B = C*E( I ) >*/ b = c__ * e[i__]; /*< CALL DLARTG( G, F, C, S, R ) >*/ dlartg_(&g, &f, &c__, &s, &r__); /*< >*/ if (i__ != m) { e[i__ - 1] = r__; } /*< G = D( I ) - P >*/ g = d__[i__] - p; /*< R = ( D( I+1 )-G )*S + TWO*C*B >*/ r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b; /*< P = S*R >*/ p = s * r__; /*< D( I ) = G + P >*/ d__[i__] = g + p; /*< G = C*R - B >*/ g = c__ * r__ - b; /* If eigenvectors are desired, then save rotations. */ /*< IF( ICOMPZ.GT.0 ) THEN >*/ if (icompz > 0) { /*< WORK( I ) = C >*/ work[i__] = c__; /*< WORK( N-1+I ) = S >*/ work[*n - 1 + i__] = s; /*< END IF >*/ } /*< 120 CONTINUE >*/ /* L120: */ } /* If eigenvectors are desired, then apply saved rotations. */ /*< IF( ICOMPZ.GT.0 ) THEN >*/ if (icompz > 0) { /*< MM = L - M + 1 >*/ mm = l - m + 1; /*< >*/ dlasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m * z_dim1 + 1], ldz, (ftnlen)1, (ftnlen)1, (ftnlen)1); /*< END IF >*/ } /*< D( L ) = D( L ) - P >*/ d__[l] -= p; /*< E( LM1 ) = G >*/ e[lm1] = g; /*< GO TO 90 >*/ goto L90; /* Eigenvalue found. */ /*< 130 CONTINUE >*/ L130: /*< D( L ) = P >*/ d__[l] = p; /*< L = L - 1 >*/ --l; /*< >*/ if (l >= lend) { goto L90; } /*< GO TO 140 >*/ goto L140; /*< END IF >*/ } /* Undo scaling if necessary */ /*< 140 CONTINUE >*/ L140: /*< IF( ISCALE.EQ.1 ) THEN >*/ if (iscale == 1) { /*< >*/ i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], n, info, (ftnlen)1); /*< >*/ i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, info, (ftnlen)1); /*< ELSE IF( ISCALE.EQ.2 ) THEN >*/ } else if (iscale == 2) { /*< >*/ i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], n, info, (ftnlen)1); /*< >*/ i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, info, (ftnlen)1); /*< END IF >*/ } /* Check for no convergence to an eigenvalue after a total */ /* of N*MAXIT iterations. */ /*< >*/ if (jtot < nmaxit) { goto L10; } /*< DO 150 I = 1, N - 1 >*/ i__1 = *n - 1; for (i__ = 1; i__ <= i__1; ++i__) { /*< >*/ if (e[i__] != 0.) { ++(*info); } /*< 150 CONTINUE >*/ /* L150: */ } /*< GO TO 190 >*/ goto L190; /* Order eigenvalues and eigenvectors. */ /*< 160 CONTINUE >*/ L160: /*< IF( ICOMPZ.EQ.0 ) THEN >*/ if (icompz == 0) { /* Use Quick Sort */ /*< CALL DLASRT( 'I', N, D, INFO ) >*/ dlasrt_("I", n, &d__[1], info, (ftnlen)1); /*< ELSE >*/ } else { /* Use Selection Sort to minimize swaps of eigenvectors */ /*< DO 180 II = 2, N >*/ i__1 = *n; for (ii = 2; ii <= i__1; ++ii) { /*< I = II - 1 >*/ i__ = ii - 1; /*< K = I >*/ k = i__; /*< P = D( I ) >*/ p = d__[i__]; /*< DO 170 J = II, N >*/ i__2 = *n; for (j = ii; j <= i__2; ++j) { /*< IF( D( J ).LT.P ) THEN >*/ if (d__[j] < p) { /*< K = J >*/ k = j; /*< P = D( J ) >*/ p = d__[j]; /*< END IF >*/ } /*< 170 CONTINUE >*/ /* L170: */ } /*< IF( K.NE.I ) THEN >*/ if (k != i__) { /*< D( K ) = D( I ) >*/ d__[k] = d__[i__]; /*< D( I ) = P >*/ d__[i__] = p; /*< CALL DSWAP( N, Z( 1, I ), 1, Z( 1, K ), 1 ) >*/ dswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], &c__1); /*< END IF >*/ } /*< 180 CONTINUE >*/ /* L180: */ } /*< END IF >*/ } /*< 190 CONTINUE >*/ L190: /*< RETURN >*/ return 0; /* End of DSTEQR */ /*< END >*/ } /* dsteqr_ */
/* Subroutine */ int zstemr_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, integer *m, doublereal *w, doublecomplex *z__, integer * ldz, integer *nzc, integer *isuppz, logical *tryrac, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info) { /* System generated locals */ integer z_dim1, z_offset, i__1, i__2; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal); /* Local variables */ integer i__, j; doublereal r1, r2; integer jj; doublereal cs; integer in; doublereal sn, wl, wu; integer iil, iiu; doublereal eps, tmp; integer indd, iend, jblk, wend; doublereal rmin, rmax; integer itmp; doublereal tnrm; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); integer inde2, itmp2; doublereal rtol1, rtol2; extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, integer *); doublereal scale; integer indgp; extern logical lsame_(char *, char *); integer iinfo, iindw, ilast; extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, doublereal *, integer *); integer lwmin; logical wantz; extern /* Subroutine */ int zswap_(integer *, doublecomplex *, integer *, doublecomplex *, integer *), dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); extern doublereal dlamch_(char *); logical alleig; integer ibegin; logical indeig; integer iindbl; logical valeig; extern /* Subroutine */ int dlarrc_(char *, integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, integer *, integer *), dlarre_(char *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, integer *); integer wbegin; doublereal safmin; extern /* Subroutine */ int dlarrj_(integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, doublereal *, doublereal *, doublereal *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); doublereal bignum; integer inderr, iindwk, indgrs, offset; extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); extern /* Subroutine */ int dlarrr_(integer *, doublereal *, doublereal *, integer *), dlasrt_(char *, integer *, doublereal *, integer *); doublereal thresh; integer iinspl, indwrk, ifirst, liwmin, nzcmin; doublereal pivmin; integer nsplit; doublereal smlnum; extern /* Subroutine */ int zlarrv_(integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, integer *, integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, doublereal *, doublecomplex *, integer *, integer *, doublereal *, integer *, integer *); logical lquery, zquery; /* -- LAPACK computational routine (version 3.5.0) -- */ /* -- LAPACK is a software package provided by Univ. of Tennessee, -- */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ /* November 2013 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* ===================================================================== */ /* .. Parameters .. */ /* .. */ /* .. Local Scalars .. */ /* .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Intrinsic Functions .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ --d__; --e; --w; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --isuppz; --work; --iwork; /* Function Body */ wantz = lsame_(jobz, "V"); alleig = lsame_(range, "A"); valeig = lsame_(range, "V"); indeig = lsame_(range, "I"); lquery = *lwork == -1 || *liwork == -1; zquery = *nzc == -1; /* DSTEMR needs WORK of size 6*N, IWORK of size 3*N. */ /* In addition, DLARRE needs WORK of size 6*N, IWORK of size 5*N. */ /* Furthermore, ZLARRV needs WORK of size 12*N, IWORK of size 7*N. */ if (wantz) { lwmin = *n * 18; liwmin = *n * 10; } else { /* need less workspace if only the eigenvalues are wanted */ lwmin = *n * 12; liwmin = *n << 3; } wl = 0.; wu = 0.; iil = 0; iiu = 0; nsplit = 0; if (valeig) { /* We do not reference VL, VU in the cases RANGE = 'I','A' */ /* The interval (WL, WU] contains all the wanted eigenvalues. */ /* It is either given by the user or computed in DLARRE. */ wl = *vl; wu = *vu; } else if (indeig) { /* We do not reference IL, IU in the cases RANGE = 'V','A' */ iil = *il; iiu = *iu; } *info = 0; if (! (wantz || lsame_(jobz, "N"))) { *info = -1; } else if (! (alleig || valeig || indeig)) { *info = -2; } else if (*n < 0) { *info = -3; } else if (valeig && *n > 0 && wu <= wl) { *info = -7; } else if (indeig && (iil < 1 || iil > *n)) { *info = -8; } else if (indeig && (iiu < iil || iiu > *n)) { *info = -9; } else if (*ldz < 1 || wantz && *ldz < *n) { *info = -13; } else if (*lwork < lwmin && ! lquery) { *info = -17; } else if (*liwork < liwmin && ! lquery) { *info = -19; } /* Get machine constants. */ safmin = dlamch_("Safe minimum"); eps = dlamch_("Precision"); smlnum = safmin / eps; bignum = 1. / smlnum; rmin = sqrt(smlnum); /* Computing MIN */ d__1 = sqrt(bignum); d__2 = 1. / sqrt(sqrt(safmin)); // , expr subst rmax = min(d__1,d__2); if (*info == 0) { work[1] = (doublereal) lwmin; iwork[1] = liwmin; if (wantz && alleig) { nzcmin = *n; } else if (wantz && valeig) { dlarrc_("T", n, vl, vu, &d__[1], &e[1], &safmin, &nzcmin, &itmp, & itmp2, info); } else if (wantz && indeig) { nzcmin = iiu - iil + 1; } else { /* WANTZ .EQ. FALSE. */ nzcmin = 0; } if (zquery && *info == 0) { i__1 = z_dim1 + 1; z__[i__1].r = (doublereal) nzcmin; z__[i__1].i = 0.; // , expr subst } else if (*nzc < nzcmin && ! zquery) { *info = -14; } } if (*info != 0) { i__1 = -(*info); xerbla_("ZSTEMR", &i__1); return 0; } else if (lquery || zquery) { return 0; } /* Handle N = 0, 1, and 2 cases immediately */ *m = 0; if (*n == 0) { return 0; } if (*n == 1) { if (alleig || indeig) { *m = 1; w[1] = d__[1]; } else { if (wl < d__[1] && wu >= d__[1]) { *m = 1; w[1] = d__[1]; } } if (wantz && ! zquery) { i__1 = z_dim1 + 1; z__[i__1].r = 1.; z__[i__1].i = 0.; // , expr subst isuppz[1] = 1; isuppz[2] = 1; } return 0; } if (*n == 2) { if (! wantz) { dlae2_(&d__[1], &e[1], &d__[2], &r1, &r2); } else if (wantz && ! zquery) { dlaev2_(&d__[1], &e[1], &d__[2], &r1, &r2, &cs, &sn); } if (alleig || valeig && r2 > wl && r2 <= wu || indeig && iil == 1) { ++(*m); w[*m] = r2; if (wantz && ! zquery) { i__1 = *m * z_dim1 + 1; d__1 = -sn; z__[i__1].r = d__1; z__[i__1].i = 0.; // , expr subst i__1 = *m * z_dim1 + 2; z__[i__1].r = cs; z__[i__1].i = 0.; // , expr subst /* Note: At most one of SN and CS can be zero. */ if (sn != 0.) { if (cs != 0.) { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 2; } else { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 1; } } else { isuppz[(*m << 1) - 1] = 2; isuppz[*m * 2] = 2; } } } if (alleig || valeig && r1 > wl && r1 <= wu || indeig && iiu == 2) { ++(*m); w[*m] = r1; if (wantz && ! zquery) { i__1 = *m * z_dim1 + 1; z__[i__1].r = cs; z__[i__1].i = 0.; // , expr subst i__1 = *m * z_dim1 + 2; z__[i__1].r = sn; z__[i__1].i = 0.; // , expr subst /* Note: At most one of SN and CS can be zero. */ if (sn != 0.) { if (cs != 0.) { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 2; } else { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 1; } } else { isuppz[(*m << 1) - 1] = 2; isuppz[*m * 2] = 2; } } } } else { /* Continue with general N */ indgrs = 1; inderr = (*n << 1) + 1; indgp = *n * 3 + 1; indd = (*n << 2) + 1; inde2 = *n * 5 + 1; indwrk = *n * 6 + 1; iinspl = 1; iindbl = *n + 1; iindw = (*n << 1) + 1; iindwk = *n * 3 + 1; /* Scale matrix to allowable range, if necessary. */ /* The allowable range is related to the PIVMIN parameter; see the */ /* comments in DLARRD. The preference for scaling small values */ /* up is heuristic; we expect users' matrices not to be close to the */ /* RMAX threshold. */ scale = 1.; tnrm = dlanst_("M", n, &d__[1], &e[1]); if (tnrm > 0. && tnrm < rmin) { scale = rmin / tnrm; } else if (tnrm > rmax) { scale = rmax / tnrm; } if (scale != 1.) { dscal_(n, &scale, &d__[1], &c__1); i__1 = *n - 1; dscal_(&i__1, &scale, &e[1], &c__1); tnrm *= scale; if (valeig) { /* If eigenvalues in interval have to be found, */ /* scale (WL, WU] accordingly */ wl *= scale; wu *= scale; } } /* Compute the desired eigenvalues of the tridiagonal after splitting */ /* into smaller subblocks if the corresponding off-diagonal elements */ /* are small */ /* THRESH is the splitting parameter for DLARRE */ /* A negative THRESH forces the old splitting criterion based on the */ /* size of the off-diagonal. A positive THRESH switches to splitting */ /* which preserves relative accuracy. */ if (*tryrac) { /* Test whether the matrix warrants the more expensive relative approach. */ dlarrr_(n, &d__[1], &e[1], &iinfo); } else { /* The user does not care about relative accurately eigenvalues */ iinfo = -1; } /* Set the splitting criterion */ if (iinfo == 0) { thresh = eps; } else { thresh = -eps; /* relative accuracy is desired but T does not guarantee it */ *tryrac = FALSE_; } if (*tryrac) { /* Copy original diagonal, needed to guarantee relative accuracy */ dcopy_(n, &d__[1], &c__1, &work[indd], &c__1); } /* Store the squares of the offdiagonal values of T */ i__1 = *n - 1; for (j = 1; j <= i__1; ++j) { /* Computing 2nd power */ d__1 = e[j]; work[inde2 + j - 1] = d__1 * d__1; /* L5: */ } /* Set the tolerance parameters for bisection */ if (! wantz) { /* DLARRE computes the eigenvalues to full precision. */ rtol1 = eps * 4.; rtol2 = eps * 4.; } else { /* DLARRE computes the eigenvalues to less than full precision. */ /* ZLARRV will refine the eigenvalue approximations, and we only */ /* need less accurate initial bisection in DLARRE. */ /* Note: these settings do only affect the subset case and DLARRE */ rtol1 = sqrt(eps); /* Computing MAX */ d__1 = sqrt(eps) * .005; d__2 = eps * 4.; // , expr subst rtol2 = max(d__1,d__2); } dlarre_(range, n, &wl, &wu, &iil, &iiu, &d__[1], &e[1], &work[inde2], &rtol1, &rtol2, &thresh, &nsplit, &iwork[iinspl], m, &w[1], & work[inderr], &work[indgp], &iwork[iindbl], &iwork[iindw], & work[indgrs], &pivmin, &work[indwrk], &iwork[iindwk], &iinfo); if (iinfo != 0) { *info = f2c_abs(iinfo) + 10; return 0; } /* Note that if RANGE .NE. 'V', DLARRE computes bounds on the desired */ /* part of the spectrum. All desired eigenvalues are contained in */ /* (WL,WU] */ if (wantz) { /* Compute the desired eigenvectors corresponding to the computed */ /* eigenvalues */ zlarrv_(n, &wl, &wu, &d__[1], &e[1], &pivmin, &iwork[iinspl], m, & c__1, m, &c_b18, &rtol1, &rtol2, &w[1], &work[inderr], & work[indgp], &iwork[iindbl], &iwork[iindw], &work[indgrs], &z__[z_offset], ldz, &isuppz[1], &work[indwrk], &iwork[ iindwk], &iinfo); if (iinfo != 0) { *info = f2c_abs(iinfo) + 20; return 0; } } else { /* DLARRE computes eigenvalues of the (shifted) root representation */ /* ZLARRV returns the eigenvalues of the unshifted matrix. */ /* However, if the eigenvectors are not desired by the user, we need */ /* to apply the corresponding shifts from DLARRE to obtain the */ /* eigenvalues of the original matrix. */ i__1 = *m; for (j = 1; j <= i__1; ++j) { itmp = iwork[iindbl + j - 1]; w[j] += e[iwork[iinspl + itmp - 1]]; /* L20: */ } } if (*tryrac) { /* Refine computed eigenvalues so that they are relatively accurate */ /* with respect to the original matrix T. */ ibegin = 1; wbegin = 1; i__1 = iwork[iindbl + *m - 1]; for (jblk = 1; jblk <= i__1; ++jblk) { iend = iwork[iinspl + jblk - 1]; in = iend - ibegin + 1; wend = wbegin - 1; /* check if any eigenvalues have to be refined in this block */ L36: if (wend < *m) { if (iwork[iindbl + wend] == jblk) { ++wend; goto L36; } } if (wend < wbegin) { ibegin = iend + 1; goto L39; } offset = iwork[iindw + wbegin - 1] - 1; ifirst = iwork[iindw + wbegin - 1]; ilast = iwork[iindw + wend - 1]; rtol2 = eps * 4.; dlarrj_(&in, &work[indd + ibegin - 1], &work[inde2 + ibegin - 1], &ifirst, &ilast, &rtol2, &offset, &w[wbegin], & work[inderr + wbegin - 1], &work[indwrk], &iwork[ iindwk], &pivmin, &tnrm, &iinfo); ibegin = iend + 1; wbegin = wend + 1; L39: ; } } /* If matrix was scaled, then rescale eigenvalues appropriately. */ if (scale != 1.) { d__1 = 1. / scale; dscal_(m, &d__1, &w[1], &c__1); } } /* If eigenvalues are not in increasing order, then sort them, */ /* possibly along with eigenvectors. */ if (nsplit > 1 || *n == 2) { if (! wantz) { dlasrt_("I", m, &w[1], &iinfo); if (iinfo != 0) { *info = 3; return 0; } } else { i__1 = *m - 1; for (j = 1; j <= i__1; ++j) { i__ = 0; tmp = w[j]; i__2 = *m; for (jj = j + 1; jj <= i__2; ++jj) { if (w[jj] < tmp) { i__ = jj; tmp = w[jj]; } /* L50: */ } if (i__ != 0) { w[i__] = w[j]; w[j] = tmp; if (wantz) { zswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[j * z_dim1 + 1], &c__1); itmp = isuppz[(i__ << 1) - 1]; isuppz[(i__ << 1) - 1] = isuppz[(j << 1) - 1]; isuppz[(j << 1) - 1] = itmp; itmp = isuppz[i__ * 2]; isuppz[i__ * 2] = isuppz[j * 2]; isuppz[j * 2] = itmp; } } /* L60: */ } } } work[1] = (doublereal) lwmin; iwork[1] = liwmin; return 0; /* End of ZSTEMR */ }
/* Subroutine */ int zsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublecomplex *z__, integer *ldz, doublereal *work, integer *info) { /* System generated locals */ integer z_dim1, z_offset, i__1, i__2; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal), d_sign(doublereal *, doublereal *); /* Local variables */ doublereal b, c__, f, g; integer i__, j, k, l, m; doublereal p, r__, s; integer l1, ii, mm, lm1, mm1, nm1; doublereal rt1, rt2, eps; integer lsv; doublereal tst, eps2; integer lend, jtot; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); extern logical lsame_(char *, char *); doublereal anorm; extern /* Subroutine */ int zlasr_(char *, char *, char *, integer *, integer *, doublereal *, doublereal *, doublecomplex *, integer *), zswap_(integer *, doublecomplex *, integer *, doublecomplex *, integer *), dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); integer lendm1, lendp1; extern doublereal dlapy2_(doublereal *, doublereal *), dlamch_(char *); integer iscale; extern /* Subroutine */ int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *); doublereal safmin; extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal safmax; extern /* Subroutine */ int xerbla_(char *, integer *); extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, integer *); integer lendsv; doublereal ssfmin; integer nmaxit, icompz; doublereal ssfmax; extern /* Subroutine */ int zlaset_(char *, integer *, integer *, doublecomplex *, doublecomplex *, doublecomplex *, integer *); /* -- LAPACK computational routine (version 3.4.0) -- */ /* -- LAPACK is a software package provided by Univ. of Tennessee, -- */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ /* November 2011 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* ===================================================================== */ /* .. Parameters .. */ /* .. */ /* .. Local Scalars .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Intrinsic Functions .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ --d__; --e; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --work; /* Function Body */ *info = 0; 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) { i__1 = -(*info); xerbla_("ZSTEQR", &i__1); return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { if (icompz == 2) { i__1 = z_dim1 + 1; z__[i__1].r = 1.; z__[i__1].i = 0.; // , expr subst } return 0; } /* Determine the unit roundoff and over/underflow thresholds. */ eps = dlamch_("E"); /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; safmin = dlamch_("S"); safmax = 1. / safmin; ssfmax = sqrt(safmax) / 3.; ssfmin = sqrt(safmin) / eps2; /* Compute the eigenvalues and eigenvectors of the tridiagonal */ /* matrix. */ if (icompz == 2) { zlaset_("Full", n, n, &c_b1, &c_b2, &z__[z_offset], ldz); } nmaxit = *n * 30; jtot = 0; /* Determine where the matrix splits and choose QL or QR iteration */ /* for each block, according to whether top or bottom diagonal */ /* element is smaller. */ l1 = 1; nm1 = *n - 1; L10: if (l1 > *n) { goto L160; } if (l1 > 1) { e[l1 - 1] = 0.; } if (l1 <= nm1) { i__1 = nm1; for (m = l1; m <= i__1; ++m) { tst = (d__1 = e[m], f2c_abs(d__1)); if (tst == 0.) { goto L30; } if (tst <= sqrt((d__1 = d__[m], f2c_abs(d__1))) * sqrt((d__2 = d__[m + 1], f2c_abs(d__2))) * eps) { e[m] = 0.; goto L30; } /* L20: */ } } m = *n; L30: l = l1; lsv = l; lend = m; lendsv = lend; l1 = m + 1; if (lend == l) { goto L10; } /* Scale submatrix in rows and columns L to LEND */ i__1 = lend - l + 1; anorm = dlanst_("I", &i__1, &d__[l], &e[l]); iscale = 0; if (anorm == 0.) { goto L10; } if (anorm > ssfmax) { iscale = 1; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, info); } else if (anorm < ssfmin) { iscale = 2; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, info); } /* Choose between QL and QR iteration */ if ((d__1 = d__[lend], f2c_abs(d__1)) < (d__2 = d__[l], f2c_abs(d__2))) { lend = lsv; l = lendsv; } if (lend > l) { /* QL Iteration */ /* Look for small subdiagonal element. */ L40: if (l != lend) { lendm1 = lend - 1; i__1 = lendm1; for (m = l; m <= i__1; ++m) { /* Computing 2nd power */ d__2 = (d__1 = e[m], f2c_abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = d__[m], f2c_abs(d__1)) * (d__2 = d__[m + 1], f2c_abs(d__2)) + safmin) { goto L60; } /* L50: */ } } m = lend; L60: if (m < lend) { e[m] = 0.; } p = d__[l]; if (m == l) { goto L80; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 */ /* to compute its eigensystem. */ if (m == l + 1) { if (icompz > 0) { dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); work[l] = c__; work[*n - 1 + l] = s; zlasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], & z__[l * z_dim1 + 1], ldz); } else { dlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); } d__[l] = rt1; d__[l + 1] = rt2; e[l] = 0.; l += 2; if (l <= lend) { goto L40; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* Form shift. */ g = (d__[l + 1] - p) / (e[l] * 2.); r__ = dlapy2_(&g, &c_b41); g = d__[m] - p + e[l] / (g + d_sign(&r__, &g)); s = 1.; c__ = 1.; p = 0.; /* Inner loop */ mm1 = m - 1; i__1 = l; for (i__ = mm1; i__ >= i__1; --i__) { f = s * e[i__]; b = c__ * e[i__]; dlartg_(&g, &f, &c__, &s, &r__); if (i__ != m - 1) { e[i__ + 1] = r__; } g = d__[i__ + 1] - p; r__ = (d__[i__] - g) * s + c__ * 2. * b; p = s * r__; d__[i__ + 1] = g + p; g = c__ * r__ - b; /* If eigenvectors are desired, then save rotations. */ if (icompz > 0) { work[i__] = c__; work[*n - 1 + i__] = -s; } /* L70: */ } /* If eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = m - l + 1; zlasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l * z_dim1 + 1], ldz); } d__[l] -= p; e[l] = g; goto L40; /* Eigenvalue found. */ L80: d__[l] = p; ++l; if (l <= lend) { goto L40; } goto L140; } else { /* QR Iteration */ /* Look for small superdiagonal element. */ L90: if (l != lend) { lendp1 = lend + 1; i__1 = lendp1; for (m = l; m >= i__1; --m) { /* Computing 2nd power */ d__2 = (d__1 = e[m - 1], f2c_abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = d__[m], f2c_abs(d__1)) * (d__2 = d__[m - 1], f2c_abs(d__2)) + safmin) { goto L110; } /* L100: */ } } m = lend; L110: if (m > lend) { e[m - 1] = 0.; } p = d__[l]; if (m == l) { goto L130; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 */ /* to compute its eigensystem. */ if (m == l - 1) { if (icompz > 0) { dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) ; work[m] = c__; work[*n - 1 + m] = s; zlasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], & z__[(l - 1) * z_dim1 + 1], ldz); } else { dlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); } d__[l - 1] = rt1; d__[l] = rt2; e[l - 1] = 0.; l += -2; if (l >= lend) { goto L90; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* Form shift. */ g = (d__[l - 1] - p) / (e[l - 1] * 2.); r__ = dlapy2_(&g, &c_b41); g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g)); s = 1.; c__ = 1.; p = 0.; /* Inner loop */ lm1 = l - 1; i__1 = lm1; for (i__ = m; i__ <= i__1; ++i__) { f = s * e[i__]; b = c__ * e[i__]; dlartg_(&g, &f, &c__, &s, &r__); if (i__ != m) { e[i__ - 1] = r__; } g = d__[i__] - p; r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b; p = s * r__; d__[i__] = g + p; g = c__ * r__ - b; /* If eigenvectors are desired, then save rotations. */ if (icompz > 0) { work[i__] = c__; work[*n - 1 + i__] = s; } /* L120: */ } /* If eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = l - m + 1; zlasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m * z_dim1 + 1], ldz); } d__[l] -= p; e[lm1] = g; goto L90; /* Eigenvalue found. */ L130: d__[l] = p; --l; if (l >= lend) { goto L90; } goto L140; } /* Undo scaling if necessary */ L140: if (iscale == 1) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], n, info); i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, info); } else if (iscale == 2) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], n, info); i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, info); } /* Check for no convergence to an eigenvalue after a total */ /* of N*MAXIT iterations. */ if (jtot == nmaxit) { i__1 = *n - 1; for (i__ = 1; i__ <= i__1; ++i__) { if (e[i__] != 0.) { ++(*info); } /* L150: */ } return 0; } goto L10; /* Order eigenvalues and eigenvectors. */ L160: if (icompz == 0) { /* Use Quick Sort */ dlasrt_("I", n, &d__[1], info); } else { /* 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]; } /* L170: */ } if (k != i__) { d__[k] = d__[i__]; d__[i__] = p; zswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], &c__1); } /* L180: */ } } return 0; /* End of ZSTEQR */ }
/* Subroutine */ int zsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublecomplex *z__, integer *ldz, doublereal *work, integer *info) { /* System generated locals */ integer z_dim1, z_offset, i__1, i__2; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal), d_sign(doublereal *, doublereal *); /* Local variables */ doublereal b, c__, f, g; integer i__, j, k, l, m; doublereal p, r__, s; integer l1, ii, mm, lm1, mm1, nm1; doublereal rt1, rt2, eps; integer lsv; doublereal tst, eps2; integer lend, jtot; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); extern logical lsame_(char *, char *); doublereal anorm; extern /* Subroutine */ int zlasr_(char *, char *, char *, integer *, integer *, doublereal *, doublereal *, doublecomplex *, integer *), zswap_(integer *, doublecomplex *, integer *, doublecomplex *, integer *), dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); integer lendm1, lendp1; extern doublereal dlapy2_(doublereal *, doublereal *), dlamch_(char *); integer iscale; extern /* Subroutine */ int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *); doublereal safmin; extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal safmax; extern /* Subroutine */ int xerbla_(char *, integer *); extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, integer *); integer lendsv; doublereal ssfmin; integer nmaxit, icompz; doublereal ssfmax; extern /* Subroutine */ int zlaset_(char *, integer *, integer *, doublecomplex *, doublecomplex *, doublecomplex *, integer *); /* -- LAPACK routine (version 3.2) -- */ /* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ /* November 2006 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* Purpose */ /* ======= */ /* ZSTEQR computes all eigenvalues and, optionally, eigenvectors of a */ /* symmetric tridiagonal matrix using the implicit QL or QR method. */ /* The eigenvectors of a full or band complex Hermitian matrix can also */ /* be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this */ /* matrix to tridiagonal form. */ /* Arguments */ /* ========= */ /* COMPZ (input) CHARACTER*1 */ /* = 'N': Compute eigenvalues only. */ /* = 'V': Compute eigenvalues and eigenvectors of the original */ /* Hermitian matrix. On entry, Z must contain the */ /* unitary matrix used to reduce the original matrix */ /* to tridiagonal form. */ /* = 'I': Compute eigenvalues and eigenvectors of the */ /* tridiagonal matrix. Z is initialized to the identity */ /* matrix. */ /* N (input) INTEGER */ /* The order of the matrix. N >= 0. */ /* D (input/output) DOUBLE PRECISION 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) DOUBLE PRECISION array, dimension (N-1) */ /* On entry, the (n-1) subdiagonal elements of the tridiagonal */ /* matrix. */ /* On exit, E has been destroyed. */ /* Z (input/output) COMPLEX*16 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, and if */ /* eigenvectors are desired, then LDZ >= max(1,N). */ /* WORK (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2)) */ /* If COMPZ = 'N', then WORK is not referenced. */ /* INFO (output) INTEGER */ /* = 0: successful exit */ /* < 0: if INFO = -i, the i-th argument had an illegal value */ /* > 0: the algorithm has failed to find all the eigenvalues in */ /* a total of 30*N iterations; if INFO = i, then i */ /* elements of E have not converged to zero; on exit, D */ /* and E contain the elements of a symmetric tridiagonal */ /* matrix which is unitarily similar to the original */ /* matrix. */ /* ===================================================================== */ /* .. Parameters .. */ /* .. */ /* .. Local Scalars .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Intrinsic Functions .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ --d__; --e; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --work; /* Function Body */ *info = 0; 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) { i__1 = -(*info); xerbla_("ZSTEQR", &i__1); return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { if (icompz == 2) { i__1 = z_dim1 + 1; z__[i__1].r = 1., z__[i__1].i = 0.; } return 0; } /* Determine the unit roundoff and over/underflow thresholds. */ eps = dlamch_("E"); /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; safmin = dlamch_("S"); safmax = 1. / safmin; ssfmax = sqrt(safmax) / 3.; ssfmin = sqrt(safmin) / eps2; /* Compute the eigenvalues and eigenvectors of the tridiagonal */ /* matrix. */ if (icompz == 2) { zlaset_("Full", n, n, &c_b1, &c_b2, &z__[z_offset], ldz); } nmaxit = *n * 30; jtot = 0; /* Determine where the matrix splits and choose QL or QR iteration */ /* for each block, according to whether top or bottom diagonal */ /* element is smaller. */ l1 = 1; nm1 = *n - 1; L10: if (l1 > *n) { goto L160; } if (l1 > 1) { e[l1 - 1] = 0.; } if (l1 <= nm1) { i__1 = nm1; for (m = l1; m <= i__1; ++m) { tst = (d__1 = e[m], abs(d__1)); if (tst == 0.) { goto L30; } if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m + 1], abs(d__2))) * eps) { e[m] = 0.; goto L30; } /* L20: */ } } m = *n; L30: l = l1; lsv = l; lend = m; lendsv = lend; l1 = m + 1; if (lend == l) { goto L10; } /* Scale submatrix in rows and columns L to LEND */ i__1 = lend - l + 1; anorm = dlanst_("I", &i__1, &d__[l], &e[l]); iscale = 0; if (anorm == 0.) { goto L10; } if (anorm > ssfmax) { iscale = 1; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, info); } else if (anorm < ssfmin) { iscale = 2; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, info); } /* Choose between QL and QR iteration */ if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { lend = lsv; l = lendsv; } if (lend > l) { /* QL Iteration */ /* Look for small subdiagonal element. */ L40: if (l != lend) { lendm1 = lend - 1; i__1 = lendm1; for (m = l; m <= i__1; ++m) { /* Computing 2nd power */ d__2 = (d__1 = e[m], abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + 1], abs(d__2)) + safmin) { goto L60; } /* L50: */ } } m = lend; L60: if (m < lend) { e[m] = 0.; } p = d__[l]; if (m == l) { goto L80; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 */ /* to compute its eigensystem. */ if (m == l + 1) { if (icompz > 0) { dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); work[l] = c__; work[*n - 1 + l] = s; zlasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], & z__[l * z_dim1 + 1], ldz); } else { dlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); } d__[l] = rt1; d__[l + 1] = rt2; e[l] = 0.; l += 2; if (l <= lend) { goto L40; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* Form shift. */ g = (d__[l + 1] - p) / (e[l] * 2.); r__ = dlapy2_(&g, &c_b41); g = d__[m] - p + e[l] / (g + d_sign(&r__, &g)); s = 1.; c__ = 1.; p = 0.; /* Inner loop */ mm1 = m - 1; i__1 = l; for (i__ = mm1; i__ >= i__1; --i__) { f = s * e[i__]; b = c__ * e[i__]; dlartg_(&g, &f, &c__, &s, &r__); if (i__ != m - 1) { e[i__ + 1] = r__; } g = d__[i__ + 1] - p; r__ = (d__[i__] - g) * s + c__ * 2. * b; p = s * r__; d__[i__ + 1] = g + p; g = c__ * r__ - b; /* If eigenvectors are desired, then save rotations. */ if (icompz > 0) { work[i__] = c__; work[*n - 1 + i__] = -s; } /* L70: */ } /* If eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = m - l + 1; zlasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l * z_dim1 + 1], ldz); } d__[l] -= p; e[l] = g; goto L40; /* Eigenvalue found. */ L80: d__[l] = p; ++l; if (l <= lend) { goto L40; } goto L140; } else { /* QR Iteration */ /* Look for small superdiagonal element. */ L90: if (l != lend) { lendp1 = lend + 1; i__1 = lendp1; for (m = l; m >= i__1; --m) { /* Computing 2nd power */ d__2 = (d__1 = e[m - 1], abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m - 1], abs(d__2)) + safmin) { goto L110; } /* L100: */ } } m = lend; L110: if (m > lend) { e[m - 1] = 0.; } p = d__[l]; if (m == l) { goto L130; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 */ /* to compute its eigensystem. */ if (m == l - 1) { if (icompz > 0) { dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) ; work[m] = c__; work[*n - 1 + m] = s; zlasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], & z__[(l - 1) * z_dim1 + 1], ldz); } else { dlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); } d__[l - 1] = rt1; d__[l] = rt2; e[l - 1] = 0.; l += -2; if (l >= lend) { goto L90; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* Form shift. */ g = (d__[l - 1] - p) / (e[l - 1] * 2.); r__ = dlapy2_(&g, &c_b41); g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g)); s = 1.; c__ = 1.; p = 0.; /* Inner loop */ lm1 = l - 1; i__1 = lm1; for (i__ = m; i__ <= i__1; ++i__) { f = s * e[i__]; b = c__ * e[i__]; dlartg_(&g, &f, &c__, &s, &r__); if (i__ != m) { e[i__ - 1] = r__; } g = d__[i__] - p; r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b; p = s * r__; d__[i__] = g + p; g = c__ * r__ - b; /* If eigenvectors are desired, then save rotations. */ if (icompz > 0) { work[i__] = c__; work[*n - 1 + i__] = s; } /* L120: */ } /* If eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = l - m + 1; zlasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m * z_dim1 + 1], ldz); } d__[l] -= p; e[lm1] = g; goto L90; /* Eigenvalue found. */ L130: d__[l] = p; --l; if (l >= lend) { goto L90; } goto L140; } /* Undo scaling if necessary */ L140: if (iscale == 1) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], n, info); i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, info); } else if (iscale == 2) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], n, info); i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, info); } /* Check for no convergence to an eigenvalue after a total */ /* of N*MAXIT iterations. */ if (jtot == nmaxit) { i__1 = *n - 1; for (i__ = 1; i__ <= i__1; ++i__) { if (e[i__] != 0.) { ++(*info); } /* L150: */ } return 0; } goto L10; /* Order eigenvalues and eigenvectors. */ L160: if (icompz == 0) { /* Use Quick Sort */ dlasrt_("I", n, &d__[1], info); } else { /* 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]; } /* L170: */ } if (k != i__) { d__[k] = d__[i__]; d__[i__] = p; zswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], &c__1); } /* L180: */ } } return 0; /* End of ZSTEQR */ } /* zsteqr_ */
/* Subroutine */ int dstemr_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, integer *m, doublereal *w, doublereal *z__, integer *ldz, integer *nzc, integer *isuppz, logical *tryrac, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info) { /* System generated locals */ integer z_dim1, z_offset, i__1, i__2; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal); /* Local variables */ integer i__, j; doublereal r1, r2; integer jj; doublereal cs; integer in; doublereal sn, wl, wu; integer iil, iiu; doublereal eps, tmp; integer indd, iend, jblk, wend; doublereal rmin, rmax; integer itmp; doublereal tnrm; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); integer inde2, itmp2; doublereal rtol1, rtol2; extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, integer *); doublereal scale; integer indgp; extern logical lsame_(char *, char *); integer iinfo, iindw, ilast; extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, doublereal *, integer *), dswap_(integer *, doublereal *, integer *, doublereal *, integer *); integer lwmin; logical wantz; extern /* Subroutine */ int dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); extern doublereal dlamch_(char *); logical alleig; integer ibegin; logical indeig; integer iindbl; logical valeig; extern /* Subroutine */ int dlarrc_(char *, integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, integer *, integer *), dlarre_(char *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, integer *); integer wbegin; doublereal safmin; extern /* Subroutine */ int dlarrj_(integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, doublereal *, doublereal *, doublereal *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); doublereal bignum; integer inderr, iindwk, indgrs, offset; extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); extern /* Subroutine */ int dlarrr_(integer *, doublereal *, doublereal *, integer *), dlarrv_(integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, integer *, integer *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *), dlasrt_(char *, integer *, doublereal *, integer *); doublereal thresh; integer iinspl, ifirst, indwrk, liwmin, nzcmin; doublereal pivmin; integer nsplit; doublereal smlnum; logical lquery, zquery; /* -- LAPACK computational routine (version 3.1) -- */ /* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ /* November 2006 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* Purpose */ /* ======= */ /* DSTEMR computes selected eigenvalues and, optionally, eigenvectors */ /* of a real symmetric tridiagonal matrix T. Any such unreduced matrix has */ /* a well defined set of pairwise different real eigenvalues, the corresponding */ /* real eigenvectors are pairwise orthogonal. */ /* The spectrum may be computed either completely or partially by specifying */ /* either an interval (VL,VU] or a range of indices IL:IU for the desired */ /* eigenvalues. */ /* Depending on the number of desired eigenvalues, these are computed either */ /* by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are */ /* computed by the use of various suitable L D L^T factorizations near clusters */ /* of close eigenvalues (referred to as RRRs, Relatively Robust */ /* Representations). An informal sketch of the algorithm follows. */ /* For each unreduced block (submatrix) of T, */ /* (a) Compute T - sigma I = L D L^T, so that L and D */ /* define all the wanted eigenvalues to high relative accuracy. */ /* This means that small relative changes in the entries of D and L */ /* cause only small relative changes in the eigenvalues and */ /* eigenvectors. The standard (unfactored) representation of the */ /* tridiagonal matrix T does not have this property in general. */ /* (b) Compute the eigenvalues to suitable accuracy. */ /* If the eigenvectors are desired, the algorithm attains full */ /* accuracy of the computed eigenvalues only right before */ /* the corresponding vectors have to be computed, see steps c) and d). */ /* (c) For each cluster of close eigenvalues, select a new */ /* shift close to the cluster, find a new factorization, and refine */ /* the shifted eigenvalues to suitable accuracy. */ /* (d) For each eigenvalue with a large enough relative separation compute */ /* the corresponding eigenvector by forming a rank revealing twisted */ /* factorization. Go back to (c) for any clusters that remain. */ /* For more details, see: */ /* - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations */ /* to compute orthogonal eigenvectors of symmetric tridiagonal matrices," */ /* Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004. */ /* - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and */ /* Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25, */ /* 2004. Also LAPACK Working Note 154. */ /* - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric */ /* tridiagonal eigenvalue/eigenvector problem", */ /* Computer Science Division Technical Report No. UCB/CSD-97-971, */ /* UC Berkeley, May 1997. */ /* Notes: */ /* 1.DSTEMR works only on machines which follow IEEE-754 */ /* floating-point standard in their handling of infinities and NaNs. */ /* This permits the use of efficient inner loops avoiding a check for */ /* zero divisors. */ /* Arguments */ /* ========= */ /* JOBZ (input) CHARACTER*1 */ /* = 'N': Compute eigenvalues only; */ /* = 'V': Compute eigenvalues and eigenvectors. */ /* RANGE (input) CHARACTER*1 */ /* = 'A': all eigenvalues will be found. */ /* = 'V': all eigenvalues in the half-open interval (VL,VU] */ /* will be found. */ /* = 'I': the IL-th through IU-th eigenvalues will be found. */ /* N (input) INTEGER */ /* The order of the matrix. N >= 0. */ /* D (input/output) DOUBLE PRECISION array, dimension (N) */ /* On entry, the N diagonal elements of the tridiagonal matrix */ /* T. On exit, D is overwritten. */ /* E (input/output) DOUBLE PRECISION array, dimension (N) */ /* On entry, the (N-1) subdiagonal elements of the tridiagonal */ /* matrix T in elements 1 to N-1 of E. E(N) need not be set on */ /* input, but is used internally as workspace. */ /* On exit, E is overwritten. */ /* VL (input) DOUBLE PRECISION */ /* VU (input) DOUBLE PRECISION */ /* If RANGE='V', the lower and upper bounds of the interval to */ /* be searched for eigenvalues. VL < VU. */ /* Not referenced if RANGE = 'A' or 'I'. */ /* IL (input) INTEGER */ /* IU (input) INTEGER */ /* If RANGE='I', the indices (in ascending order) of the */ /* smallest and largest eigenvalues to be returned. */ /* 1 <= IL <= IU <= N, if N > 0. */ /* Not referenced if RANGE = 'A' or 'V'. */ /* M (output) INTEGER */ /* The total number of eigenvalues found. 0 <= M <= N. */ /* If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1. */ /* W (output) DOUBLE PRECISION array, dimension (N) */ /* The first M elements contain the selected eigenvalues in */ /* ascending order. */ /* Z (output) DOUBLE PRECISION array, dimension (LDZ, max(1,M) ) */ /* If JOBZ = 'V', and if INFO = 0, then the first M columns of Z */ /* contain the orthonormal eigenvectors of the matrix T */ /* corresponding to the selected eigenvalues, with the i-th */ /* column of Z holding the eigenvector associated with W(i). */ /* If JOBZ = 'N', then Z is not referenced. */ /* Note: the user must ensure that at least max(1,M) columns are */ /* supplied in the array Z; if RANGE = 'V', the exact value of M */ /* is not known in advance and can be computed with a workspace */ /* query by setting NZC = -1, see below. */ /* LDZ (input) INTEGER */ /* The leading dimension of the array Z. LDZ >= 1, and if */ /* JOBZ = 'V', then LDZ >= max(1,N). */ /* NZC (input) INTEGER */ /* The number of eigenvectors to be held in the array Z. */ /* If RANGE = 'A', then NZC >= max(1,N). */ /* If RANGE = 'V', then NZC >= the number of eigenvalues in (VL,VU]. */ /* If RANGE = 'I', then NZC >= IU-IL+1. */ /* If NZC = -1, then a workspace query is assumed; the */ /* routine calculates the number of columns of the array Z that */ /* are needed to hold the eigenvectors. */ /* This value is returned as the first entry of the Z array, and */ /* no error message related to NZC is issued by XERBLA. */ /* ISUPPZ (output) INTEGER ARRAY, dimension ( 2*max(1,M) ) */ /* The support of the eigenvectors in Z, i.e., the indices */ /* indicating the nonzero elements in Z. The i-th computed eigenvector */ /* is nonzero only in elements ISUPPZ( 2*i-1 ) through */ /* ISUPPZ( 2*i ). This is relevant in the case when the matrix */ /* is split. ISUPPZ is only accessed when JOBZ is 'V' and N > 0. */ /* TRYRAC (input/output) LOGICAL */ /* If TRYRAC.EQ..TRUE., indicates that the code should check whether */ /* the tridiagonal matrix defines its eigenvalues to high relative */ /* accuracy. If so, the code uses relative-accuracy preserving */ /* algorithms that might be (a bit) slower depending on the matrix. */ /* If the matrix does not define its eigenvalues to high relative */ /* accuracy, the code can uses possibly faster algorithms. */ /* If TRYRAC.EQ..FALSE., the code is not required to guarantee */ /* relatively accurate eigenvalues and can use the fastest possible */ /* techniques. */ /* On exit, a .TRUE. TRYRAC will be set to .FALSE. if the matrix */ /* does not define its eigenvalues to high relative accuracy. */ /* WORK (workspace/output) DOUBLE PRECISION array, dimension (LWORK) */ /* On exit, if INFO = 0, WORK(1) returns the optimal */ /* (and minimal) LWORK. */ /* LWORK (input) INTEGER */ /* The dimension of the array WORK. LWORK >= max(1,18*N) */ /* if JOBZ = 'V', and LWORK >= max(1,12*N) if JOBZ = 'N'. */ /* 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. LIWORK >= max(1,10*N) */ /* if the eigenvectors are desired, and LIWORK >= max(1,8*N) */ /* if only the eigenvalues are to be computed. */ /* 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 */ /* On exit, INFO */ /* = 0: successful exit */ /* < 0: if INFO = -i, the i-th argument had an illegal value */ /* > 0: if INFO = 1X, internal error in DLARRE, */ /* if INFO = 2X, internal error in DLARRV. */ /* Here, the digit X = ABS( IINFO ) < 10, where IINFO is */ /* the nonzero error code returned by DLARRE or */ /* DLARRV, respectively. */ /* Further Details */ /* =============== */ /* Based on contributions by */ /* Beresford Parlett, University of California, Berkeley, USA */ /* Jim Demmel, University of California, Berkeley, USA */ /* Inderjit Dhillon, University of Texas, Austin, USA */ /* Osni Marques, LBNL/NERSC, USA */ /* Christof Voemel, University of California, Berkeley, USA */ /* ===================================================================== */ /* .. Parameters .. */ /* .. */ /* .. Local Scalars .. */ /* .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Intrinsic Functions .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ --d__; --e; --w; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --isuppz; --work; --iwork; /* Function Body */ wantz = lsame_(jobz, "V"); alleig = lsame_(range, "A"); valeig = lsame_(range, "V"); indeig = lsame_(range, "I"); lquery = *lwork == -1 || *liwork == -1; zquery = *nzc == -1; *tryrac = *info != 0; /* DSTEMR needs WORK of size 6*N, IWORK of size 3*N. */ /* In addition, DLARRE needs WORK of size 6*N, IWORK of size 5*N. */ /* Furthermore, DLARRV needs WORK of size 12*N, IWORK of size 7*N. */ if (wantz) { lwmin = *n * 18; liwmin = *n * 10; } else { /* need less workspace if only the eigenvalues are wanted */ lwmin = *n * 12; liwmin = *n << 3; } wl = 0.; wu = 0.; iil = 0; iiu = 0; if (valeig) { /* We do not reference VL, VU in the cases RANGE = 'I','A' */ /* The interval (WL, WU] contains all the wanted eigenvalues. */ /* It is either given by the user or computed in DLARRE. */ wl = *vl; wu = *vu; } else if (indeig) { /* We do not reference IL, IU in the cases RANGE = 'V','A' */ iil = *il; iiu = *iu; } *info = 0; if (! (wantz || lsame_(jobz, "N"))) { *info = -1; } else if (! (alleig || valeig || indeig)) { *info = -2; } else if (*n < 0) { *info = -3; } else if (valeig && *n > 0 && wu <= wl) { *info = -7; } else if (indeig && (iil < 1 || iil > *n)) { *info = -8; } else if (indeig && (iiu < iil || iiu > *n)) { *info = -9; } else if (*ldz < 1 || wantz && *ldz < *n) { *info = -13; } else if (*lwork < lwmin && ! lquery) { *info = -17; } else if (*liwork < liwmin && ! lquery) { *info = -19; } /* Get machine constants. */ safmin = dlamch_("Safe minimum"); eps = dlamch_("Precision"); smlnum = safmin / eps; bignum = 1. / smlnum; rmin = sqrt(smlnum); /* Computing MIN */ d__1 = sqrt(bignum), d__2 = 1. / sqrt(sqrt(safmin)); rmax = min(d__1,d__2); if (*info == 0) { work[1] = (doublereal) lwmin; iwork[1] = liwmin; if (wantz && alleig) { nzcmin = *n; } else if (wantz && valeig) { dlarrc_("T", n, vl, vu, &d__[1], &e[1], &safmin, &nzcmin, &itmp, & itmp2, info); } else if (wantz && indeig) { nzcmin = iiu - iil + 1; } else { /* WANTZ .EQ. FALSE. */ nzcmin = 0; } if (zquery && *info == 0) { z__[z_dim1 + 1] = (doublereal) nzcmin; } else if (*nzc < nzcmin && ! zquery) { *info = -14; } } if (*info != 0) { i__1 = -(*info); xerbla_("DSTEMR", &i__1); return 0; } else if (lquery || zquery) { return 0; } /* Handle N = 0, 1, and 2 cases immediately */ *m = 0; if (*n == 0) { return 0; } if (*n == 1) { if (alleig || indeig) { *m = 1; w[1] = d__[1]; } else { if (wl < d__[1] && wu >= d__[1]) { *m = 1; w[1] = d__[1]; } } if (wantz && ! zquery) { z__[z_dim1 + 1] = 1.; isuppz[1] = 1; isuppz[2] = 1; } return 0; } if (*n == 2) { if (! wantz) { dlae2_(&d__[1], &e[1], &d__[2], &r1, &r2); } else if (wantz && ! zquery) { dlaev2_(&d__[1], &e[1], &d__[2], &r1, &r2, &cs, &sn); } if (alleig || valeig && r2 > wl && r2 <= wu || indeig && iil == 1) { ++(*m); w[*m] = r2; if (wantz && ! zquery) { z__[*m * z_dim1 + 1] = -sn; z__[*m * z_dim1 + 2] = cs; /* Note: At most one of SN and CS can be zero. */ if (sn != 0.) { if (cs != 0.) { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 2; } else { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 1; } } else { isuppz[(*m << 1) - 1] = 2; isuppz[*m * 2] = 2; } } } if (alleig || valeig && r1 > wl && r1 <= wu || indeig && iiu == 2) { ++(*m); w[*m] = r1; if (wantz && ! zquery) { z__[*m * z_dim1 + 1] = cs; z__[*m * z_dim1 + 2] = sn; /* Note: At most one of SN and CS can be zero. */ if (sn != 0.) { if (cs != 0.) { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 2; } else { isuppz[(*m << 1) - 1] = 1; isuppz[(*m << 1) - 1] = 1; } } else { isuppz[(*m << 1) - 1] = 2; isuppz[*m * 2] = 2; } } } return 0; } /* Continue with general N */ indgrs = 1; inderr = (*n << 1) + 1; indgp = *n * 3 + 1; indd = (*n << 2) + 1; inde2 = *n * 5 + 1; indwrk = *n * 6 + 1; iinspl = 1; iindbl = *n + 1; iindw = (*n << 1) + 1; iindwk = *n * 3 + 1; /* Scale matrix to allowable range, if necessary. */ /* The allowable range is related to the PIVMIN parameter; see the */ /* comments in DLARRD. The preference for scaling small values */ /* up is heuristic; we expect users' matrices not to be close to the */ /* RMAX threshold. */ scale = 1.; tnrm = dlanst_("M", n, &d__[1], &e[1]); if (tnrm > 0. && tnrm < rmin) { scale = rmin / tnrm; } else if (tnrm > rmax) { scale = rmax / tnrm; } if (scale != 1.) { dscal_(n, &scale, &d__[1], &c__1); i__1 = *n - 1; dscal_(&i__1, &scale, &e[1], &c__1); tnrm *= scale; if (valeig) { /* If eigenvalues in interval have to be found, */ /* scale (WL, WU] accordingly */ wl *= scale; wu *= scale; } } /* Compute the desired eigenvalues of the tridiagonal after splitting */ /* into smaller subblocks if the corresponding off-diagonal elements */ /* are small */ /* THRESH is the splitting parameter for DLARRE */ /* A negative THRESH forces the old splitting criterion based on the */ /* size of the off-diagonal. A positive THRESH switches to splitting */ /* which preserves relative accuracy. */ if (*tryrac) { /* Test whether the matrix warrants the more expensive relative approach. */ dlarrr_(n, &d__[1], &e[1], &iinfo); } else { /* The user does not care about relative accurately eigenvalues */ iinfo = -1; } /* Set the splitting criterion */ if (iinfo == 0) { thresh = eps; } else { thresh = -eps; /* relative accuracy is desired but T does not guarantee it */ *tryrac = FALSE_; } if (*tryrac) { /* Copy original diagonal, needed to guarantee relative accuracy */ dcopy_(n, &d__[1], &c__1, &work[indd], &c__1); } /* Store the squares of the offdiagonal values of T */ i__1 = *n - 1; for (j = 1; j <= i__1; ++j) { /* Computing 2nd power */ d__1 = e[j]; work[inde2 + j - 1] = d__1 * d__1; /* L5: */ } /* Set the tolerance parameters for bisection */ if (! wantz) { /* DLARRE computes the eigenvalues to full precision. */ rtol1 = eps * 4.; rtol2 = eps * 4.; } else { /* DLARRE computes the eigenvalues to less than full precision. */ /* DLARRV will refine the eigenvalue approximations, and we can */ /* need less accurate initial bisection in DLARRE. */ /* Note: these settings do only affect the subset case and DLARRE */ rtol1 = sqrt(eps); /* Computing MAX */ d__1 = sqrt(eps) * .005, d__2 = eps * 4.; rtol2 = max(d__1,d__2); } dlarre_(range, n, &wl, &wu, &iil, &iiu, &d__[1], &e[1], &work[inde2], & rtol1, &rtol2, &thresh, &nsplit, &iwork[iinspl], m, &w[1], &work[ inderr], &work[indgp], &iwork[iindbl], &iwork[iindw], &work[ indgrs], &pivmin, &work[indwrk], &iwork[iindwk], &iinfo); if (iinfo != 0) { *info = abs(iinfo) + 10; return 0; } /* Note that if RANGE .NE. 'V', DLARRE computes bounds on the desired */ /* part of the spectrum. All desired eigenvalues are contained in */ /* (WL,WU] */ if (wantz) { /* Compute the desired eigenvectors corresponding to the computed */ /* eigenvalues */ dlarrv_(n, &wl, &wu, &d__[1], &e[1], &pivmin, &iwork[iinspl], m, & c__1, m, &c_b18, &rtol1, &rtol2, &w[1], &work[inderr], &work[ indgp], &iwork[iindbl], &iwork[iindw], &work[indgrs], &z__[ z_offset], ldz, &isuppz[1], &work[indwrk], &iwork[iindwk], & iinfo); if (iinfo != 0) { *info = abs(iinfo) + 20; return 0; } } else { /* DLARRE computes eigenvalues of the (shifted) root representation */ /* DLARRV returns the eigenvalues of the unshifted matrix. */ /* However, if the eigenvectors are not desired by the user, we need */ /* to apply the corresponding shifts from DLARRE to obtain the */ /* eigenvalues of the original matrix. */ i__1 = *m; for (j = 1; j <= i__1; ++j) { itmp = iwork[iindbl + j - 1]; w[j] += e[iwork[iinspl + itmp - 1]]; /* L20: */ } } if (*tryrac) { /* Refine computed eigenvalues so that they are relatively accurate */ /* with respect to the original matrix T. */ ibegin = 1; wbegin = 1; i__1 = iwork[iindbl + *m - 1]; for (jblk = 1; jblk <= i__1; ++jblk) { iend = iwork[iinspl + jblk - 1]; in = iend - ibegin + 1; wend = wbegin - 1; /* check if any eigenvalues have to be refined in this block */ L36: if (wend < *m) { if (iwork[iindbl + wend] == jblk) { ++wend; goto L36; } } if (wend < wbegin) { ibegin = iend + 1; goto L39; } offset = iwork[iindw + wbegin - 1] - 1; ifirst = iwork[iindw + wbegin - 1]; ilast = iwork[iindw + wend - 1]; rtol2 = eps * 4.; dlarrj_(&in, &work[indd + ibegin - 1], &work[inde2 + ibegin - 1], &ifirst, &ilast, &rtol2, &offset, &w[wbegin], &work[ inderr + wbegin - 1], &work[indwrk], &iwork[iindwk], & pivmin, &tnrm, &iinfo); ibegin = iend + 1; wbegin = wend + 1; L39: ; } } /* If matrix was scaled, then rescale eigenvalues appropriately. */ if (scale != 1.) { d__1 = 1. / scale; dscal_(m, &d__1, &w[1], &c__1); } /* If eigenvalues are not in increasing order, then sort them, */ /* possibly along with eigenvectors. */ if (nsplit > 1) { if (! wantz) { dlasrt_("I", m, &w[1], &iinfo); if (iinfo != 0) { *info = 3; return 0; } } else { i__1 = *m - 1; for (j = 1; j <= i__1; ++j) { i__ = 0; tmp = w[j]; i__2 = *m; for (jj = j + 1; jj <= i__2; ++jj) { if (w[jj] < tmp) { i__ = jj; tmp = w[jj]; } /* L50: */ } if (i__ != 0) { w[i__] = w[j]; w[j] = tmp; if (wantz) { dswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[j * z_dim1 + 1], &c__1); itmp = isuppz[(i__ << 1) - 1]; isuppz[(i__ << 1) - 1] = isuppz[(j << 1) - 1]; isuppz[(j << 1) - 1] = itmp; itmp = isuppz[i__ * 2]; isuppz[i__ * 2] = isuppz[j * 2]; isuppz[j * 2] = itmp; } } /* L60: */ } } } work[1] = (doublereal) lwmin; iwork[1] = liwmin; return 0; /* End of DSTEMR */ } /* dstemr_ */
/*< subroutine dstqrb ( n, d, e, z, work, info ) >*/ /* Subroutine */ int dstqrb_(integer *n, doublereal *d__, doublereal *e, doublereal *z__, doublereal *work, integer *info) { /* System generated locals */ integer i__1, i__2; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal), d_sign(doublereal *, doublereal *); /* Local variables */ doublereal b, c__, f, g; integer i__, j, k, l, m; doublereal p, r__, s; integer l1, ii, mm, lm1, mm1, nm1; doublereal rt1, rt2, eps; integer lsv; doublereal tst, eps2; integer lend, jtot; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *), dlasr_(char *, char *, char *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, ftnlen, ftnlen, ftnlen); doublereal anorm; extern /* Subroutine */ int dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); integer lendm1, lendp1; extern doublereal dlapy2_(doublereal *, doublereal *), dlamch_(char *, ftnlen); integer iscale; extern /* Subroutine */ int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *, ftnlen); doublereal safmin; extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal safmax; extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *, ftnlen); extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, integer *, ftnlen); integer lendsv, nmaxit, icompz; doublereal ssfmax, ssfmin; /* %------------------% */ /* | Scalar Arguments | */ /* %------------------% */ /*< integer info, n >*/ /* %-----------------% */ /* | Array Arguments | */ /* %-----------------% */ /*< >*/ /* .. parameters .. */ /*< >*/ /*< >*/ /*< integer maxit >*/ /*< parameter ( maxit = 30 ) >*/ /* .. */ /* .. local scalars .. */ /*< >*/ /*< >*/ /* .. */ /* .. external functions .. */ /*< logical lsame >*/ /*< >*/ /*< external lsame, dlamch, dlanst, dlapy2 >*/ /* .. */ /* .. external subroutines .. */ /*< >*/ /* .. */ /* .. intrinsic functions .. */ /*< intrinsic abs, max, sign, sqrt >*/ /* .. */ /* .. executable statements .. */ /* test the input parameters. */ /*< info = 0 >*/ /* Parameter adjustments */ --work; --z__; --e; --d__; /* Function Body */ *info = 0; /* $$$ IF( LSAME( COMPZ, 'N' ) ) THEN */ /* $$$ ICOMPZ = 0 */ /* $$$ ELSE IF( LSAME( COMPZ, 'V' ) ) THEN */ /* $$$ ICOMPZ = 1 */ /* $$$ ELSE IF( LSAME( COMPZ, 'I' ) ) THEN */ /* $$$ ICOMPZ = 2 */ /* $$$ ELSE */ /* $$$ ICOMPZ = -1 */ /* $$$ END IF */ /* $$$ IF( ICOMPZ.LT.0 ) THEN */ /* $$$ INFO = -1 */ /* $$$ ELSE IF( N.LT.0 ) THEN */ /* $$$ INFO = -2 */ /* $$$ ELSE IF( ( LDZ.LT.1 ) .OR. ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX( 1, */ /* $$$ $ N ) ) ) THEN */ /* $$$ INFO = -6 */ /* $$$ END IF */ /* $$$ IF( INFO.NE.0 ) THEN */ /* $$$ CALL XERBLA( 'SSTEQR', -INFO ) */ /* $$$ RETURN */ /* $$$ END IF */ /* *** New starting with version 2.5 *** */ /*< icompz = 2 >*/ icompz = 2; /* ************************************* */ /* quick return if possible */ /*< >*/ if (*n == 0) { return 0; } /*< if( n.eq.1 ) then >*/ if (*n == 1) { /*< if( icompz.eq.2 ) z( 1 ) = one >*/ if (icompz == 2) { z__[1] = 1.; } /*< return >*/ return 0; /*< end if >*/ } /* determine the unit roundoff and over/underflow thresholds. */ /*< eps = dlamch( 'e' ) >*/ eps = dlamch_("e", (ftnlen)1); /*< eps2 = eps**2 >*/ /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; /*< safmin = dlamch( 's' ) >*/ safmin = dlamch_("s", (ftnlen)1); /*< safmax = one / safmin >*/ safmax = 1. / safmin; /*< ssfmax = sqrt( safmax ) / three >*/ ssfmax = sqrt(safmax) / 3.; /*< ssfmin = sqrt( safmin ) / eps2 >*/ ssfmin = sqrt(safmin) / eps2; /* compute the eigenvalues and eigenvectors of the tridiagonal */ /* matrix. */ /* $$ if( icompz.eq.2 ) */ /* $$$ $ call dlaset( 'full', n, n, zero, one, z, ldz ) */ /* *** New starting with version 2.5 *** */ /*< if ( icompz .eq. 2 ) then >*/ if (icompz == 2) { /*< do 5 j = 1, n-1 >*/ i__1 = *n - 1; for (j = 1; j <= i__1; ++j) { /*< z(j) = zero >*/ z__[j] = 0.; /*< 5 continue >*/ /* L5: */ } /*< z( n ) = one >*/ z__[*n] = 1.; /*< end if >*/ } /* ************************************* */ /*< nmaxit = n*maxit >*/ nmaxit = *n * 30; /*< jtot = 0 >*/ jtot = 0; /* determine where the matrix splits and choose ql or qr iteration */ /* for each block, according to whether top or bottom diagonal */ /* element is smaller. */ /*< l1 = 1 >*/ l1 = 1; /*< nm1 = n - 1 >*/ nm1 = *n - 1; /*< 10 continue >*/ L10: /*< >*/ if (l1 > *n) { goto L160; } /*< >*/ if (l1 > 1) { e[l1 - 1] = 0.; } /*< if( l1.le.nm1 ) then >*/ if (l1 <= nm1) { /*< do 20 m = l1, nm1 >*/ i__1 = nm1; for (m = l1; m <= i__1; ++m) { /*< tst = abs( e( m ) ) >*/ tst = (d__1 = e[m], abs(d__1)); /*< >*/ if (tst == 0.) { goto L30; } /*< >*/ if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m + 1], abs(d__2))) * eps) { /*< e( m ) = zero >*/ e[m] = 0.; /*< go to 30 >*/ goto L30; /*< end if >*/ } /*< 20 continue >*/ /* L20: */ } /*< end if >*/ } /*< m = n >*/ m = *n; /*< 30 continue >*/ L30: /*< l = l1 >*/ l = l1; /*< lsv = l >*/ lsv = l; /*< lend = m >*/ lend = m; /*< lendsv = lend >*/ lendsv = lend; /*< l1 = m + 1 >*/ l1 = m + 1; /*< >*/ if (lend == l) { goto L10; } /* scale submatrix in rows and columns l to lend */ /*< anorm = dlanst( 'i', lend-l+1, d( l ), e( l ) ) >*/ i__1 = lend - l + 1; anorm = dlanst_("i", &i__1, &d__[l], &e[l], (ftnlen)1); /*< iscale = 0 >*/ iscale = 0; /*< >*/ if (anorm == 0.) { goto L10; } /*< if( anorm.gt.ssfmax ) then >*/ if (anorm > ssfmax) { /*< iscale = 1 >*/ iscale = 1; /*< >*/ i__1 = lend - l + 1; dlascl_("g", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, info, (ftnlen)1); /*< >*/ i__1 = lend - l; dlascl_("g", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, info, (ftnlen)1); /*< else if( anorm.lt.ssfmin ) then >*/ } else if (anorm < ssfmin) { /*< iscale = 2 >*/ iscale = 2; /*< >*/ i__1 = lend - l + 1; dlascl_("g", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, info, (ftnlen)1); /*< >*/ i__1 = lend - l; dlascl_("g", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, info, (ftnlen)1); /*< end if >*/ } /* choose between ql and qr iteration */ /*< if( abs( d( lend ) ).lt.abs( d( l ) ) ) then >*/ if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { /*< lend = lsv >*/ lend = lsv; /*< l = lendsv >*/ l = lendsv; /*< end if >*/ } /*< if( lend.gt.l ) then >*/ if (lend > l) { /* ql iteration */ /* look for small subdiagonal element. */ /*< 40 continue >*/ L40: /*< if( l.ne.lend ) then >*/ if (l != lend) { /*< lendm1 = lend - 1 >*/ lendm1 = lend - 1; /*< do 50 m = l, lendm1 >*/ i__1 = lendm1; for (m = l; m <= i__1; ++m) { /*< tst = abs( e( m ) )**2 >*/ /* Computing 2nd power */ d__2 = (d__1 = e[m], abs(d__1)); tst = d__2 * d__2; /*< >*/ if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + 1], abs(d__2)) + safmin) { goto L60; } /*< 50 continue >*/ /* L50: */ } /*< end if >*/ } /*< m = lend >*/ m = lend; /*< 60 continue >*/ L60: /*< >*/ if (m < lend) { e[m] = 0.; } /*< p = d( l ) >*/ p = d__[l]; /*< >*/ if (m == l) { goto L80; } /* if remaining matrix is 2-by-2, use dlae2 or dlaev2 */ /* to compute its eigensystem. */ /*< if( m.eq.l+1 ) then >*/ if (m == l + 1) { /*< if( icompz.gt.0 ) then >*/ if (icompz > 0) { /*< call dlaev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s ) >*/ dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); /*< work( l ) = c >*/ work[l] = c__; /*< work( n-1+l ) = s >*/ work[*n - 1 + l] = s; /* $$$ call dlasr( 'r', 'v', 'b', n, 2, work( l ), */ /* $$$ $ work( n-1+l ), z( 1, l ), ldz ) */ /* *** New starting with version 2.5 *** */ /*< tst = z(l+1) >*/ tst = z__[l + 1]; /*< z(l+1) = c*tst - s*z(l) >*/ z__[l + 1] = c__ * tst - s * z__[l]; /*< z(l) = s*tst + c*z(l) >*/ z__[l] = s * tst + c__ * z__[l]; /* ************************************* */ /*< else >*/ } else { /*< call dlae2( d( l ), e( l ), d( l+1 ), rt1, rt2 ) >*/ dlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); /*< end if >*/ } /*< d( l ) = rt1 >*/ d__[l] = rt1; /*< d( l+1 ) = rt2 >*/ d__[l + 1] = rt2; /*< e( l ) = zero >*/ e[l] = 0.; /*< l = l + 2 >*/ l += 2; /*< >*/ if (l <= lend) { goto L40; } /*< go to 140 >*/ goto L140; /*< end if >*/ } /*< >*/ if (jtot == nmaxit) { goto L140; } /*< jtot = jtot + 1 >*/ ++jtot; /* form shift. */ /*< g = ( d( l+1 )-p ) / ( two*e( l ) ) >*/ g = (d__[l + 1] - p) / (e[l] * 2.); /*< r = dlapy2( g, one ) >*/ r__ = dlapy2_(&g, &c_b31); /*< g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) ) >*/ g = d__[m] - p + e[l] / (g + d_sign(&r__, &g)); /*< s = one >*/ s = 1.; /*< c = one >*/ c__ = 1.; /*< p = zero >*/ p = 0.; /* inner loop */ /*< mm1 = m - 1 >*/ mm1 = m - 1; /*< do 70 i = mm1, l, -1 >*/ i__1 = l; for (i__ = mm1; i__ >= i__1; --i__) { /*< f = s*e( i ) >*/ f = s * e[i__]; /*< b = c*e( i ) >*/ b = c__ * e[i__]; /*< call dlartg( g, f, c, s, r ) >*/ dlartg_(&g, &f, &c__, &s, &r__); /*< >*/ if (i__ != m - 1) { e[i__ + 1] = r__; } /*< g = d( i+1 ) - p >*/ g = d__[i__ + 1] - p; /*< r = ( d( i )-g )*s + two*c*b >*/ r__ = (d__[i__] - g) * s + c__ * 2. * b; /*< p = s*r >*/ p = s * r__; /*< d( i+1 ) = g + p >*/ d__[i__ + 1] = g + p; /*< g = c*r - b >*/ g = c__ * r__ - b; /* if eigenvectors are desired, then save rotations. */ /*< if( icompz.gt.0 ) then >*/ if (icompz > 0) { /*< work( i ) = c >*/ work[i__] = c__; /*< work( n-1+i ) = -s >*/ work[*n - 1 + i__] = -s; /*< end if >*/ } /*< 70 continue >*/ /* L70: */ } /* if eigenvectors are desired, then apply saved rotations. */ /*< if( icompz.gt.0 ) then >*/ if (icompz > 0) { /*< mm = m - l + 1 >*/ mm = m - l + 1; /* $$$ call dlasr( 'r', 'v', 'b', n, mm, work( l ), work( n-1+l ), */ /* $$$ $ z( 1, l ), ldz ) */ /* *** New starting with version 2.5 *** */ /*< >*/ dlasr_("r", "v", "b", &c__1, &mm, &work[l], &work[*n - 1 + l], & z__[l], &c__1, (ftnlen)1, (ftnlen)1, (ftnlen)1); /* ************************************* */ /*< end if >*/ } /*< d( l ) = d( l ) - p >*/ d__[l] -= p; /*< e( l ) = g >*/ e[l] = g; /*< go to 40 >*/ goto L40; /* eigenvalue found. */ /*< 80 continue >*/ L80: /*< d( l ) = p >*/ d__[l] = p; /*< l = l + 1 >*/ ++l; /*< >*/ if (l <= lend) { goto L40; } /*< go to 140 >*/ goto L140; /*< else >*/ } else { /* qr iteration */ /* look for small superdiagonal element. */ /*< 90 continue >*/ L90: /*< if( l.ne.lend ) then >*/ if (l != lend) { /*< lendp1 = lend + 1 >*/ lendp1 = lend + 1; /*< do 100 m = l, lendp1, -1 >*/ i__1 = lendp1; for (m = l; m >= i__1; --m) { /*< tst = abs( e( m-1 ) )**2 >*/ /* Computing 2nd power */ d__2 = (d__1 = e[m - 1], abs(d__1)); tst = d__2 * d__2; /*< >*/ if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m - 1], abs(d__2)) + safmin) { goto L110; } /*< 100 continue >*/ /* L100: */ } /*< end if >*/ } /*< m = lend >*/ m = lend; /*< 110 continue >*/ L110: /*< >*/ if (m > lend) { e[m - 1] = 0.; } /*< p = d( l ) >*/ p = d__[l]; /*< >*/ if (m == l) { goto L130; } /* if remaining matrix is 2-by-2, use dlae2 or dlaev2 */ /* to compute its eigensystem. */ /*< if( m.eq.l-1 ) then >*/ if (m == l - 1) { /*< if( icompz.gt.0 ) then >*/ if (icompz > 0) { /*< call dlaev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s ) >*/ dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) ; /* $$$ work( m ) = c */ /* $$$ work( n-1+m ) = s */ /* $$$ call dlasr( 'r', 'v', 'f', n, 2, work( m ), */ /* $$$ $ work( n-1+m ), z( 1, l-1 ), ldz ) */ /* *** New starting with version 2.5 *** */ /*< tst = z(l) >*/ tst = z__[l]; /*< z(l) = c*tst - s*z(l-1) >*/ z__[l] = c__ * tst - s * z__[l - 1]; /*< z(l-1) = s*tst + c*z(l-1) >*/ z__[l - 1] = s * tst + c__ * z__[l - 1]; /* ************************************* */ /*< else >*/ } else { /*< call dlae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 ) >*/ dlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); /*< end if >*/ } /*< d( l-1 ) = rt1 >*/ d__[l - 1] = rt1; /*< d( l ) = rt2 >*/ d__[l] = rt2; /*< e( l-1 ) = zero >*/ e[l - 1] = 0.; /*< l = l - 2 >*/ l += -2; /*< >*/ if (l >= lend) { goto L90; } /*< go to 140 >*/ goto L140; /*< end if >*/ } /*< >*/ if (jtot == nmaxit) { goto L140; } /*< jtot = jtot + 1 >*/ ++jtot; /* form shift. */ /*< g = ( d( l-1 )-p ) / ( two*e( l-1 ) ) >*/ g = (d__[l - 1] - p) / (e[l - 1] * 2.); /*< r = dlapy2( g, one ) >*/ r__ = dlapy2_(&g, &c_b31); /*< g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) ) >*/ g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g)); /*< s = one >*/ s = 1.; /*< c = one >*/ c__ = 1.; /*< p = zero >*/ p = 0.; /* inner loop */ /*< lm1 = l - 1 >*/ lm1 = l - 1; /*< do 120 i = m, lm1 >*/ i__1 = lm1; for (i__ = m; i__ <= i__1; ++i__) { /*< f = s*e( i ) >*/ f = s * e[i__]; /*< b = c*e( i ) >*/ b = c__ * e[i__]; /*< call dlartg( g, f, c, s, r ) >*/ dlartg_(&g, &f, &c__, &s, &r__); /*< >*/ if (i__ != m) { e[i__ - 1] = r__; } /*< g = d( i ) - p >*/ g = d__[i__] - p; /*< r = ( d( i+1 )-g )*s + two*c*b >*/ r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b; /*< p = s*r >*/ p = s * r__; /*< d( i ) = g + p >*/ d__[i__] = g + p; /*< g = c*r - b >*/ g = c__ * r__ - b; /* if eigenvectors are desired, then save rotations. */ /*< if( icompz.gt.0 ) then >*/ if (icompz > 0) { /*< work( i ) = c >*/ work[i__] = c__; /*< work( n-1+i ) = s >*/ work[*n - 1 + i__] = s; /*< end if >*/ } /*< 120 continue >*/ /* L120: */ } /* if eigenvectors are desired, then apply saved rotations. */ /*< if( icompz.gt.0 ) then >*/ if (icompz > 0) { /*< mm = l - m + 1 >*/ mm = l - m + 1; /* $$$ call dlasr( 'r', 'v', 'f', n, mm, work( m ), work( n-1+m ), */ /* $$$ $ z( 1, m ), ldz ) */ /* *** New starting with version 2.5 *** */ /*< >*/ dlasr_("r", "v", "f", &c__1, &mm, &work[m], &work[*n - 1 + m], & z__[m], &c__1, (ftnlen)1, (ftnlen)1, (ftnlen)1); /* ************************************* */ /*< end if >*/ } /*< d( l ) = d( l ) - p >*/ d__[l] -= p; /*< e( lm1 ) = g >*/ e[lm1] = g; /*< go to 90 >*/ goto L90; /* eigenvalue found. */ /*< 130 continue >*/ L130: /*< d( l ) = p >*/ d__[l] = p; /*< l = l - 1 >*/ --l; /*< >*/ if (l >= lend) { goto L90; } /*< go to 140 >*/ goto L140; /*< end if >*/ } /* undo scaling if necessary */ /*< 140 continue >*/ L140: /*< if( iscale.eq.1 ) then >*/ if (iscale == 1) { /*< >*/ i__1 = lendsv - lsv + 1; dlascl_("g", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], n, info, (ftnlen)1); /*< >*/ i__1 = lendsv - lsv; dlascl_("g", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, info, (ftnlen)1); /*< else if( iscale.eq.2 ) then >*/ } else if (iscale == 2) { /*< >*/ i__1 = lendsv - lsv + 1; dlascl_("g", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], n, info, (ftnlen)1); /*< >*/ i__1 = lendsv - lsv; dlascl_("g", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, info, (ftnlen)1); /*< end if >*/ } /* check for no convergence to an eigenvalue after a total */ /* of n*maxit iterations. */ /*< >*/ if (jtot < nmaxit) { goto L10; } /*< do 150 i = 1, n - 1 >*/ i__1 = *n - 1; for (i__ = 1; i__ <= i__1; ++i__) { /*< >*/ if (e[i__] != 0.) { ++(*info); } /*< 150 continue >*/ /* L150: */ } /*< go to 190 >*/ goto L190; /* order eigenvalues and eigenvectors. */ /*< 160 continue >*/ L160: /*< if( icompz.eq.0 ) then >*/ if (icompz == 0) { /* use quick sort */ /*< call dlasrt( 'i', n, d, info ) >*/ dlasrt_("i", n, &d__[1], info, (ftnlen)1); /*< else >*/ } else { /* use selection sort to minimize swaps of eigenvectors */ /*< do 180 ii = 2, n >*/ i__1 = *n; for (ii = 2; ii <= i__1; ++ii) { /*< i = ii - 1 >*/ i__ = ii - 1; /*< k = i >*/ k = i__; /*< p = d( i ) >*/ p = d__[i__]; /*< do 170 j = ii, n >*/ i__2 = *n; for (j = ii; j <= i__2; ++j) { /*< if( d( j ).lt.p ) then >*/ if (d__[j] < p) { /*< k = j >*/ k = j; /*< p = d( j ) >*/ p = d__[j]; /*< end if >*/ } /*< 170 continue >*/ /* L170: */ } /*< if( k.ne.i ) then >*/ if (k != i__) { /*< d( k ) = d( i ) >*/ d__[k] = d__[i__]; /*< d( i ) = p >*/ d__[i__] = p; /* $$$ call dswap( n, z( 1, i ), 1, z( 1, k ), 1 ) */ /* *** New starting with version 2.5 *** */ /*< p = z(k) >*/ p = z__[k]; /*< z(k) = z(i) >*/ z__[k] = z__[i__]; /*< z(i) = p >*/ z__[i__] = p; /* ************************************* */ /*< end if >*/ } /*< 180 continue >*/ /* L180: */ } /*< end if >*/ } /*< 190 continue >*/ L190: /*< return >*/ return 0; /* %---------------% */ /* | End of dstqrb | */ /* %---------------% */ /*< end >*/ } /* dstqrb_ */
/* Subroutine */ int zsteqr_(char *compz, integer *n, doublereal *d, doublereal *e, doublecomplex *z, integer *ldz, doublereal *work, integer *info) { /* -- LAPACK 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 ======= ZSTEQR computes all eigenvalues and, optionally, eigenvectors of a symmetric tridiagonal matrix using the implicit QL or QR method. The eigenvectors of a full or band complex Hermitian matrix can also be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this matrix to tridiagonal form. Arguments ========= COMPZ (input) CHARACTER*1 = 'N': Compute eigenvalues only. = 'V': Compute eigenvalues and eigenvectors of the original Hermitian matrix. On entry, Z must contain the unitary matrix used to reduce the original matrix to tridiagonal form. = 'I': Compute eigenvalues and eigenvectors of the tridiagonal matrix. Z is initialized to the identity matrix. N (input) INTEGER The order of the matrix. N >= 0. D (input/output) DOUBLE PRECISION 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) DOUBLE PRECISION array, dimension (N-1) On entry, the (n-1) subdiagonal elements of the tridiagonal matrix. On exit, E has been destroyed. Z (input/output) COMPLEX*16 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, and if eigenvectors are desired, then LDZ >= max(1,N). WORK (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2)) If COMPZ = 'N', then WORK is not referenced. INFO (output) INTEGER = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value > 0: the algorithm has failed to find all the eigenvalues in a total of 30*N iterations; if INFO = i, then i elements of E have not converged to zero; on exit, D and E contain the elements of a symmetric tridiagonal matrix which is unitarily similar to the original matrix. ===================================================================== Test the input parameters. Parameter adjustments Function Body */ /* Table of constant values */ static doublecomplex c_b1 = {0.,0.}; static doublecomplex c_b2 = {1.,0.}; static integer c__0 = 0; static integer c__1 = 1; static integer c__2 = 2; static doublereal c_b41 = 1.; /* System generated locals */ integer z_dim1, z_offset, i__1, i__2; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal), d_sign(doublereal *, doublereal *); /* Local variables */ static integer lend, jtot; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); static doublereal b, c, f, g; static integer i, j, k, l, m; static doublereal p, r, s; extern logical lsame_(char *, char *); static doublereal anorm; extern /* Subroutine */ int zlasr_(char *, char *, char *, integer *, integer *, doublereal *, doublereal *, doublecomplex *, integer *); static integer l1; extern /* Subroutine */ int zswap_(integer *, doublecomplex *, integer *, doublecomplex *, integer *), dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); static integer lendm1, lendp1; extern doublereal dlapy2_(doublereal *, doublereal *); static integer ii; extern doublereal dlamch_(char *); static integer mm, iscale; extern /* Subroutine */ int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *); static doublereal safmin; extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); static doublereal safmax; extern /* Subroutine */ int xerbla_(char *, integer *); extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, integer *); static integer lendsv; static doublereal ssfmin; static integer nmaxit, icompz; static doublereal ssfmax; extern /* Subroutine */ int zlaset_(char *, integer *, integer *, doublecomplex *, doublecomplex *, doublecomplex *, integer *); static integer lm1, mm1, nm1; static doublereal rt1, rt2, eps; static integer lsv; static doublereal tst, eps2; #define D(I) d[(I)-1] #define E(I) e[(I)-1] #define WORK(I) work[(I)-1] #define Z(I,J) z[(I)-1 + ((J)-1)* ( *ldz)] *info = 0; 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) { i__1 = -(*info); xerbla_("ZSTEQR", &i__1); return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { if (icompz == 2) { i__1 = z_dim1 + 1; Z(1,1).r = 1., Z(1,1).i = 0.; } return 0; } /* Determine the unit roundoff and over/underflow thresholds. */ eps = dlamch_("E"); /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; safmin = dlamch_("S"); safmax = 1. / safmin; ssfmax = sqrt(safmax) / 3.; ssfmin = sqrt(safmin) / eps2; /* Compute the eigenvalues and eigenvectors of the tridiagonal matrix. */ if (icompz == 2) { zlaset_("Full", n, n, &c_b1, &c_b2, &Z(1,1), ldz); } nmaxit = *n * 30; jtot = 0; /* Determine where the matrix splits and choose QL or QR iteration for each block, according to whether top or bottom diagonal element is smaller. */ l1 = 1; nm1 = *n - 1; L10: if (l1 > *n) { goto L160; } if (l1 > 1) { E(l1 - 1) = 0.; } if (l1 <= nm1) { i__1 = nm1; for (m = l1; m <= nm1; ++m) { tst = (d__1 = E(m), abs(d__1)); if (tst == 0.) { goto L30; } if (tst <= sqrt((d__1 = D(m), abs(d__1))) * sqrt((d__2 = D(m + 1), abs(d__2))) * eps) { E(m) = 0.; goto L30; } /* L20: */ } } m = *n; L30: l = l1; lsv = l; lend = m; lendsv = lend; l1 = m + 1; if (lend == l) { goto L10; } /* Scale submatrix in rows and columns L to LEND */ i__1 = lend - l + 1; anorm = dlanst_("I", &i__1, &D(l), &E(l)); iscale = 0; if (anorm == 0.) { goto L10; } if (anorm > ssfmax) { iscale = 1; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &D(l), n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &E(l), n, info); } else if (anorm < ssfmin) { iscale = 2; i__1 = lend - l + 1; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &D(l), n, info); i__1 = lend - l; dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &E(l), n, info); } /* Choose between QL and QR iteration */ if ((d__1 = D(lend), abs(d__1)) < (d__2 = D(l), abs(d__2))) { lend = lsv; l = lendsv; } if (lend > l) { /* QL Iteration Look for small subdiagonal element. */ L40: if (l != lend) { lendm1 = lend - 1; i__1 = lendm1; for (m = l; m <= lendm1; ++m) { /* Computing 2nd power */ d__2 = (d__1 = E(m), abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = D(m), abs(d__1)) * (d__2 = D(m + 1), abs(d__2)) + safmin) { goto L60; } /* L50: */ } } m = lend; L60: if (m < lend) { E(m) = 0.; } p = D(l); if (m == l) { goto L80; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 to compute its eigensystem. */ if (m == l + 1) { if (icompz > 0) { dlaev2_(&D(l), &E(l), &D(l + 1), &rt1, &rt2, &c, &s); WORK(l) = c; WORK(*n - 1 + l) = s; zlasr_("R", "V", "B", n, &c__2, &WORK(l), &WORK(*n - 1 + l), & Z(1,l), ldz); } else { dlae2_(&D(l), &E(l), &D(l + 1), &rt1, &rt2); } D(l) = rt1; D(l + 1) = rt2; E(l) = 0.; l += 2; if (l <= lend) { goto L40; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* Form shift. */ g = (D(l + 1) - p) / (E(l) * 2.); r = dlapy2_(&g, &c_b41); g = D(m) - p + E(l) / (g + d_sign(&r, &g)); s = 1.; c = 1.; p = 0.; /* Inner loop */ mm1 = m - 1; i__1 = l; for (i = mm1; i >= l; --i) { f = s * E(i); b = c * E(i); dlartg_(&g, &f, &c, &s, &r); if (i != m - 1) { E(i + 1) = r; } g = D(i + 1) - p; r = (D(i) - g) * s + c * 2. * b; p = s * r; D(i + 1) = g + p; g = c * r - b; /* If eigenvectors are desired, then save rotations. */ if (icompz > 0) { WORK(i) = c; WORK(*n - 1 + i) = -s; } /* L70: */ } /* If eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = m - l + 1; zlasr_("R", "V", "B", n, &mm, &WORK(l), &WORK(*n - 1 + l), &Z(1,l), ldz); } D(l) -= p; E(l) = g; goto L40; /* Eigenvalue found. */ L80: D(l) = p; ++l; if (l <= lend) { goto L40; } goto L140; } else { /* QR Iteration Look for small superdiagonal element. */ L90: if (l != lend) { lendp1 = lend + 1; i__1 = lendp1; for (m = l; m >= lendp1; --m) { /* Computing 2nd power */ d__2 = (d__1 = E(m - 1), abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = D(m), abs(d__1)) * (d__2 = D(m - 1), abs(d__2)) + safmin) { goto L110; } /* L100: */ } } m = lend; L110: if (m > lend) { E(m - 1) = 0.; } p = D(l); if (m == l) { goto L130; } /* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 to compute its eigensystem. */ if (m == l - 1) { if (icompz > 0) { dlaev2_(&D(l - 1), &E(l - 1), &D(l), &rt1, &rt2, &c, &s); WORK(m) = c; WORK(*n - 1 + m) = s; zlasr_("R", "V", "F", n, &c__2, &WORK(m), &WORK(*n - 1 + m), & Z(1,l-1), ldz); } else { dlae2_(&D(l - 1), &E(l - 1), &D(l), &rt1, &rt2); } D(l - 1) = rt1; D(l) = rt2; E(l - 1) = 0.; l += -2; if (l >= lend) { goto L90; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* Form shift. */ g = (D(l - 1) - p) / (E(l - 1) * 2.); r = dlapy2_(&g, &c_b41); g = D(m) - p + E(l - 1) / (g + d_sign(&r, &g)); s = 1.; c = 1.; p = 0.; /* Inner loop */ lm1 = l - 1; i__1 = lm1; for (i = m; i <= lm1; ++i) { f = s * E(i); b = c * E(i); dlartg_(&g, &f, &c, &s, &r); if (i != m) { E(i - 1) = r; } g = D(i) - p; r = (D(i + 1) - g) * s + c * 2. * b; p = s * r; D(i) = g + p; g = c * r - b; /* If eigenvectors are desired, then save rotations. */ if (icompz > 0) { WORK(i) = c; WORK(*n - 1 + i) = s; } /* L120: */ } /* If eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = l - m + 1; zlasr_("R", "V", "F", n, &mm, &WORK(m), &WORK(*n - 1 + m), &Z(1,m), ldz); } D(l) -= p; E(lm1) = g; goto L90; /* Eigenvalue found. */ L130: D(l) = p; --l; if (l >= lend) { goto L90; } goto L140; } /* Undo scaling if necessary */ L140: if (iscale == 1) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &D(lsv), n, info); i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &E(lsv), n, info); } else if (iscale == 2) { i__1 = lendsv - lsv + 1; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &D(lsv), n, info); i__1 = lendsv - lsv; dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &E(lsv), n, info); } /* Check for no convergence to an eigenvalue after a total of N*MAXIT iterations. */ if (jtot == nmaxit) { i__1 = *n - 1; for (i = 1; i <= *n-1; ++i) { if (E(i) != 0.) { ++(*info); } /* L150: */ } return 0; } goto L10; /* Order eigenvalues and eigenvectors. */ L160: if (icompz == 0) { /* Use Quick Sort */ dlasrt_("I", n, &D(1), info); } else { /* Use Selection Sort to minimize swaps of eigenvectors */ i__1 = *n; for (ii = 2; ii <= *n; ++ii) { i = ii - 1; k = i; p = D(i); i__2 = *n; for (j = ii; j <= *n; ++j) { if (D(j) < p) { k = j; p = D(j); } /* L170: */ } if (k != i) { D(k) = D(i); D(i) = p; zswap_(n, &Z(1,i), &c__1, &Z(1,k), & c__1); } /* L180: */ } } return 0; /* End of ZSTEQR */ } /* zsteqr_ */
/* Subroutine */ int dstqrb_(integer *n, doublereal *d__, doublereal *e, doublereal *z__, doublereal *work, integer *info) { /* System generated locals */ integer i__1, i__2; doublereal d__1, d__2; /* Local variables */ static doublereal b, c__, f, g; static integer i__, j, k, l, m; static doublereal p, r__, s; static integer l1, ii, mm, lm1, mm1, nm1; static doublereal rt1, rt2, eps; static integer lsv; static doublereal tst, eps2; static integer lend, jtot; extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *), dlasr_(char *, char *, char *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *, ftnlen, ftnlen, ftnlen); static doublereal anorm; extern /* Subroutine */ int dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); static integer lendm1, lendp1; extern doublereal dlapy2_(doublereal *, doublereal *), dlamch_(char *, ftnlen); static integer iscale; extern /* Subroutine */ int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *, ftnlen); static doublereal safmin; extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); static doublereal safmax; extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *, ftnlen); extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, integer *, ftnlen); static integer lendsv, nmaxit, icompz; static doublereal ssfmax, ssfmin; /* %------------------% */ /* | Scalar Arguments | */ /* %------------------% */ /* %-----------------% */ /* | Array Arguments | */ /* %-----------------% */ /* .. parameters .. */ /* .. */ /* .. local scalars .. */ /* .. */ /* .. external functions .. */ /* .. */ /* .. external subroutines .. */ /* .. */ /* .. intrinsic functions .. */ /* .. */ /* .. executable statements .. */ /* test the input parameters. */ /* Parameter adjustments */ --work; --z__; --e; --d__; /* Function Body */ *info = 0; /* $$$ IF( LSAME( COMPZ, 'N' ) ) THEN */ /* $$$ ICOMPZ = 0 */ /* $$$ ELSE IF( LSAME( COMPZ, 'V' ) ) THEN */ /* $$$ ICOMPZ = 1 */ /* $$$ ELSE IF( LSAME( COMPZ, 'I' ) ) THEN */ /* $$$ ICOMPZ = 2 */ /* $$$ ELSE */ /* $$$ ICOMPZ = -1 */ /* $$$ END IF */ /* $$$ IF( ICOMPZ.LT.0 ) THEN */ /* $$$ INFO = -1 */ /* $$$ ELSE IF( N.LT.0 ) THEN */ /* $$$ INFO = -2 */ /* $$$ ELSE IF( ( LDZ.LT.1 ) .OR. ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX( 1, */ /* $$$ $ N ) ) ) THEN */ /* $$$ INFO = -6 */ /* $$$ END IF */ /* $$$ IF( INFO.NE.0 ) THEN */ /* $$$ CALL XERBLA( 'SSTEQR', -INFO ) */ /* $$$ RETURN */ /* $$$ END IF */ /* *** New starting with version 2.5 *** */ icompz = 2; /* ************************************* */ /* quick return if possible */ if (*n == 0) { return 0; } if (*n == 1) { if (icompz == 2) { z__[1] = 1.; } return 0; } /* determine the unit roundoff and over/underflow thresholds. */ eps = dlamch_("e", (ftnlen)1); /* Computing 2nd power */ d__1 = eps; eps2 = d__1 * d__1; safmin = dlamch_("s", (ftnlen)1); safmax = 1. / safmin; ssfmax = sqrt(safmax) / 3.; ssfmin = sqrt(safmin) / eps2; /* compute the eigenvalues and eigenvectors of the tridiagonal */ /* matrix. */ /* $$ if( icompz.eq.2 ) */ /* $$$ $ call dlaset( 'full', n, n, zero, one, z, ldz ) */ /* *** New starting with version 2.5 *** */ if (icompz == 2) { i__1 = *n - 1; for (j = 1; j <= i__1; ++j) { z__[j] = 0.; /* L5: */ } z__[*n] = 1.; } /* ************************************* */ nmaxit = *n * 30; jtot = 0; /* determine where the matrix splits and choose ql or qr iteration */ /* for each block, according to whether top or bottom diagonal */ /* element is smaller. */ l1 = 1; nm1 = *n - 1; L10: if (l1 > *n) { goto L160; } if (l1 > 1) { e[l1 - 1] = 0.; } if (l1 <= nm1) { i__1 = nm1; for (m = l1; m <= i__1; ++m) { tst = (d__1 = e[m], abs(d__1)); if (tst == 0.) { goto L30; } if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m + 1], abs(d__2))) * eps) { e[m] = 0.; goto L30; } /* L20: */ } } m = *n; L30: l = l1; lsv = l; lend = m; lendsv = lend; l1 = m + 1; if (lend == l) { goto L10; } /* scale submatrix in rows and columns l to lend */ i__1 = lend - l + 1; anorm = dlanst_("i", &i__1, &d__[l], &e[l], (ftnlen)1); iscale = 0; if (anorm == 0.) { goto L10; } if (anorm > ssfmax) { iscale = 1; i__1 = lend - l + 1; dlascl_("g", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, info, (ftnlen)1); i__1 = lend - l; dlascl_("g", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, info, (ftnlen)1); } else if (anorm < ssfmin) { iscale = 2; i__1 = lend - l + 1; dlascl_("g", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, info, (ftnlen)1); i__1 = lend - l; dlascl_("g", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, info, (ftnlen)1); } /* choose between ql and qr iteration */ if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { lend = lsv; l = lendsv; } if (lend > l) { /* ql iteration */ /* look for small subdiagonal element. */ L40: if (l != lend) { lendm1 = lend - 1; i__1 = lendm1; for (m = l; m <= i__1; ++m) { /* Computing 2nd power */ d__2 = (d__1 = e[m], abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + 1], abs(d__2)) + safmin) { goto L60; } /* L50: */ } } m = lend; L60: if (m < lend) { e[m] = 0.; } p = d__[l]; if (m == l) { goto L80; } /* if remaining matrix is 2-by-2, use dlae2 or dlaev2 */ /* to compute its eigensystem. */ if (m == l + 1) { if (icompz > 0) { dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); work[l] = c__; work[*n - 1 + l] = s; /* $$$ call dlasr( 'r', 'v', 'b', n, 2, work( l ), */ /* $$$ $ work( n-1+l ), z( 1, l ), ldz ) */ /* *** New starting with version 2.5 *** */ tst = z__[l + 1]; z__[l + 1] = c__ * tst - s * z__[l]; z__[l] = s * tst + c__ * z__[l]; /* ************************************* */ } else { dlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); } d__[l] = rt1; d__[l + 1] = rt2; e[l] = 0.; l += 2; if (l <= lend) { goto L40; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* form shift. */ g = (d__[l + 1] - p) / (e[l] * 2.); r__ = dlapy2_(&g, &c_b31); g = d__[m] - p + e[l] / (g + d_sign(&r__, &g)); s = 1.; c__ = 1.; p = 0.; /* inner loop */ mm1 = m - 1; i__1 = l; for (i__ = mm1; i__ >= i__1; --i__) { f = s * e[i__]; b = c__ * e[i__]; dlartg_(&g, &f, &c__, &s, &r__); if (i__ != m - 1) { e[i__ + 1] = r__; } g = d__[i__ + 1] - p; r__ = (d__[i__] - g) * s + c__ * 2. * b; p = s * r__; d__[i__ + 1] = g + p; g = c__ * r__ - b; /* if eigenvectors are desired, then save rotations. */ if (icompz > 0) { work[i__] = c__; work[*n - 1 + i__] = -s; } /* L70: */ } /* if eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = m - l + 1; /* $$$ call dlasr( 'r', 'v', 'b', n, mm, work( l ), work( n-1+l ), */ /* $$$ $ z( 1, l ), ldz ) */ /* *** New starting with version 2.5 *** */ dlasr_("r", "v", "b", &c__1, &mm, &work[l], &work[*n - 1 + l], & z__[l], &c__1, (ftnlen)1, (ftnlen)1, (ftnlen)1); /* ************************************* */ } d__[l] -= p; e[l] = g; goto L40; /* eigenvalue found. */ L80: d__[l] = p; ++l; if (l <= lend) { goto L40; } goto L140; } else { /* qr iteration */ /* look for small superdiagonal element. */ L90: if (l != lend) { lendp1 = lend + 1; i__1 = lendp1; for (m = l; m >= i__1; --m) { /* Computing 2nd power */ d__2 = (d__1 = e[m - 1], abs(d__1)); tst = d__2 * d__2; if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m - 1], abs(d__2)) + safmin) { goto L110; } /* L100: */ } } m = lend; L110: if (m > lend) { e[m - 1] = 0.; } p = d__[l]; if (m == l) { goto L130; } /* if remaining matrix is 2-by-2, use dlae2 or dlaev2 */ /* to compute its eigensystem. */ if (m == l - 1) { if (icompz > 0) { dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) ; /* $$$ work( m ) = c */ /* $$$ work( n-1+m ) = s */ /* $$$ call dlasr( 'r', 'v', 'f', n, 2, work( m ), */ /* $$$ $ work( n-1+m ), z( 1, l-1 ), ldz ) */ /* *** New starting with version 2.5 *** */ tst = z__[l]; z__[l] = c__ * tst - s * z__[l - 1]; z__[l - 1] = s * tst + c__ * z__[l - 1]; /* ************************************* */ } else { dlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); } d__[l - 1] = rt1; d__[l] = rt2; e[l - 1] = 0.; l += -2; if (l >= lend) { goto L90; } goto L140; } if (jtot == nmaxit) { goto L140; } ++jtot; /* form shift. */ g = (d__[l - 1] - p) / (e[l - 1] * 2.); r__ = dlapy2_(&g, &c_b31); g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g)); s = 1.; c__ = 1.; p = 0.; /* inner loop */ lm1 = l - 1; i__1 = lm1; for (i__ = m; i__ <= i__1; ++i__) { f = s * e[i__]; b = c__ * e[i__]; dlartg_(&g, &f, &c__, &s, &r__); if (i__ != m) { e[i__ - 1] = r__; } g = d__[i__] - p; r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b; p = s * r__; d__[i__] = g + p; g = c__ * r__ - b; /* if eigenvectors are desired, then save rotations. */ if (icompz > 0) { work[i__] = c__; work[*n - 1 + i__] = s; } /* L120: */ } /* if eigenvectors are desired, then apply saved rotations. */ if (icompz > 0) { mm = l - m + 1; /* $$$ call dlasr( 'r', 'v', 'f', n, mm, work( m ), work( n-1+m ), */ /* $$$ $ z( 1, m ), ldz ) */ /* *** New starting with version 2.5 *** */ dlasr_("r", "v", "f", &c__1, &mm, &work[m], &work[*n - 1 + m], & z__[m], &c__1, (ftnlen)1, (ftnlen)1, (ftnlen)1); /* ************************************* */ } d__[l] -= p; e[lm1] = g; goto L90; /* eigenvalue found. */ L130: d__[l] = p; --l; if (l >= lend) { goto L90; } goto L140; } /* undo scaling if necessary */ L140: if (iscale == 1) { i__1 = lendsv - lsv + 1; dlascl_("g", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], n, info, (ftnlen)1); i__1 = lendsv - lsv; dlascl_("g", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, info, (ftnlen)1); } else if (iscale == 2) { i__1 = lendsv - lsv + 1; dlascl_("g", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], n, info, (ftnlen)1); i__1 = lendsv - lsv; dlascl_("g", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, info, (ftnlen)1); } /* check for no convergence to an eigenvalue after a total */ /* of n*maxit iterations. */ if (jtot < nmaxit) { goto L10; } i__1 = *n - 1; for (i__ = 1; i__ <= i__1; ++i__) { if (e[i__] != 0.) { ++(*info); } /* L150: */ } goto L190; /* order eigenvalues and eigenvectors. */ L160: if (icompz == 0) { /* use quick sort */ dlasrt_("i", n, &d__[1], info, (ftnlen)1); } else { /* 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]; } /* L170: */ } if (k != i__) { d__[k] = d__[i__]; d__[i__] = p; /* $$$ call dswap( n, z( 1, i ), 1, z( 1, k ), 1 ) */ /* *** New starting with version 2.5 *** */ p = z__[k]; z__[k] = z__[i__]; z__[i__] = p; /* ************************************* */ } /* L180: */ } } L190: return 0; /* %---------------% */ /* | End of dstqrb | */ /* %---------------% */ } /* dstqrb_ */