📄 dhgeqz.f
字号:
* Special case: j=ILAST
*
GO TO 80
ELSE
IF( ABS( A( ILAST, ILAST-1 ) ).LE.ATOL ) THEN
A( ILAST, ILAST-1 ) = ZERO
GO TO 80
END IF
END IF
*
IF( ABS( B( ILAST, ILAST ) ).LE.BTOL ) THEN
B( ILAST, ILAST ) = ZERO
GO TO 70
END IF
*
* General case: j<ILAST
*
DO 60 J = ILAST - 1, ILO, -1
*
* Test 1: for A(j,j-1)=0 or j=ILO
*
IF( J.EQ.ILO ) THEN
ILAZRO = .TRUE.
ELSE
IF( ABS( A( J, J-1 ) ).LE.ATOL ) THEN
A( J, J-1 ) = ZERO
ILAZRO = .TRUE.
ELSE
ILAZRO = .FALSE.
END IF
END IF
*
* Test 2: for B(j,j)=0
*
IF( ABS( B( J, J ) ).LT.BTOL ) THEN
B( J, J ) = ZERO
*
* Test 1a: Check for 2 consecutive small subdiagonals in A
*
ILAZR2 = .FALSE.
IF( .NOT.ILAZRO ) THEN
TEMP = ABS( A( J, J-1 ) )
TEMP2 = ABS( A( J, J ) )
TEMPR = MAX( TEMP, TEMP2 )
IF( TEMPR.LT.ONE .AND. TEMPR.NE.ZERO ) THEN
TEMP = TEMP / TEMPR
TEMP2 = TEMP2 / TEMPR
END IF
IF( TEMP*( ASCALE*ABS( A( J+1, J ) ) ).LE.TEMP2*
$ ( ASCALE*ATOL ) )ILAZR2 = .TRUE.
END IF
*
* If both tests pass (1 & 2), i.e., the leading diagonal
* element of B in the block is zero, split a 1x1 block off
* at the top. (I.e., at the J-th row/column) The leading
* diagonal element of the remainder can also be zero, so
* this may have to be done repeatedly.
*
IF( ILAZRO .OR. ILAZR2 ) THEN
DO 40 JCH = J, ILAST - 1
TEMP = A( JCH, JCH )
CALL DLARTG( TEMP, A( JCH+1, JCH ), C, S,
$ A( JCH, JCH ) )
A( JCH+1, JCH ) = ZERO
CALL DROT( ILASTM-JCH, A( JCH, JCH+1 ), LDA,
$ A( JCH+1, JCH+1 ), LDA, C, S )
CALL DROT( ILASTM-JCH, B( JCH, JCH+1 ), LDB,
$ B( JCH+1, JCH+1 ), LDB, C, S )
IF( ILQ )
$ CALL DROT( N, Q( 1, JCH ), 1, Q( 1, JCH+1 ), 1,
$ C, S )
IF( ILAZR2 )
$ A( JCH, JCH-1 ) = A( JCH, JCH-1 )*C
ILAZR2 = .FALSE.
IF( ABS( B( JCH+1, JCH+1 ) ).GE.BTOL ) THEN
IF( JCH+1.GE.ILAST ) THEN
GO TO 80
ELSE
IFIRST = JCH + 1
GO TO 110
END IF
END IF
B( JCH+1, JCH+1 ) = ZERO
40 CONTINUE
GO TO 70
ELSE
*
* Only test 2 passed -- chase the zero to B(ILAST,ILAST)
* Then process as in the case B(ILAST,ILAST)=0
*
DO 50 JCH = J, ILAST - 1
TEMP = B( JCH, JCH+1 )
CALL DLARTG( TEMP, B( JCH+1, JCH+1 ), C, S,
$ B( JCH, JCH+1 ) )
B( JCH+1, JCH+1 ) = ZERO
IF( JCH.LT.ILASTM-1 )
$ CALL DROT( ILASTM-JCH-1, B( JCH, JCH+2 ), LDB,
$ B( JCH+1, JCH+2 ), LDB, C, S )
CALL DROT( ILASTM-JCH+2, A( JCH, JCH-1 ), LDA,
$ A( JCH+1, JCH-1 ), LDA, C, S )
IF( ILQ )
$ CALL DROT( N, Q( 1, JCH ), 1, Q( 1, JCH+1 ), 1,
$ C, S )
TEMP = A( JCH+1, JCH )
CALL DLARTG( TEMP, A( JCH+1, JCH-1 ), C, S,
$ A( JCH+1, JCH ) )
A( JCH+1, JCH-1 ) = ZERO
CALL DROT( JCH+1-IFRSTM, A( IFRSTM, JCH ), 1,
$ A( IFRSTM, JCH-1 ), 1, C, S )
CALL DROT( JCH-IFRSTM, B( IFRSTM, JCH ), 1,
$ B( IFRSTM, JCH-1 ), 1, C, S )
IF( ILZ )
$ CALL DROT( N, Z( 1, JCH ), 1, Z( 1, JCH-1 ), 1,
$ C, S )
50 CONTINUE
GO TO 70
END IF
ELSE IF( ILAZRO ) THEN
*
* Only test 1 passed -- work on J:ILAST
*
IFIRST = J
GO TO 110
END IF
*
* Neither test passed -- try next J
*
60 CONTINUE
*
* (Drop-through is "impossible")
*
INFO = N + 1
GO TO 420
*
* B(ILAST,ILAST)=0 -- clear A(ILAST,ILAST-1) to split off a
* 1x1 block.
*
70 CONTINUE
TEMP = A( ILAST, ILAST )
CALL DLARTG( TEMP, A( ILAST, ILAST-1 ), C, S,
$ A( ILAST, ILAST ) )
A( ILAST, ILAST-1 ) = ZERO
CALL DROT( ILAST-IFRSTM, A( IFRSTM, ILAST ), 1,
$ A( IFRSTM, ILAST-1 ), 1, C, S )
CALL DROT( ILAST-IFRSTM, B( IFRSTM, ILAST ), 1,
$ B( IFRSTM, ILAST-1 ), 1, C, S )
IF( ILZ )
$ CALL DROT( N, Z( 1, ILAST ), 1, Z( 1, ILAST-1 ), 1, C, S )
*
* A(ILAST,ILAST-1)=0 -- Standardize B, set ALPHAR, ALPHAI,
* and BETA
*
80 CONTINUE
IF( B( ILAST, ILAST ).LT.ZERO ) THEN
IF( ILSCHR ) THEN
DO 90 J = IFRSTM, ILAST
A( J, ILAST ) = -A( J, ILAST )
B( J, ILAST ) = -B( J, ILAST )
90 CONTINUE
ELSE
A( ILAST, ILAST ) = -A( ILAST, ILAST )
B( ILAST, ILAST ) = -B( ILAST, ILAST )
END IF
IF( ILZ ) THEN
DO 100 J = 1, N
Z( J, ILAST ) = -Z( J, ILAST )
100 CONTINUE
END IF
END IF
ALPHAR( ILAST ) = A( ILAST, ILAST )
ALPHAI( ILAST ) = ZERO
BETA( ILAST ) = B( ILAST, ILAST )
*
* Go to next block -- exit if finished.
*
ILAST = ILAST - 1
IF( ILAST.LT.ILO )
$ GO TO 380
*
* Reset counters
*
IITER = 0
ESHIFT = ZERO
IF( .NOT.ILSCHR ) THEN
ILASTM = ILAST
IF( IFRSTM.GT.ILAST )
$ IFRSTM = ILO
END IF
GO TO 350
*
* QZ step
*
* This iteration only involves rows/columns IFIRST:ILAST. We
* assume IFIRST < ILAST, and that the diagonal of B is non-zero.
*
110 CONTINUE
IITER = IITER + 1
IF( .NOT.ILSCHR ) THEN
IFRSTM = IFIRST
END IF
*
* Compute single shifts.
*
* At this point, IFIRST < ILAST, and the diagonal elements of
* B(IFIRST:ILAST,IFIRST,ILAST) are larger than BTOL (in
* magnitude)
*
IF( ( IITER / 10 )*10.EQ.IITER ) THEN
*
* Exceptional shift. Chosen for no particularly good reason.
* (Single shift only.)
*
IF( ( DBLE( MAXIT )*SAFMIN )*ABS( A( ILAST-1, ILAST ) ).LT.
$ ABS( B( ILAST-1, ILAST-1 ) ) ) THEN
ESHIFT = ESHIFT + A( ILAST-1, ILAST ) /
$ B( ILAST-1, ILAST-1 )
ELSE
ESHIFT = ESHIFT + ONE / ( SAFMIN*DBLE( MAXIT ) )
END IF
S1 = ONE
WR = ESHIFT
*
ELSE
*
* Shifts based on the generalized eigenvalues of the
* bottom-right 2x2 block of A and B. The first eigenvalue
* returned by DLAG2 is the Wilkinson shift (AEP p.512),
*
CALL DLAG2( A( ILAST-1, ILAST-1 ), LDA,
$ B( ILAST-1, ILAST-1 ), LDB, SAFMIN*SAFETY, S1,
$ S2, WR, WR2, WI )
*
TEMP = MAX( S1, SAFMIN*MAX( ONE, ABS( WR ), ABS( WI ) ) )
IF( WI.NE.ZERO )
$ GO TO 200
END IF
*
* Fiddle with shift to avoid overflow
*
TEMP = MIN( ASCALE, ONE )*( HALF*SAFMAX )
IF( S1.GT.TEMP ) THEN
SCALE = TEMP / S1
ELSE
SCALE = ONE
END IF
*
TEMP = MIN( BSCALE, ONE )*( HALF*SAFMAX )
IF( ABS( WR ).GT.TEMP )
$ SCALE = MIN( SCALE, TEMP / ABS( WR ) )
S1 = SCALE*S1
WR = SCALE*WR
*
* Now check for two consecutive small subdiagonals.
*
DO 120 J = ILAST - 1, IFIRST + 1, -1
ISTART = J
TEMP = ABS( S1*A( J, J-1 ) )
TEMP2 = ABS( S1*A( J, J )-WR*B( J, J ) )
TEMPR = MAX( TEMP, TEMP2 )
IF( TEMPR.LT.ONE .AND. TEMPR.NE.ZERO ) THEN
TEMP = TEMP / TEMPR
TEMP2 = TEMP2 / TEMPR
END IF
IF( ABS( ( ASCALE*A( J+1, J ) )*TEMP ).LE.( ASCALE*ATOL )*
$ TEMP2 )GO TO 130
120 CONTINUE
*
ISTART = IFIRST
130 CONTINUE
*
* Do an implicit single-shift QZ sweep.
*
* Initial Q
*
TEMP = S1*A( ISTART, ISTART ) - WR*B( ISTART, ISTART )
TEMP2 = S1*A( ISTART+1, ISTART )
CALL DLARTG( TEMP, TEMP2, C, S, TEMPR )
*
* Sweep
*
DO 190 J = ISTART, ILAST - 1
IF( J.GT.ISTART ) THEN
TEMP = A( J, J-1 )
CALL DLARTG( TEMP, A( J+1, J-1 ), C, S, A( J, J-1 ) )
A( J+1, J-1 ) = ZERO
END IF
*
DO 140 JC = J, ILASTM
TEMP = C*A( J, JC ) + S*A( J+1, JC )
A( J+1, JC ) = -S*A( J, JC ) + C*A( J+1, JC )
A( J, JC ) = TEMP
TEMP2 = C*B( J, JC ) + S*B( J+1, JC )
B( J+1, JC ) = -S*B( J, JC ) + C*B( J+1, JC )
B( J, JC ) = TEMP2
140 CONTINUE
IF( ILQ ) THEN
DO 150 JR = 1, N
TEMP = C*Q( JR, J ) + S*Q( JR, J+1 )
Q( JR, J+1 ) = -S*Q( JR, J ) + C*Q( JR, J+1 )
Q( JR, J ) = TEMP
150 CONTINUE
END IF
*
TEMP = B( J+1, J+1 )
CALL DLARTG( TEMP, B( J+1, J ), C, S, B( J+1, J+1 ) )
B( J+1, J ) = ZERO
*
DO 160 JR = IFRSTM, MIN( J+2, ILAST )
TEMP = C*A( JR, J+1 ) + S*A( JR, J )
A( JR, J ) = -S*A( JR, J+1 ) + C*A( JR, J )
A( JR, J+1 ) = TEMP
160 CONTINUE
DO 170 JR = IFRSTM, J
TEMP = C*B( JR, J+1 ) + S*B( JR, J )
B( JR, J ) = -S*B( JR, J+1 ) + C*B( JR, J )
B( JR, J+1 ) = TEMP
170 CONTINUE
IF( ILZ ) THEN
DO 180 JR = 1, N
TEMP = C*Z( JR, J+1 ) + S*Z( JR, J )
Z( JR, J ) = -S*Z( JR, J+1 ) + C*Z( JR, J )
Z( JR, J+1 ) = TEMP
180 CONTINUE
END IF
190 CONTINUE
*
GO TO 350
*
* Use Francis double-shift
*
* Note: the Francis double-shift should work with real shifts,
* but only if the block is at least 3x3.
* This code may break if this point is reached with
* a 2x2 block with real eigenvalues.
*
200 CONTINUE
IF( IFIRST+1.EQ.ILAST ) THEN
*
* Special case -- 2x2 block with complex eigenvectors
*
* Step 1: Standardize, that is, rotate so that
*
* ( B11 0 )
* B = ( ) with B11 non-negative.
* ( 0 B22 )
*
CALL DLASV2( B( ILAST-1, ILAST-1 ), B( ILAST-1, ILAST ),
$ B( ILAST, ILAST ), B22, B11, SR, CR, SL, CL )
*
IF( B11.LT.ZERO ) THEN
CR = -CR
SR = -SR
B11 = -B11
B22 = -B22
END IF
*
CALL DROT( ILASTM+1-IFIRST, A( ILAST-1, ILAST-1 ), LDA,
$ A( ILAST, ILAST-1 ), LDA, CL, SL )
CALL DROT( ILAST+1-IFRSTM, A( IFRSTM, ILAST-1 ), 1,
$ A( IFRSTM, ILAST ), 1, CR, SR )
*
IF( ILAST.LT.ILASTM )
$ CALL DROT( ILASTM-ILAST, B( ILAST-1, ILAST+1 ), LDB,
$ B( ILAST, ILAST+1 ), LDA, CL, SL )
IF( IFRSTM.LT.ILAST-1 )
$ CALL DROT( IFIRST-IFRSTM, B( IFRSTM, ILAST-1 ), 1,
$ B( IFRSTM, ILAST ), 1, CR, SR )
*
IF( ILQ )
$ CALL DROT( N, Q( 1, ILAST-1 ), 1, Q( 1, ILAST ), 1, CL,
$ SL )
IF( ILZ )
$ CALL DROT( N, Z( 1, ILAST-1 ), 1, Z( 1, ILAST ), 1, CR,
$ SR )
*
B( ILAST-1, ILAST-1 ) = B11
B( ILAST-1, ILAST ) = ZERO
B( ILAST, ILAST-1 ) = ZERO
B( ILAST, ILAST ) = B22
*
* If B22 is negative, negate column ILAST
*
IF( B22.LT.ZERO ) THEN
DO 210 J = IFRSTM, ILAST
A( J, ILAST ) = -A( J, ILAST )
B( J, ILAST ) = -B( J, ILAST )
210 CONTINUE
*
IF( ILZ ) THEN
DO 220 J = 1, N
Z( J, ILAST ) = -Z( J, ILAST )
220 CONTINUE
END IF
END IF
*
* Step 2: Compute ALPHAR, ALPHAI, and BETA (see refs.)
*
* Recompute shift
*
CALL DLAG2( A( ILAST-1, ILAST-1 ), LDA,
$ B( ILAST-1, ILAST-1 ), LDB, SAFMIN*SAFETY, S1,
$ TEMP, WR, TEMP2, WI )
*
* If standardization has perturbed the shift onto real line,
* do another (real single-shift) QR step.
*
IF( WI.EQ.ZERO )
$ GO TO 350
S1INV = ONE / S1
*
* Do EISPACK (QZVAL) computation of alpha and beta
*
A11 = A( ILAST-1, ILAST-1 )
A21 = A( ILAST, ILAST-1 )
A12 = A( ILAST-1, ILAST )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -