示例#1
0
文件: zlaev2.c 项目: flame/libflame
/* Subroutine */
int zlaev2_(doublecomplex *a, doublecomplex *b, doublecomplex *c__, doublereal *rt1, doublereal *rt2, doublereal *cs1, doublecomplex *sn1)
{
    /* System generated locals */
    doublereal d__1, d__2, d__3;
    doublecomplex z__1, z__2;
    /* Builtin functions */
    double z_abs(doublecomplex *);
    void d_cnjg(doublecomplex *, doublecomplex *);
    /* Local variables */
    doublereal t;
    doublecomplex w;
    extern /* Subroutine */
    int dlaev2_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *);
    /* -- LAPACK auxiliary routine (version 3.4.2) -- */
    /* -- LAPACK is a software package provided by Univ. of Tennessee, -- */
    /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */
    /* September 2012 */
    /* .. Scalar Arguments .. */
    /* .. */
    /* ===================================================================== */
    /* .. Parameters .. */
    /* .. */
    /* .. Local Scalars .. */
    /* .. */
    /* .. External Subroutines .. */
    /* .. */
    /* .. Intrinsic Functions .. */
    /* .. */
    /* .. Executable Statements .. */
    if (z_abs(b) == 0.)
    {
        w.r = 1.;
        w.i = 0.; // , expr subst
    }
    else
    {
        d_cnjg(&z__2, b);
        d__1 = z_abs(b);
        z__1.r = z__2.r / d__1;
        z__1.i = z__2.i / d__1; // , expr subst
        w.r = z__1.r;
        w.i = z__1.i; // , expr subst
    }
    d__1 = a->r;
    d__2 = z_abs(b);
    d__3 = c__->r;
    dlaev2_(&d__1, &d__2, &d__3, rt1, rt2, cs1, &t);
    z__1.r = t * w.r;
    z__1.i = t * w.i; // , expr subst
    sn1->r = z__1.r, sn1->i = z__1.i;
    return 0;
    /* End of ZLAEV2 */
}
示例#2
0
/*<       SUBROUTINE DSPTRF( UPLO, N, AP, IPIV, INFO ) >*/
/* Subroutine */ int dsptrf_(char *uplo, integer *n, doublereal *ap, integer *ipiv, 
integer *info, ftnlen uplo_len)
{
    /* System generated locals */
    integer i__1;
    doublereal d__1, d__2, d__3;

    /* Builtin functions */
    double sqrt(doublereal);

    /* Local variables */
    doublereal c__;
    integer j, k;
    doublereal s, t, r1, r2;
    integer kc, kk, kp, kx, knc, kpc=0, npp, imax=0, jmax;
    extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, 
	    doublereal *, integer *, doublereal *, doublereal *), dspr_(char *
	    , integer *, doublereal *, doublereal *, integer *, doublereal *, 
	    ftnlen);
    doublereal alpha;
    extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, 
	    integer *);
    extern logical lsame_(const char *, const char *, ftnlen, ftnlen);
    extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, 
	    doublereal *, integer *);
    integer kstep;
    logical upper;
    extern /* Subroutine */ int dlaev2_(doublereal *, doublereal *, 
	    doublereal *, doublereal *, doublereal *, doublereal *, 
	    doublereal *);
    doublereal absakk;
    extern integer idamax_(integer *, doublereal *, integer *);
    extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen);
    doublereal colmax, rowmax;
    (void)uplo_len;

/*  -- LAPACK routine (version 2.0) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */
/*     Courant Institute, Argonne National Lab, and Rice University */
/*     March 31, 1993 */

/*     .. Scalar Arguments .. */
/*<       CHARACTER          UPLO >*/
/*<       INTEGER            INFO, N >*/
/*     .. */
/*     .. Array Arguments .. */
/*<       INTEGER            IPIV( * ) >*/
/*<       DOUBLE PRECISION   AP( * ) >*/
/*     .. */

/*  Purpose */
/*  ======= */

/*  DSPTRF computes the factorization of a real symmetric matrix A stored */
/*  in packed format using the Bunch-Kaufman diagonal pivoting method: */

/*     A = U*D*U**T  or  A = L*D*L**T */

/*  where U (or L) is a product of permutation and unit upper (lower) */
/*  triangular matrices, and D is symmetric and block diagonal with */
/*  1-by-1 and 2-by-2 diagonal blocks. */

/*  Arguments */
/*  ========= */

/*  UPLO    (input) CHARACTER*1 */
/*          = 'U':  Upper triangle of A is stored; */
/*          = 'L':  Lower triangle of A is stored. */

/*  N       (input) INTEGER */
/*          The order of the matrix A.  N >= 0. */

/*  AP      (input/output) DOUBLE PRECISION array, dimension (N*(N+1)/2) */
/*          On entry, the upper or lower triangle of the symmetric matrix */
/*          A, packed columnwise in a linear array.  The j-th column of A */
/*          is stored in the array AP as follows: */
/*          if UPLO = 'U', AP(i + (j-1)*j/2) = A(i,j) for 1<=i<=j; */
/*          if UPLO = 'L', AP(i + (j-1)*(2n-j)/2) = A(i,j) for j<=i<=n. */

/*          On exit, the block diagonal matrix D and the multipliers used */
/*          to obtain the factor U or L, stored as a packed triangular */
/*          matrix overwriting A (see below for further details). */

/*  IPIV    (output) INTEGER array, dimension (N) */
/*          Details of the interchanges and the block structure of D. */
/*          If IPIV(k) > 0, then rows and columns k and IPIV(k) were */
/*          interchanged and D(k,k) is a 1-by-1 diagonal block. */
/*          If UPLO = 'U' and IPIV(k) = IPIV(k-1) < 0, then rows and */
/*          columns k-1 and -IPIV(k) were interchanged and D(k-1:k,k-1:k) */
/*          is a 2-by-2 diagonal block.  If UPLO = 'L' and IPIV(k) = */
/*          IPIV(k+1) < 0, then rows and columns k+1 and -IPIV(k) were */
/*          interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. */

/*  INFO    (output) INTEGER */
/*          = 0: successful exit */
/*          < 0: if INFO = -i, the i-th argument had an illegal value */
/*          > 0: if INFO = i, D(i,i) is exactly zero.  The factorization */
/*               has been completed, but the block diagonal matrix D is */
/*               exactly singular, and division by zero will occur if it */
/*               is used to solve a system of equations. */

/*  Further Details */
/*  =============== */

/*  If UPLO = 'U', then A = U*D*U', where */
/*     U = P(n)*U(n)* ... *P(k)U(k)* ..., */
/*  i.e., U is a product of terms P(k)*U(k), where k decreases from n to */
/*  1 in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1 */
/*  and 2-by-2 diagonal blocks D(k).  P(k) is a permutation matrix as */
/*  defined by IPIV(k), and U(k) is a unit upper triangular matrix, such */
/*  that if the diagonal block D(k) is of order s (s = 1 or 2), then */

/*             (   I    v    0   )   k-s */
/*     U(k) =  (   0    I    0   )   s */
/*             (   0    0    I   )   n-k */
/*                k-s   s   n-k */

/*  If s = 1, D(k) overwrites A(k,k), and v overwrites A(1:k-1,k). */
/*  If s = 2, the upper triangle of D(k) overwrites A(k-1,k-1), A(k-1,k), */
/*  and A(k,k), and v overwrites A(1:k-2,k-1:k). */

/*  If UPLO = 'L', then A = L*D*L', where */
/*     L = P(1)*L(1)* ... *P(k)*L(k)* ..., */
/*  i.e., L is a product of terms P(k)*L(k), where k increases from 1 to */
/*  n in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1 */
/*  and 2-by-2 diagonal blocks D(k).  P(k) is a permutation matrix as */
/*  defined by IPIV(k), and L(k) is a unit lower triangular matrix, such */
/*  that if the diagonal block D(k) is of order s (s = 1 or 2), then */

/*             (   I    0     0   )  k-1 */
/*     L(k) =  (   0    I     0   )  s */
/*             (   0    v     I   )  n-k-s+1 */
/*                k-1   s  n-k-s+1 */

/*  If s = 1, D(k) overwrites A(k,k), and v overwrites A(k+1:n,k). */
/*  If s = 2, the lower triangle of D(k) overwrites A(k,k), A(k+1,k), */
/*  and A(k+1,k+1), and v overwrites A(k+2:n,k:k+1). */

/*  ===================================================================== */

/*     .. Parameters .. */
/*<       DOUBLE PRECISION   ZERO, ONE >*/
/*<       PARAMETER          ( ZERO = 0.0D+0, ONE = 1.0D+0 ) >*/
/*<       DOUBLE PRECISION   EIGHT, SEVTEN >*/
/*<       PARAMETER          ( EIGHT = 8.0D+0, SEVTEN = 17.0D+0 ) >*/
/*     .. */
/*     .. Local Scalars .. */
/*<       LOGICAL            UPPER >*/
/*<    >*/
/*<       DOUBLE PRECISION   ABSAKK, ALPHA, C, COLMAX, R1, R2, ROWMAX, S, T >*/
/*     .. */
/*     .. External Functions .. */
/*<       LOGICAL            LSAME >*/
/*<       INTEGER            IDAMAX >*/
/*<       EXTERNAL           LSAME, IDAMAX >*/
/*     .. */
/*     .. External Subroutines .. */
/*<       EXTERNAL           DLAEV2, DROT, DSCAL, DSPR, DSWAP, XERBLA >*/
/*     .. */
/*     .. Intrinsic Functions .. */
/*<       INTRINSIC          ABS, MAX, SQRT >*/
/*     .. */
/*     .. Executable Statements .. */

/*     Test the input parameters. */

/*<       INFO = 0 >*/
    /* Parameter adjustments */
    --ipiv;
    --ap;

    /* Function Body */
    *info = 0;
/*<       UPPER = LSAME( UPLO, 'U' ) >*/
    upper = lsame_(uplo, "U", (ftnlen)1, (ftnlen)1);
/*<       IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN >*/
    if (! upper && ! lsame_(uplo, "L", (ftnlen)1, (ftnlen)1)) {
/*<          INFO = -1 >*/
	*info = -1;
/*<       ELSE IF( N.LT.0 ) THEN >*/
    } else if (*n < 0) {
/*<          INFO = -2 >*/
	*info = -2;
/*<       END IF >*/
    }
/*<       IF( INFO.NE.0 ) THEN >*/
    if (*info != 0) {
/*<          CALL XERBLA( 'DSPTRF', -INFO ) >*/
	i__1 = -(*info);
	xerbla_("DSPTRF", &i__1, (ftnlen)6);
/*<          RETURN >*/
	return 0;
/*<       END IF >*/
    }

/*     Initialize ALPHA for use in choosing pivot block size. */

/*<       ALPHA = ( ONE+SQRT( SEVTEN ) ) / EIGHT >*/
    alpha = (sqrt(17.) + 1.) / 8.;

/*<       IF( UPPER ) THEN >*/
    if (upper) {

/*        Factorize A as U*D*U' using the upper triangle of A */

/*        K is the main loop index, decreasing from N to 1 in steps of */
/*        1 or 2 */

/*<          K = N >*/
	k = *n;
/*<          KC = ( N-1 )*N / 2 + 1 >*/
	kc = (*n - 1) * *n / 2 + 1;
/*<    10    CONTINUE >*/
L10:
/*<          KNC = KC >*/
	knc = kc;

/*        If K < 1, exit from loop */

/*<    >*/
	if (k < 1) {
	    goto L70;
	}
/*<          KSTEP = 1 >*/
	kstep = 1;

/*        Determine rows and columns to be interchanged and whether */
/*        a 1-by-1 or 2-by-2 pivot block will be used */

/*<          ABSAKK = ABS( AP( KC+K-1 ) ) >*/
	absakk = (d__1 = ap[kc + k - 1], abs(d__1));

/*        IMAX is the row-index of the largest off-diagonal element in */
/*        column K, and COLMAX is its absolute value */

/*<          IF( K.GT.1 ) THEN >*/
	if (k > 1) {
/*<             IMAX = IDAMAX( K-1, AP( KC ), 1 ) >*/
	    i__1 = k - 1;
	    imax = idamax_(&i__1, &ap[kc], &c__1);
/*<             COLMAX = ABS( AP( KC+IMAX-1 ) ) >*/
	    colmax = (d__1 = ap[kc + imax - 1], abs(d__1));
/*<          ELSE >*/
	} else {
/*<             COLMAX = ZERO >*/
	    colmax = 0.;
/*<          END IF >*/
	}

/*<          IF( MAX( ABSAKK, COLMAX ).EQ.ZERO ) THEN >*/
	if (max(absakk,colmax) == 0.) {

/*           Column K is zero: set INFO and continue */

/*<    >*/
	    if (*info == 0) {
		*info = k;
	    }
/*<             KP = K >*/
	    kp = k;
/*<          ELSE >*/
	} else {
/*<             IF( ABSAKK.GE.ALPHA*COLMAX ) THEN >*/
	    if (absakk >= alpha * colmax) {

/*              no interchange, use 1-by-1 pivot block */

/*<                KP = K >*/
		kp = k;
/*<             ELSE >*/
	    } else {

/*              JMAX is the column-index of the largest off-diagonal */
/*              element in row IMAX, and ROWMAX is its absolute value */

/*<                ROWMAX = ZERO >*/
		rowmax = 0.;
/*<                JMAX = IMAX >*/
		jmax = imax;
/*<                KX = IMAX*( IMAX+1 ) / 2 + IMAX >*/
		kx = imax * (imax + 1) / 2 + imax;
/*<                DO 20 J = IMAX + 1, K >*/
		i__1 = k;
		for (j = imax + 1; j <= i__1; ++j) {
/*<                   IF( ABS( AP( KX ) ).GT.ROWMAX ) THEN >*/
		    if ((d__1 = ap[kx], abs(d__1)) > rowmax) {
/*<                      ROWMAX = ABS( AP( KX ) ) >*/
			rowmax = (d__1 = ap[kx], abs(d__1));
/*<                      JMAX = J >*/
			jmax = j;
/*<                   END IF >*/
		    }
/*<                   KX = KX + J >*/
		    kx += j;
/*<    20          CONTINUE >*/
/* L20: */
		}
/*<                KPC = ( IMAX-1 )*IMAX / 2 + 1 >*/
		kpc = (imax - 1) * imax / 2 + 1;
/*<                IF( IMAX.GT.1 ) THEN >*/
		if (imax > 1) {
/*<                   JMAX = IDAMAX( IMAX-1, AP( KPC ), 1 ) >*/
		    i__1 = imax - 1;
		    jmax = idamax_(&i__1, &ap[kpc], &c__1);
/*<                   ROWMAX = MAX( ROWMAX, ABS( AP( KPC+JMAX-1 ) ) ) >*/
/* Computing MAX */
		    d__2 = rowmax, d__3 = (d__1 = ap[kpc + jmax - 1], abs(
			    d__1));
		    rowmax = max(d__2,d__3);
/*<                END IF >*/
		}

/*<                IF( ABSAKK.GE.ALPHA*COLMAX*( COLMAX / ROWMAX ) ) THEN >*/
		if (absakk >= alpha * colmax * (colmax / rowmax)) {

/*                 no interchange, use 1-by-1 pivot block */

/*<                   KP = K >*/
		    kp = k;
/*<                ELSE IF( ABS( AP( KPC+IMAX-1 ) ).GE.ALPHA*ROWMAX ) THEN >*/
		} else if ((d__1 = ap[kpc + imax - 1], abs(d__1)) >= alpha * 
			rowmax) {

/*                 interchange rows and columns K and IMAX, use 1-by-1 */
/*                 pivot block */

/*<                   KP = IMAX >*/
		    kp = imax;
/*<                ELSE >*/
		} else {

/*                 interchange rows and columns K-1 and IMAX, use 2-by-2 */
/*                 pivot block */

/*<                   KP = IMAX >*/
		    kp = imax;
/*<                   KSTEP = 2 >*/
		    kstep = 2;
/*<                END IF >*/
		}
/*<             END IF >*/
	    }

/*<             KK = K - KSTEP + 1 >*/
	    kk = k - kstep + 1;
/*<    >*/
	    if (kstep == 2) {
		knc = knc - k + 1;
	    }
/*<             IF( KP.NE.KK ) THEN >*/
	    if (kp != kk) {

/*              Interchange rows and columns KK and KP in the leading */
/*              submatrix A(1:k,1:k) */

/*<                CALL DSWAP( KP-1, AP( KNC ), 1, AP( KPC ), 1 ) >*/
		i__1 = kp - 1;
		dswap_(&i__1, &ap[knc], &c__1, &ap[kpc], &c__1);
/*<                KX = KPC + KP - 1 >*/
		kx = kpc + kp - 1;
/*<                DO 30 J = KP + 1, KK - 1 >*/
		i__1 = kk - 1;
		for (j = kp + 1; j <= i__1; ++j) {
/*<                   KX = KX + J - 1 >*/
		    kx = kx + j - 1;
/*<                   T = AP( KNC+J-1 ) >*/
		    t = ap[knc + j - 1];
/*<                   AP( KNC+J-1 ) = AP( KX ) >*/
		    ap[knc + j - 1] = ap[kx];
/*<                   AP( KX ) = T >*/
		    ap[kx] = t;
/*<    30          CONTINUE >*/
/* L30: */
		}
/*<                T = AP( KNC+KK-1 ) >*/
		t = ap[knc + kk - 1];
/*<                AP( KNC+KK-1 ) = AP( KPC+KP-1 ) >*/
		ap[knc + kk - 1] = ap[kpc + kp - 1];
/*<                AP( KPC+KP-1 ) = T >*/
		ap[kpc + kp - 1] = t;
/*<                IF( KSTEP.EQ.2 ) THEN >*/
		if (kstep == 2) {
/*<                   T = AP( KC+K-2 ) >*/
		    t = ap[kc + k - 2];
/*<                   AP( KC+K-2 ) = AP( KC+KP-1 ) >*/
		    ap[kc + k - 2] = ap[kc + kp - 1];
/*<                   AP( KC+KP-1 ) = T >*/
		    ap[kc + kp - 1] = t;
/*<                END IF >*/
		}
/*<             END IF >*/
	    }

/*           Update the leading submatrix */

/*<             IF( KSTEP.EQ.1 ) THEN >*/
	    if (kstep == 1) {

/*              1-by-1 pivot block D(k): column k now holds */

/*              W(k) = U(k)*D(k) */

/*              where U(k) is the k-th column of U */

/*              Perform a rank-1 update of A(1:k-1,1:k-1) as */

/*              A := A - U(k)*D(k)*U(k)' = A - W(k)*1/D(k)*W(k)' */

/*<                R1 = ONE / AP( KC+K-1 ) >*/
		r1 = 1. / ap[kc + k - 1];
/*<                CALL DSPR( UPLO, K-1, -R1, AP( KC ), 1, AP ) >*/
		i__1 = k - 1;
		d__1 = -r1;
		dspr_(uplo, &i__1, &d__1, &ap[kc], &c__1, &ap[1], (ftnlen)1);

/*              Store U(k) in column k */

/*<                CALL DSCAL( K-1, R1, AP( KC ), 1 ) >*/
		i__1 = k - 1;
		dscal_(&i__1, &r1, &ap[kc], &c__1);
/*<             ELSE >*/
	    } else {

/*              2-by-2 pivot block D(k): columns k and k-1 now hold */

/*              ( W(k-1) W(k) ) = ( U(k-1) U(k) )*D(k) */

/*              where U(k) and U(k-1) are the k-th and (k-1)-th columns */
/*              of U */

/*              Perform a rank-2 update of A(1:k-2,1:k-2) as */

/*              A := A - ( U(k-1) U(k) )*D(k)*( U(k-1) U(k) )' */
/*                 = A - ( W(k-1) W(k) )*inv(D(k))*( W(k-1) W(k) )' */

/*              Convert this to two rank-1 updates by using the eigen- */
/*              decomposition of D(k) */

/*<    >*/
		dlaev2_(&ap[kc - 1], &ap[kc + k - 2], &ap[kc + k - 1], &r1, &
			r2, &c__, &s);
/*<                R1 = ONE / R1 >*/
		r1 = 1. / r1;
/*<                R2 = ONE / R2 >*/
		r2 = 1. / r2;
/*<                CALL DROT( K-2, AP( KNC ), 1, AP( KC ), 1, C, S ) >*/
		i__1 = k - 2;
		drot_(&i__1, &ap[knc], &c__1, &ap[kc], &c__1, &c__, &s);
/*<                CALL DSPR( UPLO, K-2, -R1, AP( KNC ), 1, AP ) >*/
		i__1 = k - 2;
		d__1 = -r1;
		dspr_(uplo, &i__1, &d__1, &ap[knc], &c__1, &ap[1], (ftnlen)1);
/*<                CALL DSPR( UPLO, K-2, -R2, AP( KC ), 1, AP ) >*/
		i__1 = k - 2;
		d__1 = -r2;
		dspr_(uplo, &i__1, &d__1, &ap[kc], &c__1, &ap[1], (ftnlen)1);

/*              Store U(k) and U(k-1) in columns k and k-1 */

/*<                CALL DSCAL( K-2, R1, AP( KNC ), 1 ) >*/
		i__1 = k - 2;
		dscal_(&i__1, &r1, &ap[knc], &c__1);
/*<                CALL DSCAL( K-2, R2, AP( KC ), 1 ) >*/
		i__1 = k - 2;
		dscal_(&i__1, &r2, &ap[kc], &c__1);
/*<                CALL DROT( K-2, AP( KNC ), 1, AP( KC ), 1, C, -S ) >*/
		i__1 = k - 2;
		d__1 = -s;
		drot_(&i__1, &ap[knc], &c__1, &ap[kc], &c__1, &c__, &d__1);
/*<             END IF >*/
	    }
/*<          END IF >*/
	}

/*        Store details of the interchanges in IPIV */

/*<          IF( KSTEP.EQ.1 ) THEN >*/
	if (kstep == 1) {
/*<             IPIV( K ) = KP >*/
	    ipiv[k] = kp;
/*<          ELSE >*/
	} else {
/*<             IPIV( K ) = -KP >*/
	    ipiv[k] = -kp;
/*<             IPIV( K-1 ) = -KP >*/
	    ipiv[k - 1] = -kp;
/*<          END IF >*/
	}

/*        Decrease K and return to the start of the main loop */

/*<          K = K - KSTEP >*/
	k -= kstep;
/*<          KC = KNC - K >*/
	kc = knc - k;
/*<          GO TO 10 >*/
	goto L10;

/*<       ELSE >*/
    } else {

/*        Factorize A as L*D*L' using the lower triangle of A */

/*        K is the main loop index, increasing from 1 to N in steps of */
/*        1 or 2 */

/*<          K = 1 >*/
	k = 1;
/*<          KC = 1 >*/
	kc = 1;
/*<          NPP = N*( N+1 ) / 2 >*/
	npp = *n * (*n + 1) / 2;
/*<    40    CONTINUE >*/
L40:
/*<          KNC = KC >*/
	knc = kc;

/*        If K > N, exit from loop */

/*<    >*/
	if (k > *n) {
	    goto L70;
	}
/*<          KSTEP = 1 >*/
	kstep = 1;

/*        Determine rows and columns to be interchanged and whether */
/*        a 1-by-1 or 2-by-2 pivot block will be used */

/*<          ABSAKK = ABS( AP( KC ) ) >*/
	absakk = (d__1 = ap[kc], abs(d__1));

/*        IMAX is the row-index of the largest off-diagonal element in */
/*        column K, and COLMAX is its absolute value */

/*<          IF( K.LT.N ) THEN >*/
	if (k < *n) {
/*<             IMAX = K + IDAMAX( N-K, AP( KC+1 ), 1 ) >*/
	    i__1 = *n - k;
	    imax = k + idamax_(&i__1, &ap[kc + 1], &c__1);
/*<             COLMAX = ABS( AP( KC+IMAX-K ) ) >*/
	    colmax = (d__1 = ap[kc + imax - k], abs(d__1));
/*<          ELSE >*/
	} else {
/*<             COLMAX = ZERO >*/
	    colmax = 0.;
/*<          END IF >*/
	}

/*<          IF( MAX( ABSAKK, COLMAX ).EQ.ZERO ) THEN >*/
	if (max(absakk,colmax) == 0.) {

/*           Column K is zero: set INFO and continue */

/*<    >*/
	    if (*info == 0) {
		*info = k;
	    }
/*<             KP = K >*/
	    kp = k;
/*<          ELSE >*/
	} else {
/*<             IF( ABSAKK.GE.ALPHA*COLMAX ) THEN >*/
	    if (absakk >= alpha * colmax) {

/*              no interchange, use 1-by-1 pivot block */

/*<                KP = K >*/
		kp = k;
/*<             ELSE >*/
	    } else {

/*              JMAX is the column-index of the largest off-diagonal */
/*              element in row IMAX, and ROWMAX is its absolute value */

/*<                ROWMAX = ZERO >*/
		rowmax = 0.;
/*<                KX = KC + IMAX - K >*/
		kx = kc + imax - k;
/*<                DO 50 J = K, IMAX - 1 >*/
		i__1 = imax - 1;
		for (j = k; j <= i__1; ++j) {
/*<                   IF( ABS( AP( KX ) ).GT.ROWMAX ) THEN >*/
		    if ((d__1 = ap[kx], abs(d__1)) > rowmax) {
/*<                      ROWMAX = ABS( AP( KX ) ) >*/
			rowmax = (d__1 = ap[kx], abs(d__1));
/*<                      JMAX = J >*/
			jmax = j;
/*<                   END IF >*/
		    }
/*<                   KX = KX + N - J >*/
		    kx = kx + *n - j;
/*<    50          CONTINUE >*/
/* L50: */
		}
/*<                KPC = NPP - ( N-IMAX+1 )*( N-IMAX+2 ) / 2 + 1 >*/
		kpc = npp - (*n - imax + 1) * (*n - imax + 2) / 2 + 1;
/*<                IF( IMAX.LT.N ) THEN >*/
		if (imax < *n) {
/*<                   JMAX = IMAX + IDAMAX( N-IMAX, AP( KPC+1 ), 1 ) >*/
		    i__1 = *n - imax;
		    jmax = imax + idamax_(&i__1, &ap[kpc + 1], &c__1);
/*<                   ROWMAX = MAX( ROWMAX, ABS( AP( KPC+JMAX-IMAX ) ) ) >*/
/* Computing MAX */
		    d__2 = rowmax, d__3 = (d__1 = ap[kpc + jmax - imax], abs(
			    d__1));
		    rowmax = max(d__2,d__3);
/*<                END IF >*/
		}

/*<                IF( ABSAKK.GE.ALPHA*COLMAX*( COLMAX / ROWMAX ) ) THEN >*/
		if (absakk >= alpha * colmax * (colmax / rowmax)) {

/*                 no interchange, use 1-by-1 pivot block */

/*<                   KP = K >*/
		    kp = k;
/*<                ELSE IF( ABS( AP( KPC ) ).GE.ALPHA*ROWMAX ) THEN >*/
		} else if ((d__1 = ap[kpc], abs(d__1)) >= alpha * rowmax) {

/*                 interchange rows and columns K and IMAX, use 1-by-1 */
/*                 pivot block */

/*<                   KP = IMAX >*/
		    kp = imax;
/*<                ELSE >*/
		} else {

/*                 interchange rows and columns K+1 and IMAX, use 2-by-2 */
/*                 pivot block */

/*<                   KP = IMAX >*/
		    kp = imax;
/*<                   KSTEP = 2 >*/
		    kstep = 2;
/*<                END IF >*/
		}
/*<             END IF >*/
	    }

/*<             KK = K + KSTEP - 1 >*/
	    kk = k + kstep - 1;
/*<    >*/
	    if (kstep == 2) {
		knc = knc + *n - k + 1;
	    }
/*<             IF( KP.NE.KK ) THEN >*/
	    if (kp != kk) {

/*              Interchange rows and columns KK and KP in the trailing */
/*              submatrix A(k:n,k:n) */

/*<    >*/
		if (kp < *n) {
		    i__1 = *n - kp;
		    dswap_(&i__1, &ap[knc + kp - kk + 1], &c__1, &ap[kpc + 1],
			     &c__1);
		}
/*<                KX = KNC + KP - KK >*/
		kx = knc + kp - kk;
/*<                DO 60 J = KK + 1, KP - 1 >*/
		i__1 = kp - 1;
		for (j = kk + 1; j <= i__1; ++j) {
/*<                   KX = KX + N - J + 1 >*/
		    kx = kx + *n - j + 1;
/*<                   T = AP( KNC+J-KK ) >*/
		    t = ap[knc + j - kk];
/*<                   AP( KNC+J-KK ) = AP( KX ) >*/
		    ap[knc + j - kk] = ap[kx];
/*<                   AP( KX ) = T >*/
		    ap[kx] = t;
/*<    60          CONTINUE >*/
/* L60: */
		}
/*<                T = AP( KNC ) >*/
		t = ap[knc];
/*<                AP( KNC ) = AP( KPC ) >*/
		ap[knc] = ap[kpc];
/*<                AP( KPC ) = T >*/
		ap[kpc] = t;
/*<                IF( KSTEP.EQ.2 ) THEN >*/
		if (kstep == 2) {
/*<                   T = AP( KC+1 ) >*/
		    t = ap[kc + 1];
/*<                   AP( KC+1 ) = AP( KC+KP-K ) >*/
		    ap[kc + 1] = ap[kc + kp - k];
/*<                   AP( KC+KP-K ) = T >*/
		    ap[kc + kp - k] = t;
/*<                END IF >*/
		}
/*<             END IF >*/
	    }

/*           Update the trailing submatrix */

/*<             IF( KSTEP.EQ.1 ) THEN >*/
	    if (kstep == 1) {

/*              1-by-1 pivot block D(k): column k now holds */

/*              W(k) = L(k)*D(k) */

/*              where L(k) is the k-th column of L */

/*<                IF( K.LT.N ) THEN >*/
		if (k < *n) {

/*                 Perform a rank-1 update of A(k+1:n,k+1:n) as */

/*                 A := A - L(k)*D(k)*L(k)' = A - W(k)*(1/D(k))*W(k)' */

/*<                   R1 = ONE / AP( KC ) >*/
		    r1 = 1. / ap[kc];
/*<    >*/
		    i__1 = *n - k;
		    d__1 = -r1;
		    dspr_(uplo, &i__1, &d__1, &ap[kc + 1], &c__1, &ap[kc + *n 
			    - k + 1], (ftnlen)1);

/*                 Store L(k) in column K */

/*<                   CALL DSCAL( N-K, R1, AP( KC+1 ), 1 ) >*/
		    i__1 = *n - k;
		    dscal_(&i__1, &r1, &ap[kc + 1], &c__1);
/*<                END IF >*/
		}
/*<             ELSE >*/
	    } else {

/*              2-by-2 pivot block D(k): columns K and K+1 now hold */

/*              ( W(k) W(k+1) ) = ( L(k) L(k+1) )*D(k) */

/*              where L(k) and L(k+1) are the k-th and (k+1)-th columns */
/*              of L */

/*<                IF( K.LT.N-1 ) THEN >*/
		if (k < *n - 1) {

/*                 Perform a rank-2 update of A(k+2:n,k+2:n) as */

/*                 A := A - ( L(k) L(k+1) )*D(k)*( L(k) L(k+1) )' */
/*                    = A - ( W(k) W(k+1) )*inv(D(k))*( W(k) W(k+1) )' */

/*                 Convert this to two rank-1 updates by using the eigen- */
/*                 decomposition of D(k) */

/*<    >*/
		    dlaev2_(&ap[kc], &ap[kc + 1], &ap[knc], &r1, &r2, &c__, &
			    s);
/*<                   R1 = ONE / R1 >*/
		    r1 = 1. / r1;
/*<                   R2 = ONE / R2 >*/
		    r2 = 1. / r2;
/*<    >*/
		    i__1 = *n - k - 1;
		    drot_(&i__1, &ap[kc + 2], &c__1, &ap[knc + 1], &c__1, &
			    c__, &s);
/*<    >*/
		    i__1 = *n - k - 1;
		    d__1 = -r1;
		    dspr_(uplo, &i__1, &d__1, &ap[kc + 2], &c__1, &ap[knc + *
			    n - k], (ftnlen)1);
/*<    >*/
		    i__1 = *n - k - 1;
		    d__1 = -r2;
		    dspr_(uplo, &i__1, &d__1, &ap[knc + 1], &c__1, &ap[knc + *
			    n - k], (ftnlen)1);

/*                 Store L(k) and L(k+1) in columns k and k+1 */

/*<                   CALL DSCAL( N-K-1, R1, AP( KC+2 ), 1 ) >*/
		    i__1 = *n - k - 1;
		    dscal_(&i__1, &r1, &ap[kc + 2], &c__1);
/*<                   CALL DSCAL( N-K-1, R2, AP( KNC+1 ), 1 ) >*/
		    i__1 = *n - k - 1;
		    dscal_(&i__1, &r2, &ap[knc + 1], &c__1);
/*<    >*/
		    i__1 = *n - k - 1;
		    d__1 = -s;
		    drot_(&i__1, &ap[kc + 2], &c__1, &ap[knc + 1], &c__1, &
			    c__, &d__1);
/*<                END IF >*/
		}
/*<             END IF >*/
	    }
/*<          END IF >*/
	}

/*        Store details of the interchanges in IPIV */

/*<          IF( KSTEP.EQ.1 ) THEN >*/
	if (kstep == 1) {
/*<             IPIV( K ) = KP >*/
	    ipiv[k] = kp;
/*<          ELSE >*/
	} else {
/*<             IPIV( K ) = -KP >*/
	    ipiv[k] = -kp;
/*<             IPIV( K+1 ) = -KP >*/
	    ipiv[k + 1] = -kp;
/*<          END IF >*/
	}

/*        Increase K and return to the start of the main loop */

/*<          K = K + KSTEP >*/
	k += kstep;
/*<          KC = KNC + N - K + 2 >*/
	kc = knc + *n - k + 2;
/*<          GO TO 40 >*/
	goto L40;

/*<       END IF >*/
    }

/*<    70 CONTINUE >*/
L70:
/*<       RETURN >*/
    return 0;

/*     End of DSPTRF */

/*<       END >*/
} /* dsptrf_ */
示例#3
0
int TRL::dstqrb_(integer_ * n, doublereal_ * d__, doublereal_ * e,
			doublereal_ * z__, doublereal_ * work, integer_ * info)
{
	/*

	Purpose
	=======
	DSTQRB computes all eigenvalues and the last component of the eigenvectors of a
	symmetric tridiagonal matrix using the implicit QL or QR method.
	This is mainly a modification of the CLAPACK subroutine dsteqr.c

	Arguments
	=========

	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.

	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.

	=====================================================================
	*/
	/* Table of constant values */
	doublereal_ c_b10 = 1.;
	integer_ c__0 = 0;
	integer_ c__1 = 1;

	/* System generated locals */
	integer_ i__1, i__2;
	doublereal_ d__1, d__2;
	/* Builtin functions */
	//double sqrt_(doublereal_), d_sign(doublereal_ *, doublereal_ *);
	//extern /* Subroutine */ int dlae2_(doublereal_ *, doublereal_ *, doublereal_
	//	*, doublereal_ *, doublereal_ *);
	doublereal_ b, c__, f, g;
	integer_ i__, j, k, l, m;
	doublereal_ p, r__, s;
	//extern logical_ lsame_(char *, char *);
	//extern /* Subroutine */ int dlasr_(char *, char *, char *, integer_ *,
	//	integer_ *, doublereal_ *,
	//	doublereal_ *, doublereal_ *,
	//	integer_ *);
	doublereal_ anorm;
	//extern /* Subroutine */ int dswap_(integer_ *, doublereal_ *, integer_ *,
	//	doublereal_ *, integer_ *);
	integer_ l1;
	//extern /* Subroutine */ int dlaev2_(doublereal_ *, doublereal_ *,
	//	doublereal_ *, doublereal_ *,
	//	doublereal_ *, doublereal_ *,
	//	doublereal_ *);
	integer_ lendm1, lendp1;
	//extern doublereal_ dlapy2_(doublereal_ *, doublereal_ *);
	integer_ ii;
	//extern doublereal_ dlamch_(char *);
	integer_ mm, iscale;
	//extern /* Subroutine */ int dlascl_(char *, integer_ *, integer_ *,
	//	doublereal_ *, doublereal_ *,
	//	integer_ *, integer_ *, doublereal_ *,
	//	integer_ *, integer_ *),
	//	dlaset_(char *, integer_ *, integer_ *, doublereal_ *, doublereal_ *,
	//	doublereal_ *, 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_ *);
	/* Local variables */
	integer_ lend, jtot;
	integer_ lendsv;
	doublereal_ ssfmin;
	integer_ nmaxit;
	doublereal_ ssfmax;
	integer_ lm1, mm1, nm1;
	doublereal_ rt1, rt2, eps;
	integer_ lsv;
	doublereal_ tst, eps2;

	--d__;
	--e;
	--z__;
	/* z_dim1 = *ldz;             */
	/* z_offset = 1 + z_dim1 * 1; */
	/* z__ -= z_offset;           */
	--work;

	/* Function Body */
	*info = 0;
	/* Taken out for TRLan
	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_("DSTEQR", &i__1);
	return 0;
	}
	*/
	/*  icompz = 2; */

	/*	Quick return if possible */

	if (*n == 0) {
		return 0;
	}

	if (*n == 1) {
		z__[1] = 1;
		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. */
	/* Taken out for TRLan
	if (icompz == 2) {
	dlaset_("Full", n, n, &c_b9, &c_b10, &z__[z_offset], ldz);
	}
	*/
	for (j = 1; j < *n; j++) {
		z__[j] = 0.0;
	}
	z__[*n] = 1.0;
	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], fabs(d__1));
			if (tst == 0.) {
				goto L30;
			}
			if (tst <=
				sqrt_((d__1 = d__[m], fabs(d__1))) * sqrt_((d__2 =
				d__[m + 1],
				fabs(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], fabs(d__1)) < (d__2 = d__[l], fabs(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], fabs(d__1));
				tst = d__2 * d__2;
				if (tst <=
					eps2 * (d__1 = d__[m], fabs(d__1)) * (d__2 =
					d__[m + 1],
					fabs(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) {
			dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s);
			work[l] = c__;
			work[*n - 1 + l] = s;
			/* Taken out for TRLan
			dlasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], &
			z___ref(1, l), ldz);
			*/
			tst = z__[l + 1];
			z__[l + 1] = c__ * tst - s * z__[l];
			z__[l] = s * tst + c__ * z__[l];
			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_b10);
		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. */

			work[i__] = c__;
			work[*n - 1 + i__] = -s;

			/* L70: */
		}

		/*	If eigenvectors are desired, then apply saved rotations. */

		mm = m - l + 1;
		/* Taken out for TRLan
		dlasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &
		z___ref(1, l), ldz);
		*/
		dlasr_("R", "V", "B", &c__1, &mm, &work[l], &work[*n - 1 + l],
			&z__[l], &c__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], fabs(d__1));
				tst = d__2 * d__2;
				if (tst <=
					eps2 * (d__1 = d__[m], fabs(d__1)) * (d__2 =
					d__[m - 1],
					fabs(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) {
			dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s);
			/* Taken out for TRLan
			work[m] = c__;
			work[*n - 1 + m] = s;
			dlasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], &
			z___ref(1, l - 1), ldz);
			*/
			tst = z__[l];
			z__[l] = c__ * tst - s * z__[l - 1];
			z__[l - 1] = s * tst + c__ * z__[l - 1];

			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_b10);
		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. */

			work[i__] = c__;
			work[*n - 1 + i__] = s;

			/* L120: */
		}

		/*	If eigenvectors are desired, then apply saved rotations. */

		mm = l - m + 1;
		/*
		dlasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &
		z___ref(1, m), ldz);
		*/
		dlasr_("R", "V", "F", &c__1, &mm, &work[m], &work[*n - 1 + m],
			&z__[m], &c__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);
		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) {
		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:

	/*        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;
			/* Taken out for TRLan
			dswap_(n, &z___ref(1, i__), &c__1, &z___ref(1, k), &c__1);
			*/
			p = z__[k];
			z__[k] = z__[i__];
			z__[i__] = p;
		}
		/* L180: */
	}

L190:
	return 0;
}	
示例#4
0
/* 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_ */
示例#5
0
/* 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.2) -- */
/*     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;
/*     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_ */
示例#6
0
文件: dsteqr.c 项目: csapng/libflame
/* Subroutine */
int dsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublereal *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 *);
    extern /* Subroutine */
    int dlasr_(char *, char *, char *, integer *, integer *, doublereal *, doublereal *, doublereal *, integer *);
    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 *);
    integer iscale;
    extern /* Subroutine */
    int dlascl_(char *, integer *, integer *, doublereal *, doublereal *, integer *, integer *, doublereal *, integer *, integer *), dlaset_(char *, integer *, integer *, doublereal *, doublereal *, doublereal *, 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;
    /* -- 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_("DSTEQR", &i__1);
        return 0;
    }
    /* Quick return if possible */
    if (*n == 0)
    {
        return 0;
    }
    if (*n == 1)
    {
        if (icompz == 2)
        {
            z__[z_dim1 + 1] = 1.;
        }
        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)
    {
        dlaset_("Full", n, n, &c_b9, &c_b10, &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_("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);
    }
    /* 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;
                dlasr_("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_b10);
        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;
            dlasr_("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;
                dlasr_("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_b10);
        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;
            dlasr_("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)
    {
        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);
    }
    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;
                dswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], &c__1);
            }
            /* L180: */
        }
    }
L190:
    return 0;
    /* End of DSTEQR */
}
示例#7
0
文件: zlaev2.c 项目: dacap/loseface
/* Subroutine */ int zlaev2_(doublecomplex *a, doublecomplex *b, 
	doublecomplex *c__, doublereal *rt1, doublereal *rt2, doublereal *cs1, 
	 doublecomplex *sn1)
{
    /* System generated locals */
    doublereal d__1, d__2, d__3;
    doublecomplex z__1, z__2;

    /* Builtin functions */
    double z_abs(doublecomplex *);
    void d_cnjg(doublecomplex *, doublecomplex *);

    /* Local variables */
    doublereal t;
    doublecomplex w;
    extern /* Subroutine */ int dlaev2_(doublereal *, doublereal *, 
	    doublereal *, doublereal *, doublereal *, doublereal *, 
	    doublereal *);


/*  -- LAPACK auxiliary routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  ZLAEV2 computes the eigendecomposition of a 2-by-2 Hermitian matrix */
/*     [  A         B  ] */
/*     [  CONJG(B)  C  ]. */
/*  On return, RT1 is the eigenvalue of larger absolute value, RT2 is the */
/*  eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right */
/*  eigenvector for RT1, giving the decomposition */

/*  [ CS1  CONJG(SN1) ] [    A     B ] [ CS1 -CONJG(SN1) ] = [ RT1  0  ] */
/*  [-SN1     CS1     ] [ CONJG(B) C ] [ SN1     CS1     ]   [  0  RT2 ]. */

/*  Arguments */
/*  ========= */

/*  A      (input) COMPLEX*16 */
/*         The (1,1) element of the 2-by-2 matrix. */

/*  B      (input) COMPLEX*16 */
/*         The (1,2) element and the conjugate of the (2,1) element of */
/*         the 2-by-2 matrix. */

/*  C      (input) COMPLEX*16 */
/*         The (2,2) element of the 2-by-2 matrix. */

/*  RT1    (output) DOUBLE PRECISION */
/*         The eigenvalue of larger absolute value. */

/*  RT2    (output) DOUBLE PRECISION */
/*         The eigenvalue of smaller absolute value. */

/*  CS1    (output) DOUBLE PRECISION */
/*  SN1    (output) COMPLEX*16 */
/*         The vector (CS1, SN1) is a unit right eigenvector for RT1. */

/*  Further Details */
/*  =============== */

/*  RT1 is accurate to a few ulps barring over/underflow. */

/*  RT2 may be inaccurate if there is massive cancellation in the */
/*  determinant A*C-B*B; higher precision or correctly rounded or */
/*  correctly truncated arithmetic would be needed to compute RT2 */
/*  accurately in all cases. */

/*  CS1 and SN1 are accurate to a few ulps barring over/underflow. */

/*  Overflow is possible only if RT1 is within a factor of 5 of overflow. */
/*  Underflow is harmless if the input data is 0 or exceeds */
/*     underflow_threshold / macheps. */

/* ===================================================================== */

/*     .. Parameters .. */
/*     .. */
/*     .. Local Scalars .. */
/*     .. */
/*     .. External Subroutines .. */
/*     .. */
/*     .. Intrinsic Functions .. */
/*     .. */
/*     .. Executable Statements .. */

    if (z_abs(b) == 0.) {
	w.r = 1., w.i = 0.;
    } else {
	d_cnjg(&z__2, b);
	d__1 = z_abs(b);
	z__1.r = z__2.r / d__1, z__1.i = z__2.i / d__1;
	w.r = z__1.r, w.i = z__1.i;
    }
    d__1 = a->r;
    d__2 = z_abs(b);
    d__3 = c__->r;
    dlaev2_(&d__1, &d__2, &d__3, rt1, rt2, cs1, &t);
    z__1.r = t * w.r, z__1.i = t * w.i;
    sn1->r = z__1.r, sn1->i = z__1.i;
    return 0;

/*     End of ZLAEV2 */

} /* zlaev2_ */
示例#8
0
文件: dsteqr.c 项目: 151706061/ITK
/*<       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_ */
示例#9
0
文件: zstemr.c 项目: flame/libflame
/* 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 */
}
示例#10
0
/* Subroutine */ int zlaev2_(doublecomplex *a, doublecomplex *b, 
	doublecomplex *c, doublereal *rt1, doublereal *rt2, doublereal *cs1, 
	doublecomplex *sn1)
{
/*  -- LAPACK auxiliary routine (version 2.0) --   
       Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,   
       Courant Institute, Argonne National Lab, and Rice University   
       October 31, 1992   


    Purpose   
    =======   

    ZLAEV2 computes the eigendecomposition of a 2-by-2 Hermitian matrix   
       [  A         B  ]   
       [  CONJG(B)  C  ].   
    On return, RT1 is the eigenvalue of larger absolute value, RT2 is the 
  
    eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right 
  
    eigenvector for RT1, giving the decomposition   

    [ CS1  CONJG(SN1) ] [    A     B ] [ CS1 -CONJG(SN1) ] = [ RT1  0  ] 
  
    [-SN1     CS1     ] [ CONJG(B) C ] [ SN1     CS1     ]   [  0  RT2 ]. 
  

    Arguments   
    =========   

    A      (input) COMPLEX*16   
           The (1,1) element of the 2-by-2 matrix.   

    B      (input) COMPLEX*16   
           The (1,2) element and the conjugate of the (2,1) element of   
           the 2-by-2 matrix.   

    C      (input) COMPLEX*16   
           The (2,2) element of the 2-by-2 matrix.   

    RT1    (output) DOUBLE PRECISION   
           The eigenvalue of larger absolute value.   

    RT2    (output) DOUBLE PRECISION   
           The eigenvalue of smaller absolute value.   

    CS1    (output) DOUBLE PRECISION   
    SN1    (output) COMPLEX*16   
           The vector (CS1, SN1) is a unit right eigenvector for RT1.   

    Further Details   
    ===============   

    RT1 is accurate to a few ulps barring over/underflow.   

    RT2 may be inaccurate if there is massive cancellation in the   
    determinant A*C-B*B; higher precision or correctly rounded or   
    correctly truncated arithmetic would be needed to compute RT2   
    accurately in all cases.   

    CS1 and SN1 are accurate to a few ulps barring over/underflow.   

    Overflow is possible only if RT1 is within a factor of 5 of overflow. 
  
    Underflow is harmless if the input data is 0 or exceeds   
       underflow_threshold / macheps.   

   ===================================================================== 
*/
    /* System generated locals */
    doublereal d__1, d__2, d__3;
    doublecomplex z__1, z__2;
    /* Builtin functions */
    double z_abs(doublecomplex *);
    void d_cnjg(doublecomplex *, doublecomplex *);
    /* Local variables */
    static doublereal t;
    static doublecomplex w;
    extern /* Subroutine */ int dlaev2_(doublereal *, doublereal *, 
	    doublereal *, doublereal *, doublereal *, doublereal *, 
	    doublereal *);



    if (z_abs(b) == 0.) {
	w.r = 1., w.i = 0.;
    } else {
	d_cnjg(&z__2, b);
	d__1 = z_abs(b);
	z__1.r = z__2.r / d__1, z__1.i = z__2.i / d__1;
	w.r = z__1.r, w.i = z__1.i;
    }
    d__1 = a->r;
    d__2 = z_abs(b);
    d__3 = c->r;
    dlaev2_(&d__1, &d__2, &d__3, rt1, rt2, cs1, &t);
    z__1.r = t * w.r, z__1.i = t * w.i;
    sn1->r = z__1.r, sn1->i = z__1.i;
    return 0;

/*     End of ZLAEV2 */

} /* zlaev2_ */
/*<       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_ */
示例#12
0
/* 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_ */
示例#13
0
文件: dstqrb.f.c 项目: cadarso/tensor
/* 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_ */