diff options
Diffstat (limited to 'SRC/zlar1v.f')
-rw-r--r-- | SRC/zlar1v.f | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/SRC/zlar1v.f b/SRC/zlar1v.f new file mode 100644 index 00000000..52d71250 --- /dev/null +++ b/SRC/zlar1v.f @@ -0,0 +1,371 @@ + SUBROUTINE ZLAR1V( N, B1, BN, LAMBDA, D, L, LD, LLD, + $ PIVMIN, GAPTOL, Z, WANTNC, NEGCNT, ZTZ, MINGMA, + $ R, ISUPPZ, NRMINV, RESID, RQCORR, WORK ) +* +* -- LAPACK auxiliary routine (version 3.1) -- +* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. +* November 2006 +* +* .. Scalar Arguments .. + LOGICAL WANTNC + INTEGER B1, BN, N, NEGCNT, R + DOUBLE PRECISION GAPTOL, LAMBDA, MINGMA, NRMINV, PIVMIN, RESID, + $ RQCORR, ZTZ +* .. +* .. Array Arguments .. + INTEGER ISUPPZ( * ) + DOUBLE PRECISION D( * ), L( * ), LD( * ), LLD( * ), + $ WORK( * ) + COMPLEX*16 Z( * ) +* .. +* +* Purpose +* ======= +* +* ZLAR1V computes the (scaled) r-th column of the inverse of +* the sumbmatrix in rows B1 through BN of the tridiagonal matrix +* L D L^T - sigma I. When sigma is close to an eigenvalue, the +* computed vector is an accurate eigenvector. Usually, r corresponds +* to the index where the eigenvector is largest in magnitude. +* The following steps accomplish this computation : +* (a) Stationary qd transform, L D L^T - sigma I = L(+) D(+) L(+)^T, +* (b) Progressive qd transform, L D L^T - sigma I = U(-) D(-) U(-)^T, +* (c) Computation of the diagonal elements of the inverse of +* L D L^T - sigma I by combining the above transforms, and choosing +* r as the index where the diagonal of the inverse is (one of the) +* largest in magnitude. +* (d) Computation of the (scaled) r-th column of the inverse using the +* twisted factorization obtained by combining the top part of the +* the stationary and the bottom part of the progressive transform. +* +* Arguments +* ========= +* +* N (input) INTEGER +* The order of the matrix L D L^T. +* +* B1 (input) INTEGER +* First index of the submatrix of L D L^T. +* +* BN (input) INTEGER +* Last index of the submatrix of L D L^T. +* +* LAMBDA (input) DOUBLE PRECISION +* The shift. In order to compute an accurate eigenvector, +* LAMBDA should be a good approximation to an eigenvalue +* of L D L^T. +* +* L (input) DOUBLE PRECISION array, dimension (N-1) +* The (n-1) subdiagonal elements of the unit bidiagonal matrix +* L, in elements 1 to N-1. +* +* D (input) DOUBLE PRECISION array, dimension (N) +* The n diagonal elements of the diagonal matrix D. +* +* LD (input) DOUBLE PRECISION array, dimension (N-1) +* The n-1 elements L(i)*D(i). +* +* LLD (input) DOUBLE PRECISION array, dimension (N-1) +* The n-1 elements L(i)*L(i)*D(i). +* +* PIVMIN (input) DOUBLE PRECISION +* The minimum pivot in the Sturm sequence. +* +* GAPTOL (input) DOUBLE PRECISION +* Tolerance that indicates when eigenvector entries are negligible +* w.r.t. their contribution to the residual. +* +* Z (input/output) COMPLEX*16 array, dimension (N) +* On input, all entries of Z must be set to 0. +* On output, Z contains the (scaled) r-th column of the +* inverse. The scaling is such that Z(R) equals 1. +* +* WANTNC (input) LOGICAL +* Specifies whether NEGCNT has to be computed. +* +* NEGCNT (output) INTEGER +* If WANTNC is .TRUE. then NEGCNT = the number of pivots < pivmin +* in the matrix factorization L D L^T, and NEGCNT = -1 otherwise. +* +* ZTZ (output) DOUBLE PRECISION +* The square of the 2-norm of Z. +* +* MINGMA (output) DOUBLE PRECISION +* The reciprocal of the largest (in magnitude) diagonal +* element of the inverse of L D L^T - sigma I. +* +* R (input/output) INTEGER +* The twist index for the twisted factorization used to +* compute Z. +* On input, 0 <= R <= N. If R is input as 0, R is set to +* the index where (L D L^T - sigma I)^{-1} is largest +* in magnitude. If 1 <= R <= N, R is unchanged. +* On output, R contains the twist index used to compute Z. +* Ideally, R designates the position of the maximum entry in the +* eigenvector. +* +* ISUPPZ (output) INTEGER array, dimension (2) +* The support of the vector in Z, i.e., the vector Z is +* nonzero only in elements ISUPPZ(1) through ISUPPZ( 2 ). +* +* NRMINV (output) DOUBLE PRECISION +* NRMINV = 1/SQRT( ZTZ ) +* +* RESID (output) DOUBLE PRECISION +* The residual of the FP vector. +* RESID = ABS( MINGMA )/SQRT( ZTZ ) +* +* RQCORR (output) DOUBLE PRECISION +* The Rayleigh Quotient correction to LAMBDA. +* RQCORR = MINGMA*TMP +* +* WORK (workspace) DOUBLE PRECISION array, dimension (4*N) +* +* 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 .. + DOUBLE PRECISION ZERO, ONE + PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 ) + COMPLEX*16 CONE + PARAMETER ( CONE = ( 1.0D0, 0.0D0 ) ) + +* .. +* .. Local Scalars .. + LOGICAL SAWNAN1, SAWNAN2 + INTEGER I, INDLPL, INDP, INDS, INDUMN, NEG1, NEG2, R1, + $ R2 + DOUBLE PRECISION DMINUS, DPLUS, EPS, S, TMP +* .. +* .. External Functions .. + LOGICAL DISNAN + DOUBLE PRECISION DLAMCH + EXTERNAL DISNAN, DLAMCH +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, DBLE +* .. +* .. Executable Statements .. +* + EPS = DLAMCH( 'Precision' ) + + + IF( R.EQ.0 ) THEN + R1 = B1 + R2 = BN + ELSE + R1 = R + R2 = R + END IF + +* Storage for LPLUS + INDLPL = 0 +* Storage for UMINUS + INDUMN = N + INDS = 2*N + 1 + INDP = 3*N + 1 + + IF( B1.EQ.1 ) THEN + WORK( INDS ) = ZERO + ELSE + WORK( INDS+B1-1 ) = LLD( B1-1 ) + END IF + +* +* Compute the stationary transform (using the differential form) +* until the index R2. +* + SAWNAN1 = .FALSE. + NEG1 = 0 + S = WORK( INDS+B1-1 ) - LAMBDA + DO 50 I = B1, R1 - 1 + DPLUS = D( I ) + S + WORK( INDLPL+I ) = LD( I ) / DPLUS + IF(DPLUS.LT.ZERO) NEG1 = NEG1 + 1 + WORK( INDS+I ) = S*WORK( INDLPL+I )*L( I ) + S = WORK( INDS+I ) - LAMBDA + 50 CONTINUE + SAWNAN1 = DISNAN( S ) + IF( SAWNAN1 ) GOTO 60 + DO 51 I = R1, R2 - 1 + DPLUS = D( I ) + S + WORK( INDLPL+I ) = LD( I ) / DPLUS + WORK( INDS+I ) = S*WORK( INDLPL+I )*L( I ) + S = WORK( INDS+I ) - LAMBDA + 51 CONTINUE + SAWNAN1 = DISNAN( S ) +* + 60 CONTINUE + IF( SAWNAN1 ) THEN +* Runs a slower version of the above loop if a NaN is detected + NEG1 = 0 + S = WORK( INDS+B1-1 ) - LAMBDA + DO 70 I = B1, R1 - 1 + DPLUS = D( I ) + S + IF(ABS(DPLUS).LT.PIVMIN) DPLUS = -PIVMIN + WORK( INDLPL+I ) = LD( I ) / DPLUS + IF(DPLUS.LT.ZERO) NEG1 = NEG1 + 1 + WORK( INDS+I ) = S*WORK( INDLPL+I )*L( I ) + IF( WORK( INDLPL+I ).EQ.ZERO ) + $ WORK( INDS+I ) = LLD( I ) + S = WORK( INDS+I ) - LAMBDA + 70 CONTINUE + DO 71 I = R1, R2 - 1 + DPLUS = D( I ) + S + IF(ABS(DPLUS).LT.PIVMIN) DPLUS = -PIVMIN + WORK( INDLPL+I ) = LD( I ) / DPLUS + WORK( INDS+I ) = S*WORK( INDLPL+I )*L( I ) + IF( WORK( INDLPL+I ).EQ.ZERO ) + $ WORK( INDS+I ) = LLD( I ) + S = WORK( INDS+I ) - LAMBDA + 71 CONTINUE + END IF +* +* Compute the progressive transform (using the differential form) +* until the index R1 +* + SAWNAN2 = .FALSE. + NEG2 = 0 + WORK( INDP+BN-1 ) = D( BN ) - LAMBDA + DO 80 I = BN - 1, R1, -1 + DMINUS = LLD( I ) + WORK( INDP+I ) + TMP = D( I ) / DMINUS + IF(DMINUS.LT.ZERO) NEG2 = NEG2 + 1 + WORK( INDUMN+I ) = L( I )*TMP + WORK( INDP+I-1 ) = WORK( INDP+I )*TMP - LAMBDA + 80 CONTINUE + TMP = WORK( INDP+R1-1 ) + SAWNAN2 = DISNAN( TMP ) + + IF( SAWNAN2 ) THEN +* Runs a slower version of the above loop if a NaN is detected + NEG2 = 0 + DO 100 I = BN-1, R1, -1 + DMINUS = LLD( I ) + WORK( INDP+I ) + IF(ABS(DMINUS).LT.PIVMIN) DMINUS = -PIVMIN + TMP = D( I ) / DMINUS + IF(DMINUS.LT.ZERO) NEG2 = NEG2 + 1 + WORK( INDUMN+I ) = L( I )*TMP + WORK( INDP+I-1 ) = WORK( INDP+I )*TMP - LAMBDA + IF( TMP.EQ.ZERO ) + $ WORK( INDP+I-1 ) = D( I ) - LAMBDA + 100 CONTINUE + END IF +* +* Find the index (from R1 to R2) of the largest (in magnitude) +* diagonal element of the inverse +* + MINGMA = WORK( INDS+R1-1 ) + WORK( INDP+R1-1 ) + IF( MINGMA.LT.ZERO ) NEG1 = NEG1 + 1 + IF( WANTNC ) THEN + NEGCNT = NEG1 + NEG2 + ELSE + NEGCNT = -1 + ENDIF + IF( ABS(MINGMA).EQ.ZERO ) + $ MINGMA = EPS*WORK( INDS+R1-1 ) + R = R1 + DO 110 I = R1, R2 - 1 + TMP = WORK( INDS+I ) + WORK( INDP+I ) + IF( TMP.EQ.ZERO ) + $ TMP = EPS*WORK( INDS+I ) + IF( ABS( TMP ).LE.ABS( MINGMA ) ) THEN + MINGMA = TMP + R = I + 1 + END IF + 110 CONTINUE +* +* Compute the FP vector: solve N^T v = e_r +* + ISUPPZ( 1 ) = B1 + ISUPPZ( 2 ) = BN + Z( R ) = CONE + ZTZ = ONE +* +* Compute the FP vector upwards from R +* + IF( .NOT.SAWNAN1 .AND. .NOT.SAWNAN2 ) THEN + DO 210 I = R-1, B1, -1 + Z( I ) = -( WORK( INDLPL+I )*Z( I+1 ) ) + IF( (ABS(Z(I))+ABS(Z(I+1)))* ABS(LD(I)).LT.GAPTOL ) + $ THEN + Z( I ) = ZERO + ISUPPZ( 1 ) = I + 1 + GOTO 220 + ENDIF + ZTZ = ZTZ + DBLE( Z( I )*Z( I ) ) + 210 CONTINUE + 220 CONTINUE + ELSE +* Run slower loop if NaN occurred. + DO 230 I = R - 1, B1, -1 + IF( Z( I+1 ).EQ.ZERO ) THEN + Z( I ) = -( LD( I+1 ) / LD( I ) )*Z( I+2 ) + ELSE + Z( I ) = -( WORK( INDLPL+I )*Z( I+1 ) ) + END IF + IF( (ABS(Z(I))+ABS(Z(I+1)))* ABS(LD(I)).LT.GAPTOL ) + $ THEN + Z( I ) = ZERO + ISUPPZ( 1 ) = I + 1 + GO TO 240 + END IF + ZTZ = ZTZ + DBLE( Z( I )*Z( I ) ) + 230 CONTINUE + 240 CONTINUE + ENDIF + +* Compute the FP vector downwards from R in blocks of size BLKSIZ + IF( .NOT.SAWNAN1 .AND. .NOT.SAWNAN2 ) THEN + DO 250 I = R, BN-1 + Z( I+1 ) = -( WORK( INDUMN+I )*Z( I ) ) + IF( (ABS(Z(I))+ABS(Z(I+1)))* ABS(LD(I)).LT.GAPTOL ) + $ THEN + Z( I+1 ) = ZERO + ISUPPZ( 2 ) = I + GO TO 260 + END IF + ZTZ = ZTZ + DBLE( Z( I+1 )*Z( I+1 ) ) + 250 CONTINUE + 260 CONTINUE + ELSE +* Run slower loop if NaN occurred. + DO 270 I = R, BN - 1 + IF( Z( I ).EQ.ZERO ) THEN + Z( I+1 ) = -( LD( I-1 ) / LD( I ) )*Z( I-1 ) + ELSE + Z( I+1 ) = -( WORK( INDUMN+I )*Z( I ) ) + END IF + IF( (ABS(Z(I))+ABS(Z(I+1)))* ABS(LD(I)).LT.GAPTOL ) + $ THEN + Z( I+1 ) = ZERO + ISUPPZ( 2 ) = I + GO TO 280 + END IF + ZTZ = ZTZ + DBLE( Z( I+1 )*Z( I+1 ) ) + 270 CONTINUE + 280 CONTINUE + END IF +* +* Compute quantities for convergence test +* + TMP = ONE / ZTZ + NRMINV = SQRT( TMP ) + RESID = ABS( MINGMA )*NRMINV + RQCORR = MINGMA*TMP +* +* + RETURN +* +* End of ZLAR1V +* + END |