C********************************************************************** C C Copyright (C) 1991-1992 Roland W. Freund and Noel M. Nachtigal C All rights reserved. C C This code is part of a copyrighted package. For details, see the C file "cpyrit.doc" in the top-level directory. C C ***************************************************************** C ANY USE OF THIS CODE CONSTITUTES ACCEPTANCE OF THE TERMS OF THE C COPYRIGHT NOTICE C ***************************************************************** C C********************************************************************** C C This file contains the routines for the eigenvalue solver, using C the three-term recurrence variant of the look-ahead Lanczos C algorithm. C C********************************************************************** C SUBROUTINE ZSLAL (NDIM,NLEN,NLIM,MAXN,MAXVW,M,NORM,ZWK,DWK,IDX, $ IWK,HWK,VECS,INFO) C C Purpose: C This subroutine uses the Lanczos algorithm with look-ahead to C compute eigenvalue estimates. The algorithm was first described C in the RIACS Technical Report 90.45, `An Implementation of the C Look-Ahead Lanczos Algorithm for Non-Hermitian Matrices, Part I`, C by R.W. Freund, M.H. Gutknecht and N.M. Nachtigal, November 1990. C The routine will first run the look-ahead Lanczos algorithm for a C number of steps. It will then prompt the user for the number of C eigenvalues to compute. In addition, the routine will also find C the common eigenvalues in two successive runs. C C Parameters: C For a description of the parameters, see the file "zslal.doc" in C the current directory. C C External routines used: C subroutine daxpby(n,z,a,x,b,y) C Library routine, computes z = a * x + b * y. C double precision dlamch(ch) C LAPACK routine, computes machine-related constants. C double precision dznrm2(n,dx,incx) C BLAS-1 routine, computes the 2-norm of x. C subroutine zaxpby(n,z,a,x,b,y) C Library routine, computes z = a * x + b * y. C double precision zdotu(n,dx,incx,dy,incy) C BLAS-1 routine, computes y^H * x. C subroutine zrandn(n,x,seed) C Library routine, fills x with random numbers. C subroutine zslal1(ndim,nlen,m,maxvw,numchk,n,l,lstar,nl,nlstar,vf, C ierr,adjust,norm1,norma,tmax,tnrm,zwk,dwk,iwk,idx,vecs) C Low-level routine, builds the vectors v_{n+1} and w_{n+1}. C subroutine zslalc(maxn,neig,nold,hwk,tf,vf) C Library routine, computes common eigenvalues. C subroutine zslale(maxn,neig,hwk,tf,vf) C Library routine, computes Lanczos eigenvalue approximations. C C Noel M. Nachtigal C October 24, 1990 C C********************************************************************** C INTRINSIC DABS, DIMAG, DREAL, DSQRT, MAX0, MOD EXTERNAL DAXPBY, DLAMCH, DZNRM2, ZAXPBY, ZDOTU, ZRANDN, ZSLAL1 EXTERNAL ZSLALC, ZSLALE DOUBLE COMPLEX ZDOTU DOUBLE PRECISION DLAMCH, DZNRM2 C INTEGER INFO(4), M, MAXN, MAXVW, NDIM, NLEN, NLIM INTEGER IDX(3,NLIM+2), IWK(M,4) DOUBLE COMPLEX VECS(NDIM,1*MAXVW+2+1), ZWK(M,5*M+3) DOUBLE PRECISION DWK(M,4), HWK(MAXN,4*MAXN+8), NORM C C Common block variables. C C C Common block ZSLALX. C DOUBLE PRECISION NORMA COMMON /ZSLALX/NORMA C C Miscellaneous parameters. C DOUBLE COMPLEX ZONE, ZZERO PARAMETER (ZONE = (1.0D0,0.0D0),ZZERO = (0.0D0,0.0D0)) DOUBLE PRECISION DONE, DTEN, DZERO PARAMETER (DONE = 1.0D0,DTEN = 1.0D1,DZERO = 0.0D0) C C Local variables, permanent. C INTEGER IERR, L, LSTAR, MVWBLT, N, NL, NLSTAR, NMAX, NUMCHK SAVE IERR, L, LSTAR, MVWBLT, N, NL, NLSTAR, NMAX, NUMCHK INTEGER RETLBL, TF, VF SAVE RETLBL, TF, VF DOUBLE PRECISION ADJUST, NORM1, TMAX, TMIN, TNRM SAVE ADJUST, NORM1, TMAX, TMIN, TNRM C C Local variables, transient. C INTEGER I, J, K, NEIG, REVCOM DOUBLE COMPLEX ZTMP DOUBLE PRECISION DTMP1, DTMP2 C C Local variables. C INTEGER NLAL, NOLD C C Initialize some of the permanent variables. C DATA RETLBL /0/ C C Check the reverse communication flag to see where to branch. C REVCOM RETLBL Comment C 0 0 first call, go to label 10 C 1 60 returning from AXB, go to label 60 C 2 70 returning from ATXB, go to label 70 C REVCOM = INFO(2) INFO(2) = 0 IF (REVCOM.EQ.0) THEN N = 0 NLAL = 0 MVWBLT = 0 IF (RETLBL.EQ.0) GO TO 10 ELSE IF (REVCOM.EQ.1) THEN IF (RETLBL.EQ.60) THEN GO TO 60 END IF ELSE IF (REVCOM.EQ.2) THEN IF (RETLBL.EQ.70) GO TO 70 END IF IERR = 1 GO TO 110 C C Check whether the inputs are valid. C 10 IERR = 0 IF (NDIM.LT.1) IERR = 2 IF (NLEN.LT.1) IERR = 2 IF (NLIM.LT.1) IERR = 2 IF (MAXVW.LT.1) IERR = 2 IF (NLEN.GT.NDIM) IERR = 2 IF (NLIM.GT.MAXN-2) IERR = 2 IF (M.LT.2*MAXVW+2) IERR = 2 IF (IERR.NE.0) GO TO 110 C C Extract from INFO the output units TF and VF, and the starting C vector flags J and K. C VF = MAX0(INFO(1),0) J = VF / 100000 VF = VF - J * 100000 K = VF / 10000 VF = VF - K * 10000 TF = VF / 100 VF = VF - TF * 100 C C Extract the norms. C NORMA = DZERO NORM1 = DABS(NORM) C C Set the adjustment parameters. C NUMCHK = 25 ADJUST = DTEN C C Extract and check the various tolerances and norm estimates. C TNRM = DLAMCH('E') * DTEN TMIN = DSQRT(DSQRT(DLAMCH('S'))) TMAX = DONE / TMIN C C Set up wrapped indices. The following indices are used: C IDX(1,I) = indices used for IWK and DWK, row-dimensioned M; C IDX(2,I) = indices used for v_i; C IDX(3,I) = indices used for w_i. C DO 20 I = 1, NLIM+2 IDX(1,I) = MOD(I-1,M) + 1 IDX(2,I) = 1 + 1 + 0*(MAXVW+2) + MOD(I-1,MAXVW+2) IDX(3,I) = IDX(2,I) 20 CONTINUE C C Check whether any starting vectors must be supplied. C IF (K.EQ.0) CALL ZRANDN (NLEN,VECS(1,1),1) CALL ZAXPBY (NLEN,VECS(1,IDX(2,1)),ZONE,VECS(1,1),ZZERO,VECS(1, $IDX(2,1))) CSYM IF (J.EQ.0) CALL ZRANDN (NLEN,VECS(1,1),1) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,1)),ZONE,VECS(1,1),ZZERO,VECS(1,IDX(3,1))) C C Zero out the Lanczos matrix. C DO 40 I = 1, MAXN DO 30 J = 1, MAXN HWK(I,J) = DZERO HWK(I,MAXN+J) = DZERO 30 CONTINUE 40 CONTINUE C C Scale the first pair of Lanczos vectors and check for invariant C subspaces. C DTMP1 = DZNRM2(NLEN,VECS(1,IDX(2,1)),1) CSYM DTMP2 = DZNRM2(NLEN,VECS(1,IDX(3,1)),1) DTMP2 = DTMP1 IF (DTMP1.LT.TNRM) IERR = IERR + 16 IF (DTMP2.LT.TNRM) IERR = IERR + 32 IF (IERR.NE.0) GO TO 110 DWK(IDX(1,1),1) = DONE ZWK(IDX(1,1),IDX(1,1)) = ZDOTU(NLEN,VECS(1,IDX(2,1)),1,VECS(1, $IDX(3,1)),1) / ( DTMP1 * DTMP2 ) IF ((DTMP1.GE.TMAX).OR.(DTMP1.LE.TMIN)) THEN ZTMP = DCMPLX(DONE / DTMP1,DZERO) CALL ZAXPBY (NLEN,VECS(1,IDX(2,1)),ZTMP,VECS(1,IDX(2,1)),ZZERO, $VECS(1,IDX(2,1))) DTMP1 = DONE END IF IF ((DTMP2.GE.TMAX).OR.(DTMP2.LE.TMIN)) THEN ZTMP = DCMPLX(DONE / DTMP2,DZERO) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,1)),ZTMP,VECS(1,IDX(3,1)),ZZERO,VECS(1,IDX(3,1))) DTMP2 = DONE END IF DWK(IDX(1,1),2) = DONE / DTMP1 DWK(IDX(1,1),3) = DONE / DTMP2 C C Initialize the counters. C L = 1 N = 1 NLAL = 0 NMAX = 0 IWK(IDX(1,0+1),1) = 1 IWK(IDX(1,1+1),1) = 1 MVWBLT = 1 NL = IWK(IDX(1,L+1),1) C C This is one step of the coupled two-term Lanczos algorithm. C V_n, W_n, D_{n-1}, F_{n-1}, H_{n-1}, and D_{nn} are given. C C Note that the previous step was not necessarily step N-1, as it C could have been a restart. C Except at the first step, the following hold: C NL.LE.N, N-NL.LE.MAXVW-1. C IF (VF.NE.0) WRITE (VF,'(A29)') 'Running look-ahead Lanczos...' 50 IWK(IDX(1,N),4) = L IWK(IDX(1,N),3) = N C C Build v_{n+1} and w_{n+1}. C Have the caller carry out AXB, then return here. C CALL AXB (VECS(1,IDX(2,N)),VECS(1,1)) C INFO(2) = 1 INFO(3) = IDX(2,N) INFO(4) = 1 RETLBL = 60 RETURN C C Have the caller carry out ATXB, then return here. C CALL ATXB (VECS(1,IDX(3,N)),VECS(1,1)) C 60 INFO(2) = 2 INFO(3) = IDX(3,N) INFO(4) = 2 RETLBL = 70 CSYM RETURN 70 IF ((VF.NE.0).AND.(N.LE.NMAX)) WRITE (VF,'(A11,I8)') 'Rebuilding:' $, N+1 CALL ZSLAL1 (NDIM,NLEN,M,MAXVW,NUMCHK,N,L,LSTAR,NL,NLSTAR,VF,IERR, $ ADJUST,NORM1,NORMA,TMAX,TMIN,TNRM,ZWK,DWK,IWK,IDX,VECS $) IF ((IERR.NE.0).AND.(IERR.NE.16).AND.(IERR.NE.32) $ .AND.(IERR.NE.48)) GO TO 110 MVWBLT = MAX0(MVWBLT,NL-IWK(IDX(1,L-1+1),1)) IWK(IDX(1,N),2) = NLSTAR C C Update the counter for steps taken. C NLAL = N NMAX = MAX0(NMAX,NLAL) C C Extract the column of H. C CALL DAXPBY (N+1,HWK(1,N),DZERO,HWK(1,N),DZERO,HWK(1,N)) CALL DAXPBY (N+1,HWK(1,MAXN+N),DZERO,HWK(1,MAXN+N),DZERO,HWK(1, $MAXN+N)) DO 80 I = NLSTAR, N+1 ZTMP = ZWK(IDX(1,I),2*M+IDX(1,N)) HWK(I,N) = DREAL(ZTMP) HWK(I,MAXN+N) = DIMAG(ZTMP) 80 CONTINUE C C Do the next step. C IF ((IERR.NE.0).OR.(N.GE.NLIM)) GO TO 90 N = N + 1 GO TO 50 C C The eigenvalue code starts here. C 90 NOLD = 0 100 NEIG = 0 WRITE (6,'()') WRITE (6,'(A43,I4)') 'Number of Lanczos steps completed : ' $, NLAL WRITE (6,'(A43,$)') 'Number of eigenvalues to compute (0=done): ' READ (5,*) NEIG IF ((NEIG.GT.0).AND.(NEIG.LE.NLAL)) THEN CALL ZSLALE (MAXN,NEIG,HWK,TF,VF) IF (NEIG.EQ.0) GO TO 100 IF (NOLD.NE.0) CALL ZSLALC (MAXN,NEIG,NOLD,HWK,TF,VF) NOLD = NEIG CALL DAXPBY (NOLD,HWK(1,4*MAXN+7),DONE,HWK(1,4*MAXN+4),DZERO, $HWK(1,4*MAXN+7)) CALL DAXPBY (NOLD,HWK(1,4*MAXN+8),DONE,HWK(1,4*MAXN+5),DZERO, $HWK(1,4*MAXN+8)) ELSE IF (NEIG.EQ.0) THEN GO TO 110 END IF GO TO 100 C C Done. C 110 RETLBL = 0 NLIM = NLAL INFO(1) = IERR NORM = NORM1 MAXVW = MVWBLT C RETURN END C C********************************************************************** C SUBROUTINE ZSLALC (MAXN,NEIG,NOLD,HWK,TF,VF) C C Purpose: C This subroutine finds eigenvalues common to the last two runs of C the eigenvalue routine. C C Parameters: C MAXN = the dimensioned size of the array HWK (input). C NEIG = the number of eigs in the current run (input). C NOLD = on entry, the number of eigs in the previous run; on exit C the number of common eigs (input/output). C HWK = double precision work array (input/output). C TF = if not 0, then the routine will output the common eigs to C this unit (input). C VF = if not 0, then the routine will produce verbose messages C on this unit (input). C C External routines used: C subroutine dhpsrt(n,wr,wi,wm) C Library routine, sorts wr and wi and wm. C C Noel M. Nachtigal C August 6, 1993 C C********************************************************************** C INTRINSIC DABS EXTERNAL DHPSRT C INTEGER MAXN, NEIG, NOLD, TF, VF DOUBLE PRECISION HWK(MAXN,4*MAXN+8) C C Local variables. C INTEGER I, J, K DOUBLE PRECISION DISTM, EIMAG, EMAGN, EREAL, TOL, TOLM C C Get the number of eigenvalues to find. C 10 WRITE (6,'()') WRITE (6,'(A43,$)') 'Find the common eigenvalues (1=Yes/0=No) ? ' READ (5,*) I IF (I.NE.1) RETURN WRITE (6,'(A43,$)') 'Enter separation tolerance : ' READ (5,*) TOL C C Check for common eigenvalues. C K = 0 DO 30 I = 1, NEIG EREAL = HWK(I,4*MAXN+4) EIMAG = HWK(I,4*MAXN+5) EMAGN = HWK(I,4*MAXN+6) DO 20 J = 1, NOLD DISTM = DSQRT(HWK(J,4*MAXN+7)**2 + HWK(J,4*MAXN+8)**2) TOLM = 0.5D0 * TOL * (EMAGN + DISTM) IF (DABS(EMAGN-DISTM).GE.TOLM) GO TO 20 DISTM = DSQRT((EREAL-HWK(J,4*MAXN+7))**2 + (EIMAG-HWK(J, $4*MAXN+8))**2) IF (DISTM.GE.TOLM) GO TO 20 K = K + 1 HWK(K,4*MAXN+1) = EREAL HWK(K,4*MAXN+2) = EIMAG HWK(K,4*MAXN+3) = EMAGN GO TO 30 20 CONTINUE 30 CONTINUE C C Sort the final eigenvalues by decreasing real part. C CALL DHPSRT (K,HWK(1,4*MAXN+1),HWK(1,4*MAXN+2),HWK(1,4*MAXN+3)) C C Output the results. C IF (VF.NE.0) WRITE (VF,'(A43,I4)') $ 'Number of common eigenvalues found : ', K IF (TF.NE.0) THEN WRITE (TF,'(A30,E12.7)') 'Common eigenvalues, tolerance: ', TOL WRITE (TF,'(2E25.17)') (HWK(I,4*MAXN+1),HWK(I,4*MAXN+2),I=1,K) WRITE (TF,'()') END IF GO TO 10 C END C C********************************************************************** C SUBROUTINE ZSLALE (MAXN,NEIG,HWK,TF,VF) C C Purpose: C This subroutine computes the eigenvalues estimates obtained from C the NEIG x NEIG upper left corner of the Lanczos matrix. It uses C the heuristic proposed by Cullum and Willoughby to separate the C genuine eigenvalues from the spurious ones. C C Parameters: C MAXN = the dimensioned size of the array HWK (input). C NEIG = the size of the submatrix whose eigs are computed. On C exit, it is the number of eigs found (input/output). C HWK = double precision work array (input/output). C TF = if not 0, then the routine will output the Lanczos eigs C to this unit (input). C VF = if not 0, then the routine will produce verbose messages C on this unit (input). C C External routines used: C subroutine cbal(nm,n,ar,ai,low,igh,scale) C EISPACK routine, balances a matrix. C subroutine comqr(nm,n,low,igh,hr,hi,wr,wi,ierr) C EISPACK routine, computes eigenvalues of an upper Hessenberg C matrix. C subroutine daxpby(n,z,a,x,b,y) C Library routine, computes z = a * x + b * y. C subroutine dhpsrt(n,wr,wi,wm) C Library routine, sorts wr and wi and wm. C double precision dlamch(ch) C LAPACK routine, computes machine-related constants. C C Noel M. Nachtigal C August 6, 1993 C C********************************************************************** C INTRINSIC DABS, DSQRT EXTERNAL CBAL, COMQR, DAXPBY, DHPSRT, DLAMCH DOUBLE PRECISION DLAMCH C INTEGER MAXN, NEIG, TF, VF DOUBLE PRECISION HWK(MAXN,4*MAXN+8) C C Miscellaneous parameters. C DOUBLE PRECISION DONE, DZERO PARAMETER (DONE = 1.0D0,DZERO = 0.0D0) C C Local variables. C INTEGER I, IERR, J, K, NBEG, NCHK, NEND, NLAL DOUBLE PRECISION DISTM, EIMAG, EMAGN, EREAL, TOL, TOLM LOGICAL MULTIP C C Compute the separation tolerance. C TOL = DSQRT(DLAMCH('E')) C C Extract the NEIG x NEIG matrix. C DO 10 I = 1, NEIG CALL DAXPBY (I+1,HWK(1,2*MAXN+I),DONE,HWK(1,I),DZERO,HWK(1, $2*MAXN+I)) CALL DAXPBY (I+1,HWK(1,3*MAXN+I),DONE,HWK(1,MAXN+I),DZERO,HWK(1 $,3*MAXN+I)) 10 CONTINUE C C Balance it and compute its eigenvalues. C IF (VF.NE.0) WRITE (VF,'(A24)') 'Computing eigenvalues...' CALL CBAL (MAXN,NEIG,HWK(1,2*MAXN+1),HWK(1,3*MAXN+1),I,J,HWK(1, $4*MAXN+1)) CALL COMQR (MAXN,NEIG,I,J,HWK(1,2*MAXN+1),HWK(1,3*MAXN+1),HWK(1, $4*MAXN+1),HWK(1,4*MAXN+2),IERR) IF (IERR.NE.0) THEN WRITE (6,'(A25,I2)') 'Error return from COMQR: ', IERR RETURN END IF C C Compute the magnitude of the eigenvalues. C DO 20 I = 1, NEIG HWK(I,4*MAXN+3) = DSQRT(HWK(I,4*MAXN+1)**2 + HWK(I,4*MAXN+2)**2 $) 20 CONTINUE C C Sort the eigenvalues in decreasing order of magnitude. C CALL DHPSRT (NEIG,HWK(1,4*MAXN+3),HWK(1,4*MAXN+1),HWK(1,4*MAXN+2)) IF (TF.NE.0) THEN WRITE (TF,'(A33,I4)') 'All Lanczos eigenvalues at step: ', NEIG WRITE (TF,'(2E25.17)') (HWK(I,4*MAXN+1),HWK(I,4*MAXN+2),I=1, $NEIG) WRITE (TF,'()') END IF C C Separate the repeated eigenvalues from the simple ones. C I = 1 NEND = 0 NLAL = NEIG NBEG = NEIG + 1 30 IF (I.GT.NLAL) GO TO 70 C C Outer loop, over all eigenvalues. C J = I + 1 EREAL = HWK(I,4*MAXN+1) EIMAG = HWK(I,4*MAXN+2) EMAGN = HWK(I,4*MAXN+3) MULTIP = .FALSE. 40 IF (J.GT.NLAL) GO TO 60 C C Inner loop, find eigenvalues J close to eigenvalue I. "Close" is C defined relative to the average of the two points, so as to be a C symmetric relationship. C TOLM = 0.5D0 * TOL * (EMAGN + HWK(J,4*MAXN+3)) C C If the difference in magnitude between I and J is greater than C the tolerance, skip the remaining eigenvalues, they will be even C further away (the eigenvalues are assumed sorted in some order of C magnitude). C IF (EMAGN-HWK(J,4*MAXN+3).GE.TOLM) GO TO 60 C C Compute the distance between the two eigenvalues. C DISTM = DSQRT((EREAL-HWK(J,4*MAXN+1))**2 + (EIMAG-HWK(J,4*MAXN+2)) $**2) C C Check the eigenvalue J. C IF (DISTM.GE.TOLM) THEN J = J + 1 ELSE MULTIP = .TRUE. DO 50 K = J, NLAL-1 HWK(K,4*MAXN+1) = HWK(K+1,4*MAXN+1) HWK(K,4*MAXN+2) = HWK(K+1,4*MAXN+2) HWK(K,4*MAXN+3) = HWK(K+1,4*MAXN+3) 50 CONTINUE NLAL = NLAL - 1 END IF GO TO 40 C C Collect the multiple eigenvalues in ELAL(1:NEND), and the simple C ones in ELAL(NBEG:NEIG). C 60 IF (MULTIP) THEN NEND = NEND + 1 HWK(NEND,4*MAXN+4) = EREAL HWK(NEND,4*MAXN+5) = EIMAG HWK(NEND,4*MAXN+6) = EMAGN ELSE NBEG = NBEG - 1 HWK(NBEG,4*MAXN+4) = EREAL HWK(NBEG,4*MAXN+5) = EIMAG HWK(NBEG,4*MAXN+6) = EMAGN END IF I = I + 1 GO TO 30 70 CONTINUE C C Check whether they are all considered genuine. C IF (NEND.EQ.NLAL) GO TO 120 C C Extract the (NEIG-1) x (NEIG-1) matrix. C NCHK = NEIG - 1 DO 80 I = 1, NCHK CALL DAXPBY (I+1,HWK(1,2*MAXN+I),DONE,HWK(2,I+1),DZERO,HWK(1, $2*MAXN+I)) CALL DAXPBY (I+1,HWK(1,3*MAXN+I),DONE,HWK(2,MAXN+I+1),DZERO, $HWK(1,3*MAXN+I)) 80 CONTINUE C C Balance it and compute its eigenvalues. C IF (VF.NE.0) WRITE (VF,'(A30)') 'Computing check eigenvalues...' CALL CBAL (MAXN,NCHK,HWK(1,2*MAXN+1),HWK(1,3*MAXN+1),I,J,HWK(1, $4*MAXN+1)) CALL COMQR (MAXN,NCHK,I,J,HWK(1,2*MAXN+1),HWK(1,3*MAXN+1),HWK(1, $4*MAXN+1),HWK(1,4*MAXN+2),IERR) IF (IERR.NE.0) THEN WRITE (6,'(A25,I2)') 'Error return from COMQR: ', IERR RETURN END IF C C Compute the magnitude of the check eigenvalues. C DO 90 I = 1, NCHK HWK(I,4*MAXN+3) = DSQRT(HWK(I,4*MAXN+1)**2 + HWK(I,4*MAXN+2)**2 $) 90 CONTINUE C C Sort the eigenvalues in decreasing order of magnitude. C CALL DHPSRT (NCHK,HWK(1,4*MAXN+3),HWK(1,4*MAXN+1),HWK(1,4*MAXN+2)) C C Check the Lanczos eigenvalues that were simple; keep those that C appear only in the Lanczos matrix. C The approach used is brute force; it could be more sophisticated. C DO 110 I = NBEG, NEIG EREAL = HWK(I,4*MAXN+4) EIMAG = HWK(I,4*MAXN+5) EMAGN = HWK(I,4*MAXN+6) DO 100 J = 1, NCHK TOLM = 0.5D0 * TOL * (EMAGN + HWK(J,4*MAXN+3)) IF (DABS(EMAGN-HWK(J,4*MAXN+3)).GE.TOLM) GO TO 100 DISTM = DSQRT((EREAL-HWK(J,4*MAXN+1))**2 + (EIMAG-HWK(J, $4*MAXN+2))**2) IF (DISTM.LT.TOLM) GO TO 110 100 CONTINUE C C It appears only in the Lanczos matrix, so it is good. C NEND = NEND + 1 HWK(NEND,4*MAXN+4) = EREAL HWK(NEND,4*MAXN+5) = EIMAG HWK(NEND,4*MAXN+6) = EMAGN 110 CONTINUE C C Sort the final eigenvalues by decreasing real part. C 120 CALL DHPSRT (NEND,HWK(1,4*MAXN+4),HWK(1,4*MAXN+5),HWK(1,4*MAXN+6)) C C Output the results. C IF (VF.NE.0) WRITE (VF,'(A43,I4)') $ 'Number of Lanczos eigenvalues found : ', NEND IF (TF.NE.0) THEN WRITE (TF,'(A30,I4)') 'Filtered eigenvalues at step: ', NEIG WRITE (TF,'(2E25.17)') (HWK(I,4*MAXN+4),HWK(I,4*MAXN+5),I=1, $NEND) WRITE (TF,'()') END IF NEIG = NEND C C Done. C RETURN END C C********************************************************************** C DOUBLE COMPLEX FUNCTION ZSLALH(I,J) C C Purpose: C Returns the recurrence coefficients for inner vectors. C C Parameters: C I = row index of the coefficient (input). C J = column index of the coefficient (input). C C Noel M. Nachtigal C July 9, 1993 C C********************************************************************** C C C Common block ZSLALX. C DOUBLE PRECISION NORMA COMMON /ZSLALX/NORMA C INTRINSIC DCMPLX C INTEGER I, J C IF ((I.LT.1).OR.(J.LT.1)) THEN ZSLALH = (0.0D0,0.0D0) ELSE IF (I.EQ.J) THEN ZSLALH = DCMPLX(NORMA,0.0D0) ELSE ZSLALH = (0.0D0,0.0D0) END IF C RETURN END C C********************************************************************** C SUBROUTINE ZSLAL1 (NDIM,NLEN,M,MAXVW,NUMCHK,N,L,LSTAR,NL,NLSTAR, $ VF,IERR,ADJUST,NORM1,NORMA,TMAX,TMIN,TNRM,ZWK, $ DWK,IWK,IDX,VECS) C C Purpose: C This subroutine builds a new pair of vectors v_{n+1} and w_{n+1}. C It is called internally by the Lanczos code, and is not meant to C to be called directly by the user code. C C Parameters: C See descriptions in "zulal.doc" or "zsqmr.doc". C C External routines used: C double precision dlamch(ch) C LAPACK routine, computes machine-related constants. C double precision dznrm2(n,x,incx) C BLAS-1 routine, computes the 2-norm of x. C subroutine zaxpby(n,z,a,x,b,y) C Library routine, computes z = a * x + b * y. C double precision zdotu(n,x,incx,y,incy) C BLAS-1 routine, computes y^H * x. C subroutine zqrdc(x,ldx,n,p,qraux,jpvt,work,job) C LINPACK routine, computes the QR factorization of x. C subroutine zqrsl(x,ldx,n,k,qraux,y,qy,qty,b,rsd,xb,job,info) C LINPACK routine, applies the QR factorization of x. C subroutine zsvdc(x,ldx,n,p,s,e,u,ldu,v,ldv,work,job,info) C LINPACK routine, computes the SVD of x. C subroutine zslal2 (ndim,nlen,m,zwk,dwk,iwk,idx,vecs) C Forces closure of an inner block. C double precision zslalh(i,n) C User-supplied routine, computes inner recurrence coefficients. C C Noel M. Nachtigal C July 9, 1993 C c********************************************************************** C INTRINSIC CDABS, DABS, DCMPLX, DMAX1, DREAL, MAX0 EXTERNAL DLAMCH, DZNRM2, ZAXPBY, ZDOTU, ZQRDC, ZQRSL, ZSVDC EXTERNAL ZSLAL2, ZSLALH DOUBLE COMPLEX ZDOTU, ZSLALH DOUBLE PRECISION DLAMCH, DZNRM2 C INTEGER IERR, L, LSTAR, M, MAXVW, N, NDIM, NL, NLEN, NLSTAR INTEGER IDX(3,3), IWK(M,4), NUMCHK, VF DOUBLE COMPLEX VECS(NDIM,1*MAXVW+2+1), ZWK(M,5*M+3) DOUBLE PRECISION ADJUST, NORM1, NORMA, TMAX, TMIN, TNRM DOUBLE PRECISION DWK(M,4) C C Miscellaneous parameters. C DOUBLE COMPLEX ZONE, ZZERO PARAMETER (ZONE = (1.0D0,0.0D0),ZZERO = (0.0D0,0.0D0)) DOUBLE PRECISION DONE, DZERO PARAMETER (DONE = 1.0D0,DZERO = 0.0D0) C C Local variables. C INTEGER I, IJ, J, LBLKSZ, NP1 DOUBLE COMPLEX ZTMP, ZTMP1, ZTMP2 DOUBLE PRECISION DTMP, DTMP1, DTMP2, DTMP3, DTMP4 DOUBLE PRECISION IDTMP1, IDTMP2, IDTMP3, IDTMP4 LOGICAL IBUILT, INNER, RERUN C C Initialize local variables. C NP1 = N + 1 DWK(IDX(1,N),4) = DZERO RERUN = .FALSE. IBUILT = .FALSE. IERR = 0 LBLKSZ = N - NL + 1 C C Update the norm estimates. C IF (N.LE.NUMCHK) THEN DTMP1 = DZNRM2(NLEN,VECS(1,1),1) * DWK(IDX(1,N),2) CSYM DTMP2 = DZNRM2(NLEN,VECS(1,1),1) * DWK(IDX(1,N),3) DTMP2 = DTMP1 NORMA = DMAX1(DTMP1,DTMP2,NORMA) END IF NORM1 = DMAX1(ADJUST*NORMA,NORM1) C C Clear current column of H. C DO 100 I = 1, M ZWK(IDX(1,I),2*M+IDX(1,N)) = ZZERO 100 CONTINUE C C Update D^{(n-1)} to D^{(n)}. C DO 120 I = NL, N-1 ZTMP = ZZERO DO 110 J = NL, N-1 ZTMP = ZTMP + ZWK(IDX(1,I),IDX(1,J)) * ZWK(IDX(1,J),2*M+ $IDX(1,N-1)) 110 CONTINUE ZTMP = ( ZWK(IDX(1,I),M+IDX(1,N-1)) - ZTMP ) / ZWK(IDX(1,N) $,2*M+IDX(1,N-1)) ZWK(IDX(1,I),IDX(1,N)) = ZTMP ZWK(IDX(1,N),IDX(1,I)) = ZTMP * DWK(IDX(1,N),1) / DWK(IDX(1,I), $1) 120 CONTINUE C C Compute l^\star. C LSTAR = MAX0(1,L-1) NLSTAR = IWK(IDX(1,LSTAR+1),1) C C Compute F_{n,1:n-1} and F_{1:n-1,n}. Delay computing F_{nn}. C DO 140 I = MAX0(1,NL-1), N-1 ZTMP = ZZERO DO 130 J = NL, I+1 ZTMP = ZTMP + ZWK(IDX(1,N),IDX(1,J)) * ZWK(IDX(1,J),2*M+ $IDX(1,I)) 130 CONTINUE ZWK(IDX(1,N),M+IDX(1,I)) = ZTMP ZWK(IDX(1,I),M+IDX(1,N)) = ZTMP * DWK(IDX(1,I),1) / DWK(IDX(1,N $),1) NORMA = DMAX1(NORMA,CDABS(ZWK(IDX(1,N),M+IDX(1,I))), $CDABS(ZWK(IDX(1,I),M+IDX(1,N)))) NORM1 = DMAX1(ADJUST*NORMA,NORM1) 140 CONTINUE C C Check whether D_l is nonsingular. C IF (LBLKSZ.EQ.1) THEN INNER = CDABS(ZWK(IDX(1,NL),IDX(1,NL))).EQ.DZERO ELSE DO 160 I = NL, N DO 150 J = NL, N ZWK(I-NL+1,4*M+J-NL+1) = ZWK(IDX(1,I),IDX(1,J)) 150 CONTINUE 160 CONTINUE CALL ZSVDC (ZWK(1,4*M+1),M,LBLKSZ,LBLKSZ,ZWK(1,5*M+1),ZWK(1,5*M $+3),ZZERO,0,ZZERO,0,ZWK(1,5*M+2),0,I) IF (I.NE.0) THEN IERR = -I GOTO 370 END IF DTMP = DZERO IF (DREAL(ZWK(1,5*M+1)).NE.DZERO) THEN DTMP = DABS( DREAL(ZWK(LBLKSZ,5*M+1)) / DREAL(ZWK(1,5*M+1))) END IF INNER = DTMP.LT.(DBLE(NLEN) * DLAMCH('E')) END IF IF ((VF.NE.0).AND.INNER) $ WRITE (VF,'(A31)') '... moment matrix D is singular' C C Compute H_{n_{l-1}:n_l-1,n}, for n_l > 1. C Also, build the part common to both inner and regular vectors. C Assume that VECS(1,1) = A v_n and VECS(1,1) = A^T w_n. C ZWK(IDX(1,NP1),2*M+IDX(1,N)) = ZZERO IF (NL.EQ.1) GO TO 180 IF (NL.EQ.NLSTAR+1) THEN ZWK(IDX(1,NLSTAR),2*M+IDX(1,N)) = ZWK(IDX(1,NLSTAR),M+IDX(1,N)) $ / ZWK(IDX(1,NLSTAR),IDX(1,NLSTAR)) ZTMP = ZWK(IDX(1,NLSTAR),2*M+IDX(1,N)) * DWK(IDX(1,NLSTAR),2) / $ DWK(IDX(1,N),2) CALL ZAXPBY (NLEN,VECS(1,1),ZONE,VECS(1,1),-ZTMP,VECS(1,IDX(2, $NLSTAR))) ZTMP = ZWK(IDX(1,NLSTAR),2*M+IDX(1,N)) * DWK(IDX(1,NLSTAR),3) / $ DWK(IDX(1,N),3) * DWK(IDX(1,N),1) / DWK(IDX(1,NLSTAR),1) CSYM CALL ZAXPBY (NLEN,VECS(1,1),ZONE,VECS(1,1),-ZTMP,VECS(1,IDX(3,NLSTAR))) ELSE IF (NL.GT.NLSTAR+1) THEN C C If a block of size larger than 1 was just closed, combine all its C vectors into one. C ZTMP2 = ZZERO DO 170 I = NL-1, NLSTAR, -1 ZWK(IDX(1,I),2*M+IDX(1,N)) = ZWK(IDX(1,NL-1),M+IDX(1,N)) * $ZWK(IDX(1,I),3*M+IDX(1,L-1)) IF (N.NE.NL) GO TO 170 ZTMP1 = ZWK(IDX(1,I),3*M+IDX(1,L-1)) * DWK(IDX(1,I),2) CALL ZAXPBY (NLEN,VECS(1,IDX(2,NL-1)),ZTMP2,VECS(1,IDX(2,NL- $1)),ZTMP1,VECS(1,IDX(2,I))) ZTMP1 = ZWK(IDX(1,I),3*M+IDX(1,L-1)) * DWK(IDX(1,I),3) / $DWK(IDX(1,I),1) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NL-1)),ZTMP2,VECS(1,IDX(3,NL-1)),ZTMP1,VECS(1,IDX(3,I))) ZTMP2 = ZONE 170 CONTINUE ZTMP1 = ZWK(IDX(1,NL-1),M+IDX(1,N)) / DWK(IDX(1,N),2) CALL ZAXPBY (NLEN,VECS(1,1),ZONE,VECS(1,1),-ZTMP1,VECS(1,IDX(2, $NL-1))) ZTMP1 = ZWK(IDX(1,NL-1),M+IDX(1,N)) * DWK(IDX(1,N),1) / $DWK(IDX(1,N),3) CSYM CALL ZAXPBY (NLEN,VECS(1,1),ZONE,VECS(1,1),-ZTMP1,VECS(1,IDX(3,NL-1))) END IF C C Compute F_{nn}. C 180 ZWK(IDX(1,N),M+IDX(1,N)) = ZDOTU(NLEN,VECS(1,IDX(3,N)),1,VECS(1,1) $,1) * DWK(IDX(1,N),2) * DWK(IDX(1,N),3) NORMA = DMAX1(NORMA,CDABS(ZWK(IDX(1,N),M+IDX(1,N)))) NORM1 = DMAX1(ADJUST*NORMA,NORM1) IF (INNER) GO TO 320 C C Compute H_{n_l:n,n}. C IWK(IDX(1,L+1+1),1) = NP1 IF (LBLKSZ.EQ.1) THEN ZWK(IDX(1,NL),2*M+IDX(1,N)) = ZWK(IDX(1,NL),M+IDX(1,N)) / $ZWK(IDX(1,NL),IDX(1,NL)) ELSE DO 200 J = NL, N ZWK(J-NL+1,5*M+1) = ZWK(IDX(1,J),M+IDX(1,N)) DO 190 IJ = NL, N ZWK(J-NL+1,4*M+IJ-NL+1) = ZWK(IDX(1,J),IDX(1,IJ)) 190 CONTINUE 200 CONTINUE CALL ZQRDC (ZWK(1,4*M+1),M,LBLKSZ,LBLKSZ,ZWK(1,5*M+3),0,ZZERO,0 $) CALL ZQRSL (ZWK(1,4*M+1),M,LBLKSZ,LBLKSZ,ZWK(1,5*M+3),ZWK(1,5*M $+1), $ ZZERO,ZWK(1,5*M+1),ZWK(1,5*M+2),ZWK(1,5*M+1),ZZERO, $100,J) DO 210 J = NL, N ZWK(IDX(1,J),2*M+IDX(1,N)) = ZWK(J-NL+1,5*M+2) 210 CONTINUE END IF C C Either D_l is nonsingular, or VW is being rerun. For the latter, C just finish building the vectors. For the former, the check for C H_{n_{l-1}:n,n} could be done. However, the look-ahead strategy C requires the smaller of the norm checks for H_{n_{l-1}:n,n} and C H_{n_l:n,n+1}, so both norms are computed first and then checked. C C Build regular vectors. C CALL ZAXPBY (NLEN,VECS(1,IDX(2,NP1)),ZONE,VECS(1,1),-ZWK(IDX(1,N), $2*M+IDX(1,N)),VECS(1,IDX(2,N))) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NP1)),ZONE,VECS(1,1),-ZWK(IDX(1,N),2*M+IDX(1,N)),VECS(1,IDX(3,N))) DO 220 I = NL, N-1 ZTMP = ZWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),2) / DWK(IDX(1 $,N),2) CALL ZAXPBY (NLEN,VECS(1,IDX(2,NP1)),ZONE,VECS(1,IDX(2,NP1)),- $ZTMP,VECS(1,IDX(2,I))) ZTMP = ZWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),3) / DWK(IDX(1 $,N),3) * DWK(IDX(1,N),1) / DWK(IDX(1,I),1) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NP1)),ZONE,VECS(1,IDX(3,NP1)),-ZTMP,VECS(1,IDX(3,I))) 220 CONTINUE C C Compute scale factors for the new vectors. C 230 DTMP3 = DZNRM2(NLEN,VECS(1,IDX(2,NP1)),1) CSYM DTMP4 = DZNRM2(NLEN,VECS(1,IDX(3,NP1)),1) DTMP4 = DTMP3 DTMP1 = DWK(IDX(1,N),2) * DTMP3 DTMP2 = DWK(IDX(1,N),3) * DTMP4 ZWK(IDX(1,NP1),2*M+IDX(1,N)) = DCMPLX(DTMP1,DZERO) IF (DTMP1.LT.TNRM) IERR = IERR + 16 IF (DTMP2.LT.TNRM) IERR = IERR + 32 IF (IERR.NE.0) GOTO 360 DWK(IDX(1,NP1),1) = DWK(IDX(1,N),1) * DTMP1 / DTMP2 ZWK(IDX(1,NP1),IDX(1,NP1)) = ZDOTU(NLEN,VECS(1,IDX(3,NP1)),1, $VECS(1,IDX(2,NP1)),1) / ( DTMP3 * DTMP4 ) IF ((DTMP3.GE.TMAX).OR.(DTMP3.LE.TMIN)) THEN ZTMP = DCMPLX(DONE / DTMP3,DZERO) CALL ZAXPBY (NLEN,VECS(1,IDX(2,NP1)),ZTMP,VECS(1,IDX(2,NP1)), $ZZERO,VECS(1,IDX(2,NP1))) DTMP3 = DONE END IF IF ((DTMP4.GE.TMAX).OR.(DTMP4.LE.TMIN)) THEN ZTMP = DCMPLX(DONE / DTMP4,DZERO) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NP1)),ZTMP,VECS(1,IDX(3,NP1)),ZZERO,VECS(1,IDX(3,NP1))) DTMP4 = DONE END IF DWK(IDX(1,NP1),2) = DONE / DTMP3 DWK(IDX(1,NP1),3) = DONE / DTMP4 C C Compute the last column of D_l^{-1}. C IF (LBLKSZ.EQ.1) THEN ZWK(IDX(1,NL),3*M+IDX(1,L)) = ZONE / ZWK(IDX(1,NL),IDX(1,NL)) ELSE DO 240 I = 1, LBLKSZ-1 ZWK(I,5*M+1) = ZZERO 240 CONTINUE ZWK(LBLKSZ,5*M+1) = ZONE CALL ZQRSL (ZWK(1,4*M+1),M,LBLKSZ,LBLKSZ,ZWK(1,5*M+3),ZWK(1,5*M $+1), $ ZZERO,ZWK(1,5*M+1),ZWK(1,5*M+2),ZWK(1,5*M+1),ZZERO, $100,J) DO 250 I = NL, N ZWK(IDX(1,I),3*M+IDX(1,L)) = ZWK(I-NL+1,5*M+2) 250 CONTINUE END IF C C If VW is being rerun, then skip to the end. C IF (RERUN) GO TO 360 C C Compute the norm of H_{n_{l-1}:n,n}. C DTMP1 = DZERO DTMP2 = DZERO DO 260 I = IWK(IDX(1,L-1+1),1), N DTMP = CDABS(ZWK(IDX(1,I),2*M+IDX(1,N))) DTMP1 = DTMP1 + DTMP DTMP2 = DTMP2 + DTMP / DWK(IDX(1,I),1) 260 CONTINUE DTMP2 = DTMP2 * DWK(IDX(1,N),1) C C Build the 2nd term for the next step, H_{n_l:n,n+1}, regular. C Compute the norm of H_{n_l:n,n+1}. C DTMP3 = DZERO DTMP4 = DZERO ZTMP = ZWK(IDX(1,NP1),IDX(1,NP1)) * ZWK(IDX(1,NP1),2*M+IDX(1,N)) $* DWK(IDX(1,N),1) / DWK(IDX(1,NP1),1) DO 270 I = NL, N DTMP = CDABS(ZTMP * ZWK(IDX(1,I),3*M+IDX(1,L))) DTMP3 = DTMP3 + DTMP DTMP4 = DTMP4 + DTMP / DWK(IDX(1,I),1) 270 CONTINUE DTMP4 = DTMP4 * DWK(IDX(1,NP1),1) C C Check H_{n_{l-1}:n,n} and H_{n_l:n-1,n+1}. C DTMP = DMAX1(DTMP1,DTMP2,DTMP3,DTMP4) INNER = DTMP.GT.NORM1 IF (.NOT.INNER) GO TO 360 DWK(IDX(1,N),4) = DTMP C C If H_{n_{l-1}:n,n} is bad, build inner vectors. C IF (DMAX1(DTMP1,DTMP2).GT.NORM1) GO TO 320 C C If H_{n_l:n-1,n+1} is bad, check the inner vectors. C This only applies if n_l > 1. C IF (NL.LE.1) GO TO 320 C C Build the inner vectors to compute the 2nd term at the next step. C Get the coefficients H_{n_l:n+1,n} in a temporary location. C Build inner vectors in VECS(1,1) and VECS(1,1). C IBUILT = .TRUE. DO 280 I = NL, N ZWK(IDX(1,I),2*M+IDX(1,NP1)) = ZSLALH(I,N) ZTMP = ZWK(IDX(1,I),2*M+IDX(1,NP1)) * DWK(IDX(1,I),2) / $DWK(IDX(1,N),2) CALL ZAXPBY (NLEN,VECS(1,1),ZONE,VECS(1,1),-ZTMP,VECS(1,IDX(2,I $))) ZTMP = ZWK(IDX(1,I),2*M+IDX(1,NP1)) * DWK(IDX(1,I),3) / $DWK(IDX(1,N),3) * DWK(IDX(1,N),1) / DWK(IDX(1,I),1) CSYM CALL ZAXPBY (NLEN,VECS(1,1),ZONE,VECS(1,1),-ZTMP,VECS(1,IDX(3,I))) 280 CONTINUE IDTMP3 = DZNRM2(NLEN,VECS(1,1),1) CSYM IDTMP4 = DZNRM2(NLEN,VECS(1,1),1) IDTMP4 = IDTMP3 IDTMP1 = DWK(IDX(1,N),2) * IDTMP3 IDTMP2 = DWK(IDX(1,N),3) * IDTMP4 ZWK(IDX(1,NP1),2*M+IDX(1,NP1)) = DCMPLX(IDTMP1,DZERO) IF (IDTMP1.LT.TNRM) IERR = IERR + 16 IF (IDTMP2.LT.TNRM) IERR = IERR + 32 IF (IERR.NE.0) GOTO 330 C C Build the 2nd term for the next step, H_{n_{l-1}:n_l-1,n+1}, C inner. Compute the norm of H_{n_{l-1}:n_l-1,n+1}. C ZTMP = ZZERO DO 290 J = NLSTAR, NL-1 ZTMP = ZTMP + ZWK(IDX(1,NL),IDX(1,J)) * ZWK(IDX(1,I),2*M+IDX(1, $N)) 290 CONTINUE DO 300 J = NL, N ZTMP = ZTMP + ZWK(IDX(1,NL),IDX(1,J)) * ZWK(IDX(1,I),2*M+IDX(1, $NP1)) 300 CONTINUE DTMP1 = DZERO DTMP2 = DZERO DTMP3 = DMAX1(DTMP3,DTMP4) ZTMP = ( ZWK(IDX(1,NL),M+IDX(1,N)) - ZTMP ) / ZWK(IDX(1,NP1),2*M+ $IDX(1,NP1)) ZTMP = ZTMP * ZWK(IDX(1,NL),2*M+IDX(1,NL-1)) * DWK(IDX(1,NL-1),1) $ / DWK(IDX(1,NL),1) DO 310 I = IWK(IDX(1,L-1+1),1), NL-1 DTMP = CDABS(ZWK(IDX(1,I),3*M+IDX(1,L-1)) * ZTMP) DTMP1 = DTMP1 + DTMP DTMP2 = DTMP2 + DTMP / DWK(IDX(1,I),1) 310 CONTINUE DTMP2 = DTMP2 * DWK(IDX(1,N),1) C C Compare the inner and regular versions of the 2nd term at the next C step. Build the vector corresponding to the smaller term. C INNER = DTMP3.GT.DMAX1(DTMP1,DTMP2) IF (.NOT.INNER) GO TO 360 C C Build inner vectors. C Check whether the block has to be forced to close. C 320 IF (VF.NE.0) WRITE (VF,'(A7,I5,A9)') 'Vector ',NP1,' is inner' IF (NP1-NL.EQ.MAXVW) THEN CALL ZSLAL2 (NDIM,NLEN,M,N,L,LSTAR,NL,NLSTAR,VF,IERR,ADJUST, $ NORM1,ZWK,DWK,IWK,IDX,VECS) IF (IERR.NE.0) GO TO 370 LBLKSZ = N - NL + 1 INNER = .FALSE. RERUN = .TRUE. NP1 = N + 1 GO TO 230 END IF C C The temporary vectors contain either just partial inner vectors, C or the completed ones, depending on whether IBUILT is TRUE or C FALSE. In either case, replace the regular vectors. C 330 CALL ZAXPBY (NLEN,VECS(1,IDX(2,NP1)),ZONE,VECS(1,1),ZZERO,VECS(1, $IDX(2,NP1))) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NP1)),ZONE,VECS(1,1),ZZERO,VECS(1,IDX(3,NP1))) C C Get the coefficients H_{n_l:n+1,n} and build inner vectors. C IF (IBUILT) THEN DO 340 I = NL, NP1 ZWK(IDX(1,I),2*M+IDX(1,N)) = ZWK(IDX(1,I),2*M+IDX(1,NP1)) 340 CONTINUE DTMP1 = IDTMP1 DTMP2 = IDTMP2 DTMP3 = IDTMP3 DTMP4 = IDTMP4 ELSE DO 350 I = NL, N ZWK(IDX(1,I),2*M+IDX(1,N)) = ZSLALH(I,N) ZTMP = ZWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),2) / $DWK(IDX(1,N),2) CALL ZAXPBY (NLEN,VECS(1,IDX(2,NP1)),ZONE,VECS(1,IDX(2,NP1)) $,-ZTMP,VECS(1,IDX(2,I))) ZTMP = ZWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),3) / $DWK(IDX(1,N),3) * DWK(IDX(1,N),1) / DWK(IDX(1,I),1) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NP1)),ZONE,VECS(1,IDX(3,NP1)),-ZTMP,VECS(1,IDX(3,I))) 350 CONTINUE DTMP3 = DZNRM2(NLEN,VECS(1,IDX(2,NP1)),1) CSYM DTMP4 = DZNRM2(NLEN,VECS(1,IDX(3,NP1)),1) DTMP4 = DTMP3 DTMP1 = DWK(IDX(1,N),2) * DTMP3 DTMP2 = DWK(IDX(1,N),3) * DTMP4 END IF ZWK(IDX(1,NP1),2*M+IDX(1,N)) = DCMPLX(DTMP1,DZERO) IF (DTMP1.LT.TNRM) IERR = IERR + 16 IF (DTMP2.LT.TNRM) IERR = IERR + 32 IF (IERR.NE.0) GOTO 360 DWK(IDX(1,NP1),1) = DWK(IDX(1,N),1) * DTMP1 / DTMP2 ZWK(IDX(1,NP1),IDX(1,NP1)) = ZDOTU(NLEN,VECS(1,IDX(3,NP1)),1, $VECS(1,IDX(2,NP1)),1) / ( DTMP3 * DTMP4 ) IF ((DTMP3.GE.TMAX).OR.(DTMP3.LE.TMIN)) THEN ZTMP = DCMPLX(DONE / DTMP3,DZERO) CALL ZAXPBY (NLEN,VECS(1,IDX(2,NP1)),ZTMP,VECS(1,IDX(2,NP1)), $ZZERO,VECS(1,IDX(2,NP1))) DTMP3 = DONE END IF IF ((DTMP4.GE.TMAX).OR.(DTMP4.LE.TMIN)) THEN ZTMP = DCMPLX(DONE / DTMP4,DZERO) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NP1)),ZTMP,VECS(1,IDX(3,NP1)),ZZERO,VECS(1,IDX(3,NP1))) DTMP4 = DONE END IF DWK(IDX(1,NP1),2) = DONE / DTMP3 DWK(IDX(1,NP1),3) = DONE / DTMP4 C C If regular vectors were built, update the counters. C 360 IF (.NOT.INNER) THEN L = L + 1 NL = IWK(IDX(1,L+1),1) END IF C 370 RETURN END C C********************************************************************** C SUBROUTINE ZSLAL2 (NDIM,NLEN,M,N,L,LSTAR,NL,NLSTAR,VF,IERR, $ ADJUST,NORM1,ZWK,DWK,IWK,IDX,VECS) C C Purpose: C This subroutine rebuilds the data for vectors v_{n+1} and w_{n+1} C at the point where a block was forced to close. The routine is C called internally by the look-ahead Lanczos code and is not meant C to be called directly by the user code. C C Parameters: C See descriptions in "zulal.doc" or "zsqmr.doc". C C External routines used: C subroutine zaxpby(n,z,a,x,b,y) C Library routine, computes z = a * x + b * y. C subroutine zqrdc(x,ldx,n,p,qraux,jpvt,work,job) C LINPACK routine, computes the QR factorization of x. C subroutine zqrsl(x,ldx,n,k,qraux,y,qy,qty,b,rsd,xb,job,info) C LINPACK routine, applies the QR factorization of x. C C Noel M. Nachtigal C May 31, 1993 C C********************************************************************** C EXTERNAL ZAXPBY, ZQRDC, ZQRSL C INTEGER IERR, L, LSTAR, M, N, NDIM, NL, NLEN, NLSTAR INTEGER IDX(3,3), IWK(M,4), VF DOUBLE COMPLEX VECS(NDIM,*), ZWK(M,5*M+3) DOUBLE PRECISION ADJUST, DWK(M,4), NORM1 C C Miscellaneous parameters. C DOUBLE COMPLEX ZONE, ZZERO PARAMETER (ZONE = (1.0D0,0.0D0),ZZERO = (0.0D0,0.0D0)) DOUBLE PRECISION DZERO PARAMETER (DZERO = 0.0D0) C C Local variables. C INTEGER I, IJ, J, LBLKSZ, NP1 DOUBLE COMPLEX SCALV, SCALW, ZTMP1, ZTMP2 DOUBLE PRECISION DTMP1, DTMP2 C C Find the index of the vector pair with the smallest pass value. C IERR = 0 IF (VF.NE.0) WRITE (VF,'(A20)') 'block did not close:' J = NL DTMP1 = DWK(IDX(1,J),4) DO 100 I = NL+1, N DTMP2 = DWK(IDX(1,I),4) IF (DTMP2.GT.DZERO) THEN IF ((DTMP1.EQ.DZERO).OR.(DTMP2.LT.DTMP1)) THEN J = I DTMP1 = DTMP2 END IF END IF 100 CONTINUE IF (DTMP1.EQ.DZERO) THEN IF (VF.NE.0) WRITE (VF,'(A47)') $'... no new norm estimates available (aborting).' IERR = 8 RETURN END IF NORM1 = ADJUST * DTMP1 IF (VF.NE.0) WRITE (VF,'(A40,I5,E11.4)') $ '... updated norms, restarting from step:', IWK(IDX(1,J),3), $ NORM1 IF (IWK(IDX(1,J),3).EQ.N) RETURN N = IWK(IDX(1,J),3) L = IWK(IDX(1,N),4) NL = IWK(IDX(1,L+1),1) C C Initialize local variables. C NP1 = N + 1 DWK(IDX(1,N),4) = DZERO LBLKSZ = N - NL + 1 C C Compute l^\star. C LSTAR = L - 1 NLSTAR = IWK(IDX(1,LSTAR+1),1) C C Compute H_{n_l:n,n}. Save the old coefficients. C IWK(IDX(1,L+1+1),1) = NP1 IF (LBLKSZ.EQ.1) THEN ZWK(IDX(1,NL),2*M+IDX(1,NP1)) = ZWK(IDX(1,NL),2*M+IDX(1,N)) ZWK(IDX(1,NL),2*M+IDX(1,N)) = ZWK(IDX(1,NL),M+IDX(1,N)) / $ZWK(IDX(1,NL),IDX(1,NL)) ELSE DO 120 J = NL, N ZWK(J-NL+1,5*M+1) = ZWK(IDX(1,J),M+IDX(1,N)) DO 110 IJ = NL, N ZWK(J-NL+1,4*M+IJ-NL+1) = ZWK(IDX(1,J),IDX(1,IJ)) 110 CONTINUE 120 CONTINUE CALL ZQRDC (ZWK(1,4*M+1),M,LBLKSZ,LBLKSZ,ZWK(1,5*M+3),0,ZZERO,0 $) CALL ZQRSL (ZWK(1,4*M+1),M,LBLKSZ,LBLKSZ,ZWK(1,5*M+3),ZWK(1,5*M $+1), $ ZZERO,ZWK(1,5*M+1),ZWK(1,5*M+2),ZWK(1,5*M+1),ZZERO, $100,J) DO 130 J = NL, N ZWK(IDX(1,J),2*M+IDX(1,NP1)) = ZWK(IDX(1,J),2*M+IDX(1,N)) ZWK(IDX(1,J),2*M+IDX(1,N)) = ZWK(J-NL+1,5*M+2) 130 CONTINUE END IF C C Convert inner vectors to regular vectors. C SCALV = ZWK(IDX(1,NP1),2*M+IDX(1,N)) * DWK(IDX(1,NP1),2) SCALW = ZWK(IDX(1,NP1),2*M+IDX(1,N)) * DWK(IDX(1,NP1),3) * $DWK(IDX(1,N),1) / DWK(IDX(1,NP1),1) ZWK(IDX(1,NP1),2*M+IDX(1,N)) = ZZERO DO 140 I = NL, N ZTMP1 = ZWK(IDX(1,I),2*M+IDX(1,N)) - ZWK(IDX(1,I),2*M+IDX(1,NP1 $)) ZTMP2 = ZTMP1 * DWK(IDX(1,I),2) / SCALV CALL ZAXPBY (NLEN,VECS(1,IDX(2,NP1)),ZONE,VECS(1,IDX(2,NP1)),- $ZTMP2,VECS(1,IDX(2,I))) ZTMP2 = ZTMP1 * DWK(IDX(1,I),3) / SCALW * DWK(IDX(1,N),1) / $DWK(IDX(1,I),1) CSYM CALL ZAXPBY (NLEN,VECS(1,IDX(3,NP1)),ZONE,VECS(1,IDX(3,NP1)),-ZTMP2,VECS(1,IDX(3,I))) 140 CONTINUE C RETURN END C C**********************************************************************