📄 slaed4.f
字号:
SUBROUTINE SLAED4( N, I, D, Z, DELTA, RHO, DLAM, INFO )** -- LAPACK routine (instrumented to count operations, version 3.0) --* Univ. of Tennessee, Oak Ridge National Lab, Argonne National Lab,* Courant Institute, NAG Ltd., and Rice University* June 30, 1999** .. Scalar Arguments .. INTEGER I, INFO, N REAL DLAM, RHO* ..* .. Array Arguments .. REAL D( * ), DELTA( * ), Z( * )* ..* Common block to return operation count and iteration count* ITCNT is unchanged, OPS is only incremented* .. Common blocks .. COMMON / LATIME / OPS, ITCNT* ..* .. Scalars in Common .. REAL ITCNT, OPS* ..** Purpose* =======** This subroutine computes the I-th updated eigenvalue of a symmetric* rank-one modification to a diagonal matrix whose elements are* given in the array d, and that** D(i) < D(j) for i < j** and that RHO > 0. This is arranged by the calling routine, and is* no loss in generality. The rank-one modified system is thus** diag( D ) + RHO * Z * Z_transpose.** where we assume the Euclidean norm of Z is 1.** The method consists of approximating the rational functions in the* secular equation by simpler interpolating rational functions.** Arguments* =========** N (input) INTEGER* The length of all arrays.** I (input) INTEGER* The index of the eigenvalue to be computed. 1 <= I <= N.** D (input) REAL array, dimension (N)* The original eigenvalues. It is assumed that they are in* order, D(I) < D(J) for I < J.** Z (input) REAL array, dimension (N)* The components of the updating vector.** DELTA (output) REAL array, dimension (N)* If N .ne. 1, DELTA contains (D(j) - lambda_I) in its j-th* component. If N = 1, then DELTA(1) = 1. The vector DELTA* contains the information necessary to construct the* eigenvectors.** RHO (input) REAL* The scalar in the symmetric updating formula.** DLAM (output) REAL* The computed lambda_I, the I-th updated eigenvalue.** INFO (output) INTEGER* = 0: successful exit* > 0: if INFO = 1, the updating process failed.** Internal Parameters* ===================** Logical variable ORGATI (origin-at-i?) is used for distinguishing* whether D(i) or D(i+1) is treated as the origin.** ORGATI = .true. origin at i* ORGATI = .false. origin at i+1** Logical variable SWTCH3 (switch-for-3-poles?) is for noting* if we are working with THREE poles!** MAXIT is the maximum number of iterations allowed for each* eigenvalue.** Further Details* ===============** Based on contributions by* Ren-Cang Li, Computer Science Division, University of California* at Berkeley, USA** =====================================================================** .. Parameters .. INTEGER MAXIT PARAMETER ( MAXIT = 20 ) REAL ZERO, ONE, TWO, THREE, FOUR, EIGHT, TEN PARAMETER ( ZERO = 0.0E0, ONE = 1.0E0, TWO = 2.0E0, $ THREE = 3.0E0, FOUR = 4.0E0, EIGHT = 8.0E0, $ TEN = 10.0E0 )* ..* .. Local Scalars .. LOGICAL ORGATI, SWTCH, SWTCH3 INTEGER II, IIM1, IIP1, IP1, ITER, J, NITER REAL A, B, C, DEL, DPHI, DPSI, DW, EPS, ERRETM, ETA, $ PHI, PREW, PSI, RHOINV, TAU, TEMP, TEMP1, W* ..* .. Local Arrays .. REAL ZZ( 3 )* ..* .. External Functions .. REAL SLAMCH EXTERNAL SLAMCH* ..* .. External Subroutines .. EXTERNAL SLAED5, SLAED6* ..* .. Intrinsic Functions .. INTRINSIC ABS, SQRT* ..* .. Executable Statements ..** Since this routine is called in an inner loop, we do no argument* checking.** Quick return for N=1 and 2.* INFO = 0 IF( N.EQ.1 ) THEN** Presumably, I=1 upon entry* OPS = OPS + 3 DLAM = D( 1 ) + RHO*Z( 1 )*Z( 1 ) DELTA( 1 ) = ONE RETURN END IF IF( N.EQ.2 ) THEN CALL SLAED5( I, D, Z, DELTA, RHO, DLAM ) RETURN END IF** Compute machine epsilon* EPS = SLAMCH( 'Epsilon' ) OPS = OPS + 1 RHOINV = ONE / RHO** The case I = N* IF( I.EQ.N ) THEN** Initialize some basic variables* II = N - 1 NITER = 1** Calculate initial guess* OPS = OPS + 5*N + 1 TEMP = RHO / TWO** If ||Z||_2 is not one, then TEMP should be set to* RHO * ||Z||_2^2 / TWO* DO 10 J = 1, N DELTA( J ) = ( D( J )-D( I ) ) - TEMP 10 CONTINUE* PSI = ZERO DO 20 J = 1, N - 2 PSI = PSI + Z( J )*Z( J ) / DELTA( J ) 20 CONTINUE* C = RHOINV + PSI W = C + Z( II )*Z( II ) / DELTA( II ) + $ Z( N )*Z( N ) / DELTA( N )* IF( W.LE.ZERO ) THEN OPS = OPS + 7 TEMP = Z( N-1 )*Z( N-1 ) / ( D( N )-D( N-1 )+RHO ) + $ Z( N )*Z( N ) / RHO IF( C.LE.TEMP ) THEN TAU = RHO ELSE OPS = OPS + 14 DEL = D( N ) - D( N-1 ) A = -C*DEL + Z( N-1 )*Z( N-1 ) + Z( N )*Z( N ) B = Z( N )*Z( N )*DEL IF( A.LT.ZERO ) THEN TAU = TWO*B / ( SQRT( A*A+FOUR*B*C )-A ) ELSE TAU = ( A+SQRT( A*A+FOUR*B*C ) ) / ( TWO*C ) END IF END IF** It can be proved that* D(N)+RHO/2 <= LAMBDA(N) < D(N)+TAU <= D(N)+RHO* ELSE OPS = OPS + 16 DEL = D( N ) - D( N-1 ) A = -C*DEL + Z( N-1 )*Z( N-1 ) + Z( N )*Z( N ) B = Z( N )*Z( N )*DEL IF( A.LT.ZERO ) THEN TAU = TWO*B / ( SQRT( A*A+FOUR*B*C )-A ) ELSE TAU = ( A+SQRT( A*A+FOUR*B*C ) ) / ( TWO*C ) END IF** It can be proved that* D(N) < D(N)+TAU < LAMBDA(N) < D(N)+RHO/2* END IF* OPS = OPS + 2*N + 6*II + 14 DO 30 J = 1, N DELTA( J ) = ( D( J )-D( I ) ) - TAU 30 CONTINUE** Evaluate PSI and the derivative DPSI* DPSI = ZERO PSI = ZERO ERRETM = ZERO DO 40 J = 1, II TEMP = Z( J ) / DELTA( J ) PSI = PSI + Z( J )*TEMP DPSI = DPSI + TEMP*TEMP ERRETM = ERRETM + PSI 40 CONTINUE ERRETM = ABS( ERRETM )** Evaluate PHI and the derivative DPHI* TEMP = Z( N ) / DELTA( N ) PHI = Z( N )*TEMP DPHI = TEMP*TEMP ERRETM = EIGHT*( -PHI-PSI ) + ERRETM - PHI + RHOINV + $ ABS( TAU )*( DPSI+DPHI )* W = RHOINV + PHI + PSI** Test for convergence* IF( ABS( W ).LE.EPS*ERRETM ) THEN OPS = OPS + 1 DLAM = D( I ) + TAU GO TO 250 END IF** Calculate the new step* OPS = OPS + 12 NITER = NITER + 1 C = W - DELTA( N-1 )*DPSI - DELTA( N )*DPHI A = ( DELTA( N-1 )+DELTA( N ) )*W - $ DELTA( N-1 )*DELTA( N )*( DPSI+DPHI ) B = DELTA( N-1 )*DELTA( N )*W IF( C.LT.ZERO ) $ C = ABS( C ) IF( C.EQ.ZERO ) THEN* ETA = B/A OPS = OPS + 1 ETA = RHO - TAU ELSE IF( A.GE.ZERO ) THEN OPS = OPS + 8 ETA = ( A+SQRT( ABS( A*A-FOUR*B*C ) ) ) / ( TWO*C ) ELSE OPS = OPS + 8 ETA = TWO*B / ( A-SQRT( ABS( A*A-FOUR*B*C ) ) ) END IF** Note, eta should be positive if w is negative, and* eta should be negative otherwise. However,* if for some reason caused by roundoff, eta*w > 0,* we simply use one Newton step instead. This way* will guarantee eta*w < 0.* OPS = OPS + N + 6*II + 16 IF( W*ETA.GT.ZERO ) THEN OPS = OPS + 2 ETA = -W / ( DPSI+DPHI ) END IF TEMP = TAU + ETA IF( TEMP.GT.RHO ) THEN OPS = OPS + 1 ETA = RHO - TAU END IF DO 50 J = 1, N DELTA( J ) = DELTA( J ) - ETA 50 CONTINUE* TAU = TAU + ETA** Evaluate PSI and the derivative DPSI* DPSI = ZERO PSI = ZERO ERRETM = ZERO DO 60 J = 1, II TEMP = Z( J ) / DELTA( J ) PSI = PSI + Z( J )*TEMP DPSI = DPSI + TEMP*TEMP ERRETM = ERRETM + PSI 60 CONTINUE ERRETM = ABS( ERRETM )** Evaluate PHI and the derivative DPHI* TEMP = Z( N ) / DELTA( N ) PHI = Z( N )*TEMP DPHI = TEMP*TEMP ERRETM = EIGHT*( -PHI-PSI ) + ERRETM - PHI + RHOINV + $ ABS( TAU )*( DPSI+DPHI )* W = RHOINV + PHI + PSI** Main loop to update the values of the array DELTA* ITER = NITER + 1* DO 90 NITER = ITER, MAXIT** Test for convergence* OPS = OPS + 1 IF( ABS( W ).LE.EPS*ERRETM ) THEN OPS = OPS + 1 DLAM = D( I ) + TAU GO TO 250 END IF** Calculate the new step* OPS = OPS + 36 + N + 6*II C = W - DELTA( N-1 )*DPSI - DELTA( N )*DPHI A = ( DELTA( N-1 )+DELTA( N ) )*W - $ DELTA( N-1 )*DELTA( N )*( DPSI+DPHI ) B = DELTA( N-1 )*DELTA( N )*W IF( A.GE.ZERO ) THEN ETA = ( A+SQRT( ABS( A*A-FOUR*B*C ) ) ) / ( TWO*C ) ELSE ETA = TWO*B / ( A-SQRT( ABS( A*A-FOUR*B*C ) ) ) END IF** Note, eta should be positive if w is negative, and* eta should be negative otherwise. However,* if for some reason caused by roundoff, eta*w > 0,* we simply use one Newton step instead. This way* will guarantee eta*w < 0.* IF( W*ETA.GT.ZERO ) $ ETA = -W / ( DPSI+DPHI ) TEMP = TAU + ETA IF( TEMP.LE.ZERO ) $ ETA = ETA / TWO DO 70 J = 1, N DELTA( J ) = DELTA( J ) - ETA 70 CONTINUE* TAU = TAU + ETA** Evaluate PSI and the derivative DPSI* DPSI = ZERO PSI = ZERO ERRETM = ZERO DO 80 J = 1, II TEMP = Z( J ) / DELTA( J ) PSI = PSI + Z( J )*TEMP DPSI = DPSI + TEMP*TEMP ERRETM = ERRETM + PSI 80 CONTINUE ERRETM = ABS( ERRETM )** Evaluate PHI and the derivative DPHI* TEMP = Z( N ) / DELTA( N ) PHI = Z( N )*TEMP DPHI = TEMP*TEMP ERRETM = EIGHT*( -PHI-PSI ) + ERRETM - PHI + RHOINV + $ ABS( TAU )*( DPSI+DPHI )* W = RHOINV + PHI + PSI 90 CONTINUE** Return with INFO = 1, NITER = MAXIT and not converged* INFO = 1 OPS = OPS + 1 DLAM = D( I ) + TAU GO TO 250** End for the case I = N* ELSE** The case for I < N* NITER = 1 IP1 = I + 1** Calculate initial guess* TEMP = ( D( IP1 )-D( I ) ) / TWO DO 100 J = 1, N DELTA( J ) = ( D( J )-D( I ) ) - TEMP 100 CONTINUE* PSI = ZERO DO 110 J = 1, I - 1 PSI = PSI + Z( J )*Z( J ) / DELTA( J ) 110 CONTINUE* PHI = ZERO DO 120 J = N, I + 2, -1 PHI = PHI + Z( J )*Z( J ) / DELTA( J ) 120 CONTINUE C = RHOINV + PSI + PHI W = C + Z( I )*Z( I ) / DELTA( I ) + $ Z( IP1 )*Z( IP1 ) / DELTA( IP1 )* IF( W.GT.ZERO ) THEN** d(i)< the ith eigenvalue < (d(i)+d(i+1))/2** We choose d(i) as origin.* ORGATI = .TRUE. DEL = D( IP1 ) - D( I ) A = C*DEL + Z( I )*Z( I ) + Z( IP1 )*Z( IP1 ) B = Z( I )*Z( I )*DEL IF( A.GT.ZERO ) THEN TAU = TWO*B / ( A+SQRT( ABS( A*A-FOUR*B*C ) ) ) ELSE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -