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  QMR algorithm  for
C     symmetric  matrices, using  the three-term recurrence  variant of
C     the look-ahead Lanczos algorithm.
C
C**********************************************************************
C
      SUBROUTINE DSQMR (NDIM,NLEN,NLIM,MAXVW,M,NORM,DWK,IDX,IWK,
     $                  VECS,TOL,INFO)
C
C     Purpose:
C     This subroutine  uses the QMR algorithm based on  the three-term
C     variant  of the  look-ahead  Lanczos  process  to  solve  linear
C     systems.  It runs  the QMR algorithm  to convergence or  until a
C     user-specified iteration limit is reached. It is set up to solve
C     symmetric systems starting with identical starting vectors.
C
C     The  code is  set up  to solve  the system  A x = b  with initial
C     guess x_0 = 0.  Here  A x = b  denotes the preconditioned system,
C     and  it  is  connected with the  original system as follows.  Let
C     B y = c be the original unpreconditioned system to be solved, and
C     let y_0 be an arbitrary initial guess for its solution.  Then:
C          A x = b, where  A = M_1^{-1} B M_2^{-1},
C                          x = M_2 (y - y_0), b = M_1^{-1} (c - B y_0).
C     Here M = M_1 M_2 is the preconditioner.
C
C     To recover the final iterate y_n for  the original system B y = c
C     from the final iterate x_n for the preconditioned system A x = b,
C     set
C               y_n = y_0 + M_2^{-1} x_n.
C
C     The algorithm  was first described  in the RIACS Technical Report
C     90.46, `An Implementation of the Look-Ahead Lanczos Algorithm for
C     Non-Hermitian   Matrices,  Part  II`,  by  R.W. Freund  and  N.M.
C     Nachtigal, November 1990.
C
C     Parameters:
C     For a description of  the parameters, see the file "dsqmr.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 ddot(n,dx,incx,dy,incy)
C        BLAS-1 routine, computes y^H * x.
C     double precision dlamch(ch)
C        LAPACK routine, computes machine-related constants.
C     double precision dnrm2(n,dx,incx)
C        BLAS-1 routine, computes the 2-norm of x.
C     subroutine drandn(n,x,seed)
C        Library routine, fills x with random numbers.
C     subroutine drotg(da,db,dcos,dsin)
C        BLAS-1 routine, computes the Givens rotation which rotates the
C        vector [a; b] into [ sqrt(a**2 + b**2); 0 ].
C     subroutine dsqmr1(ndim,nlen,m,maxvw,numchk,n,l,lstar,nl,nlstar,vf,
C        ierr,adjust,norm1,norma,tmax,tnrm,dwk,iwk,idx,vecs)
C        Low-level routine, builds the vectors v_{n+1} and w_{n+1}.
C     double precision dsqmro(n)
C        User-supplied routine, specifies the QMR scaling factors.
C
C     Noel M. Nachtigal
C     October 24, 1990
C
C**********************************************************************
C
      INTRINSIC DABS, DBLE, DMAX1, DSQRT, MAX0, MIN0, MOD
      EXTERNAL DAXPBY, DDOT, DLAMCH, DNRM2, DRANDN, DROTG, DSQMR1
      EXTERNAL DSQMRO
      DOUBLE PRECISION DDOT, DLAMCH, DNRM2, DSQMRO
C
      INTEGER INFO(4), M, MAXVW, NDIM, NLEN, NLIM
      INTEGER IDX(3,NLIM+2), IWK(M,4)
      DOUBLE PRECISION DWK(M,5*M+13), NORM, TOL
      DOUBLE PRECISION VECS(NDIM,3*MAXVW+2+3)
C
C     Common block variables.
C
C
C     Common block DSQMRX.
C
      DOUBLE PRECISION NORMA
      COMMON /DSQMRX/NORMA
C
C     Miscellaneous parameters.
C
      DOUBLE PRECISION DHUN, DONE, DTEN, DZERO
      PARAMETER (DHUN = 1.0D2,DONE = 1.0D0,DTEN = 1.0D1,DZERO = 0.0D0)
C
C     Local variables, permanent.
C
      INTEGER IERR, IEND, L, LSTAR, MVWBLT, N, NL, NLSTAR, NMAX, NQMR
      SAVE    IERR, IEND, L, LSTAR, MVWBLT, N, NL, NLSTAR, NMAX, NQMR
      INTEGER NUMCHK, RETLBL, TF, TRES, VF
      SAVE    NUMCHK, RETLBL, TF, TRES, VF
      DOUBLE PRECISION ADJUST, MAXOMG, NORM1, R0, RESN, TMAX, TMIN
      SAVE             ADJUST, MAXOMG, NORM1, R0, RESN, TMAX, TMIN
      DOUBLE PRECISION TNRM, UCHK, UNRM
      SAVE             TNRM, UCHK, UNRM
C
C     Local variables, transient.
C
      INTEGER I, IBASE, INIT, ISJ, ISN, J, REVCOM
      DOUBLE PRECISION DTMP, DTMP1, DTMP2
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       40    returning from AXB, go to label 40
C           1      100    returning from AXB, go to label 100
C           2       50    returning from ATXB, go to label 50
C
      REVCOM  = INFO(2)
      INFO(2) = 0
      IF (REVCOM.EQ.0) THEN
         N      = 0
         NQMR   = 0
         MVWBLT = 0
         IF (RETLBL.EQ.0) GO TO 10
      ELSE IF (REVCOM.EQ.1) THEN
         IF (RETLBL.EQ.40) THEN
            GO TO 40
         ELSE IF (RETLBL.EQ.100) THEN
            GO TO 100
         END IF
      ELSE IF (REVCOM.EQ.2) THEN
         IF (RETLBL.EQ.50) GO TO 50
      END IF
      IERR = 1
      GO TO 130
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 (M.LT.2*MAXVW+2)  IERR = 2
      IF (IERR.NE.0) GO TO 130
C
C     Extract from INFO the output units TF and VF, the true residual
C     flag TRES, and the left starting vector flag INIT.
C
      VF   = MAX0(INFO(1),0)
      INIT = VF / 100000
      VF   = VF - INIT * 100000
      TRES = VF / 10000
      VF   = VF - TRES * 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
      IF (TOL.LE.DZERO) TOL = DSQRT(DLAMCH('E'))
C
C     Start the trace messages and convergence history.
C
      IF (VF.NE.0) WRITE (VF,'(I8,2E11.4)') 0, DONE, DONE
      IF (TF.NE.0) WRITE (TF,'(I8,2E11.4)') 0, DONE, DONE
C
C     Set up wrapped indices.  The following indices are used:
C        IDX(1,I) = indices used for the work arrays 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) = 3 + 1 + 0*(MAXVW+2) + MOD(I-1,MAXVW+2)
         IDX(3,I) = IDX(2,I)
 20   CONTINUE
C
C     Set x_0 = 0 and compute the norm of the initial residual.
C
      CALL DAXPBY (NLEN,VECS(1,IDX(2,1)),DONE,VECS(1,2),DZERO,VECS(1,
     $IDX(2,1)))
      CALL DAXPBY (NLEN,VECS(1,1),DZERO,VECS(1,1),DZERO,VECS(1,1))
      R0 = DNRM2(NLEN,VECS(1,IDX(2,1)),1)
      IF ((TOL.GE.DONE).OR.(R0.EQ.DZERO)) GO TO 130
C
C     Check whether the auxiliary vector must be supplied.
C
CSYM  IF (INIT.EQ.0) CALL DRANDN (NLEN,VECS(1,3),1)
CSYM  CALL DAXPBY (NLEN,VECS(1,IDX(3,1)),DONE,VECS(1,3),DZERO,VECS(1,IDX(3,1)))
C
C     Scale the first pair of Lanczos vectors and check for invariant
C     subspaces.
C
      DTMP1 = R0
CSYM  DTMP2 = DNRM2(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 130
      DWK(IDX(1,1),5*M+8)   = DONE
      DWK(IDX(1,1),IDX(1,1)) = DDOT(NLEN,VECS(1,IDX(2,1)),1,VECS(1,IDX(3
     $,1)),1) / ( DTMP1 * DTMP2 )
      IF ((DTMP1.GE.TMAX).OR.(DTMP1.LE.TMIN)) THEN
         DTMP = DONE / DTMP1
         CALL DAXPBY (NLEN,VECS(1,IDX(2,1)),DTMP,VECS(1,IDX(2,1)),DZERO,
     $VECS(1,IDX(2,1)))
         DTMP1 = DONE
      END IF
      IF ((DTMP2.GE.TMAX).OR.(DTMP2.LE.TMIN)) THEN
         DTMP = DONE / DTMP2
CSYM     CALL DAXPBY (NLEN,VECS(1,IDX(3,1)),DTMP,VECS(1,IDX(3,1)),DZERO,VECS(1,IDX(3,1)))
         DTMP2 = DONE
      END IF
      DWK(IDX(1,1),5*M+9) = DONE / DTMP1
      DWK(IDX(1,1),5*M+10) = DONE / DTMP2
C
C     Initialize the counters.
C
      L      = 1
      N      = 1
      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     Set up the QMR iteration.
C
      RESN   = DONE
      DWK(IDX(1,1),5*M+12) = DSQMRO(1)
      DWK(IDX(1,1),5*M+4) = DWK(IDX(1,1),5*M+12) * R0
      MAXOMG = DONE / DWK(IDX(1,1),5*M+12)
C
C     This is one step of the three-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
 30   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,3))
C
      INFO(2) = 1
      INFO(3) = IDX(2,N)
      INFO(4) = 3
      RETLBL  = 40
      RETURN
C
C     Have the caller carry out ATXB, then return here.
C        CALL ATXB (VECS(1,IDX(3,N)),VECS(1,3))
C
 40   INFO(2) = 2
      INFO(3) = IDX(3,N)
      INFO(4) = 4
      RETLBL  = 50
CSYM  RETURN
 50   IF ((VF.NE.0).AND.(N.LE.NMAX)) WRITE (VF,'(A11,I8)')
     $    'Rebuilding:', N+1
      CALL DSQMR1 (NDIM,NLEN,M,MAXVW,NUMCHK,N,L,LSTAR,NL,NLSTAR,VF,IERR,
     $            ADJUST,NORM1,NORMA,TMAX,TMIN,TNRM,DWK,IWK,IDX,VECS)
      IF ((IERR.NE.0).AND.(IERR.NE.16).AND.(IERR.NE.32)
     $    .AND.(IERR.NE.48)) GO TO 130
      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
      NMAX = MAX0(NMAX,N)
      IF (N.LT.NL-1) GO TO 120
C
C     The QMR code starts here.
C     At this point, steps up to NL-1 are guaranteed not to be rebuilt.
C     No errors are allowed in IERR,  other than possibly  having found
C     one  or both  invariant subspaces,  in which  case  all remaining
C     iterates are computed.
C
      IEND = NL-1
      IF (IERR.NE.0) IEND = N
 60   IF (NQMR.GT.IEND-1) GO TO 120
C
C     Update the QMR iteration counter.
C
      NQMR = NQMR + 1
C
C     Get the next scaling factor omega(i) and update MAXOMG.
C
      DWK(IDX(1,NQMR+1),5*M+12) = DSQMRO(NQMR+1)
      MAXOMG      = DMAX1(MAXOMG,DONE/DWK(IDX(1,NQMR+1),5*M+12))
C
C     Compute the starting index IBASE for the column of \hat{R}.
C
      IBASE       = MAX0(1,IWK(IDX(1,NQMR),2)-1)
      DWK(IDX(1,IBASE),5*M+5) = DZERO
C
C     Multiply the new column by the previous omegas.
C
      DO 70 J = IWK(IDX(1,NQMR),2), NQMR+1
         DWK(IDX(1,J),5*M+5) = DWK(IDX(1,J),5*M+12) * DWK(IDX(1,J),2*M+
     $IDX(1,NQMR))
 70   CONTINUE
C
C     Apply the previous rotations.
C     The loop below explicitly implements a call to DROT:
C     CALL DROT (1,DWK(IDX(1,J-1),5*M+5),1,DWK(IDX(1,J),5*M+5),1,DWK(IDX(1,J),5*M+13),DWK(IDX(1,J),5*M+6))
C
      DO 80 J = IBASE+1, NQMR
         DTMP1     = DWK(IDX(1,J),5*M+5)
         DTMP2     = DWK(IDX(1,J-1),5*M+5)
         DWK(IDX(1,J-1),5*M+5) = DWK(IDX(1,J),5*M+13) * DTMP2 +
     $DWK(IDX(1,J),5*M+6) * DTMP1
         DWK(IDX(1,J),5*M+5)   = DWK(IDX(1,J),5*M+13) * DTMP1 -
     $DWK(IDX(1,J),5*M+6) * DTMP2
 80   CONTINUE
C
C     Compute the rotation for the last element (this also applies it).
C
      CALL DROTG (DWK(IDX(1,NQMR),5*M+5),DWK(IDX(1,NQMR+1),5*M+5),
     $DWK(IDX(1,NQMR+1),5*M+13),DWK(IDX(1,NQMR+1),5*M+6))
C
C     Apply the new rotation to the right-hand side vector.
C     Could be replaced with:
C     DWK(IDX(1,NQMR+1),5*M+4) = DZERO
C     CALL DROT (1,DWK(IDX(1,NQMR),5*M+4),1,DWK(IDX(1,NQMR+1),5*M+4),1,DWK(IDX(1,NQMR+1),5*M+13),DWK(IDX(1,NQMR+1),5*M+6))
C
      DWK(IDX(1,NQMR+1),5*M+4) = -DWK(IDX(1,NQMR+1),5*M+6) * DWK(IDX(1,
     $NQMR),5*M+4)
      DWK(IDX(1,NQMR),5*M+4)   =  DWK(IDX(1,NQMR+1),5*M+13) * DWK(IDX(1,
     $NQMR),5*M+4)
C
C     Compute the next search direction s_i.
C     This is more complicated than it might have to be because storage
C     for the vectors VECS(1,ISN) is minimized.
C
      DTMP2 = DZERO
      DTMP  = DWK(IDX(1,NQMR),5*M+9)
      ISN   = 3 + 1 + MAXVW+2 + MOD(NQMR-1,2*MAXVW)
      DO 90 J = IBASE, NQMR-1
         DTMP1 = DWK(IDX(1,J),5*M+5) * DWK(IDX(1,J),5*M+7) / DTMP
         IF (DTMP1.EQ.DZERO) GO TO 90
         ISJ   = 3 + 1 + MAXVW+2 + MOD(J-1,2*MAXVW)
         CALL DAXPBY (NLEN,VECS(1,ISN),DTMP2,VECS(1,ISN),-DTMP1,VECS(1,
     $ISJ))
         DTMP2 = DONE
 90   CONTINUE
      CALL DAXPBY (NLEN,VECS(1,ISN),DTMP2,VECS(1,ISN),DONE,VECS(1,IDX(2,
     $NQMR)))
      DTMP = DTMP / DWK(IDX(1,NQMR),5*M+5)
C
C     Compute the new QMR iterate, then scale the search direction.
C
      DTMP1 = DTMP * DWK(IDX(1,NQMR),5*M+4)
      CALL DAXPBY (NLEN,VECS(1,1),DONE,VECS(1,1),DTMP1,VECS(1,ISN))
      DWK(IDX(1,NQMR),5*M+7) = DTMP
      DTMP      = DABS(DTMP)
      IF ((DTMP.GE.TMAX).OR.(DTMP.LE.TMIN)) THEN
         DWK(IDX(1,NQMR),5*M+7) = DONE
         CALL DAXPBY (NLEN,VECS(1,ISN),DTMP,VECS(1,ISN),DZERO,VECS(1,ISN
     $))
      END IF
C
C     Compute the residual norm upper bound.
C     If the scaled upper bound is within one order of magnitude of the
C     target convergence norm, compute the true residual norm.
C
      UNRM = DSQRT(DBLE(NQMR+1)) * MAXOMG * DABS(DWK(IDX(1,NQMR+1),5*M+4
     $)) / R0
      UCHK = UNRM
      IF ((TRES.EQ.0).AND.(UNRM/TOL.GT.DTEN).AND.(N.LT.NLIM)) GO TO 110
C
C     Have the caller carry out AXB, then return here.
C        CALL AXB (VECS(1,1),VECS(1,3))
C
      INFO(2) = 1
      INFO(3) = 1
      INFO(4) = 3
      RETLBL  = 100
      RETURN
 100  CALL DAXPBY (NLEN,VECS(1,3),DONE,VECS(1,2),-DONE,VECS(1,3))
      RESN = DNRM2(NLEN,VECS(1,3),1) / R0
      UCHK = RESN
C
C     Output the convergence history.
C
 110  IF (VF.NE.0) WRITE (VF,'(I8,2E11.4)') NQMR, UNRM, RESN
      IF (TF.NE.0) WRITE (TF,'(I8,2E11.4)') NQMR, UNRM, RESN
C
C     Check for convergence or termination.  Stop if:
C         1. algorithm converged;
C         2. there is an error condition;
C         3. the residual norm upper bound is smaller than the computed
C     residual norm by a factor of at least 100;
C         4. algorithm exceeded the iterations limit.
C
      IF (RESN.LE.TOL) THEN
         IERR = 0
         GO TO 130
      ELSE IF (IERR.NE.0) THEN
         GO TO 130
      ELSE IF (UNRM.LT.UCHK/DHUN) THEN
         IERR = 4
         GO TO 130
      ELSE IF (NQMR.GE.NLIM) THEN
         IERR = 4
         GO TO 130
      END IF
      GO TO 60
C
C     Update the running counter.
C
 120  IF (IERR.NE.0) GO TO 130
      IERR = 4
      IF (N.GE.NLIM) GO TO 130
      N = N + 1
      GO TO 30
C
C     Done.
C
 130  RETLBL  = 0
      NLIM    = NQMR
      INFO(1) = IERR
      NORM    = NORM1
      MAXVW   = MVWBLT
C
      RETURN
      END
C
C**********************************************************************
C
      DOUBLE PRECISION FUNCTION DSQMRH(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 DSQMRX.
C
      DOUBLE PRECISION NORMA
      COMMON /DSQMRX/NORMA
C
C
      INTEGER I, J
C
      IF ((I.LT.1).OR.(J.LT.1)) THEN
         DSQMRH = 0.0D0
      ELSE IF (I.EQ.J) THEN
         DSQMRH = NORMA
      ELSE
         DSQMRH = 0.0D0
      END IF
C
      RETURN
      END
C
C**********************************************************************
C
      DOUBLE PRECISION FUNCTION DSQMRO (I)
C
C     Purpose:
C     Returns the scaling parameter OMEGA(I).
C
C     Parameters:
C     I = the index of the parameter OMEGA (input).
C
C     Noel M. Nachtigal
C     October 7, 1990
C
C**********************************************************************
C
      INTEGER I
C
      DSQMRO = 1.0D0
C
      RETURN
      END
C
C**********************************************************************
C
      SUBROUTINE DSQMR1 (NDIM,NLEN,M,MAXVW,NUMCHK,N,L,LSTAR,NL,NLSTAR,
     $                  VF,IERR,ADJUST,NORM1,NORMA,TMAX,TMIN,TNRM,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 "dulal.doc" or "dsqmr.doc".
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 ddot(n,x,incx,y,incy)
C        BLAS-1 routine, computes y^H * x.
C     double precision dlamch(ch)
C        LAPACK routine, computes machine-related constants.
C     double precision dnrm2(n,x,incx)
C        BLAS-1 routine, computes the 2-norm of x.
C     subroutine dqrdc(x,ldx,n,p,qraux,jpvt,work,job)
C        LINPACK routine, computes the QR factorization of x.
C     subroutine dqrsl(x,ldx,n,k,qraux,y,qy,qty,b,rsd,xb,job,info)
C        LINPACK routine, applies the QR factorization of x.
C     subroutine dsvdc(x,ldx,n,p,s,e,u,ldu,v,ldv,work,job,info)
C        LINPACK routine, computes the SVD of x.
C     subroutine dsqmr2 (ndim,nlen,m,dwk,iwk,idx,vecs)
C        Forces closure of an inner block.
C     double precision dsqmrh(i,n)
C        User-supplied routine, computes inner recurrence coefficients.
C
C     Noel M. Nachtigal
C     July 9, 1993
C
C**********************************************************************
C
      INTRINSIC DABS, DMAX1, MAX0
      EXTERNAL DAXPBY, DDOT, DLAMCH, DNRM2, DQRDC, DQRSL, DSVDC
      EXTERNAL DSQMR2, DSQMRH
      DOUBLE PRECISION DDOT, DLAMCH, DNRM2, DSQMRH
C
      INTEGER IERR, L, LSTAR, M, MAXVW, N, NDIM, NL, NLEN, NLSTAR
      INTEGER IDX(3,3), IWK(M,4), NUMCHK, VF
      DOUBLE PRECISION ADJUST, NORM1, NORMA, TMAX, TMIN, TNRM
      DOUBLE PRECISION DWK(M,5*M+13), VECS(NDIM,3*MAXVW+2+3)
C
C     Miscellaneous parameters.
C
      DOUBLE PRECISION DONE, DZERO
      PARAMETER (DONE = 1.0D0,DZERO = 0.0D0)
C
C     Local variables.
C
      INTEGER I, IJ, J, LBLKSZ, NP1
      DOUBLE PRECISION DTMP, DTMP1, DTMP2, DTMP3, DTMP4, DTMP5
      DOUBLE PRECISION IDTMP1, IDTMP2, IDTMP3, IDTMP4
      LOGICAL IBUILT, INNER, RERUN
C
C     Initialize local variables.
C
      NP1        = N + 1
      DWK(IDX(1,N),5*M+11) = DZERO
      RERUN      = .FALSE.
      IBUILT     = .FALSE.
      IERR       = 0
      LBLKSZ     = N - NL + 1
C
C     Update the norm estimates.
C
      IF (N.LE.NUMCHK) THEN
         DTMP1 = DNRM2(NLEN,VECS(1,3),1) * DWK(IDX(1,N),5*M+9)
CSYM     DTMP2 = DNRM2(NLEN,VECS(1,3),1) * DWK(IDX(1,N),5*M+10)
         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
         DWK(IDX(1,I),2*M+IDX(1,N)) = DZERO
 100  CONTINUE
C
C     Update D^{(n-1)} to D^{(n)}.
C
      DO 120 I = NL, N-1
         DTMP = DZERO
         DO 110 J = NL, N-1
            DTMP = DTMP + DWK(IDX(1,I),IDX(1,J)) * DWK(IDX(1,J),2*M+
     $IDX(1,N-1))
 110     CONTINUE
         DTMP     = ( DWK(IDX(1,I),M+IDX(1,N-1)) - DTMP ) / DWK(IDX(1,N)
     $,2*M+IDX(1,N-1))
         DWK(IDX(1,I),IDX(1,N)) = DTMP
         DWK(IDX(1,N),IDX(1,I)) = DTMP * DWK(IDX(1,N),5*M+8) / DWK(IDX(1
     $,I),5*M+8)
 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
         DTMP = DZERO
         DO 130 J = NL, I+1
            DTMP = DTMP + DWK(IDX(1,N),IDX(1,J)) * DWK(IDX(1,J),2*M+
     $IDX(1,I))
 130     CONTINUE
         DWK(IDX(1,N),M+IDX(1,I)) = DTMP
         DWK(IDX(1,I),M+IDX(1,N)) = DTMP * DWK(IDX(1,I),5*M+8) /
     $DWK(IDX(1,N),5*M+8)
         NORMA    = DMAX1(NORMA,DABS(DWK(IDX(1,N),M+IDX(1,I))),
     $DABS(DWK(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 = DABS(DWK(IDX(1,NL),IDX(1,NL))).EQ.DZERO
      ELSE
         DO 160 I = NL, N
            DO 150 J = NL, N
               DWK(I-NL+1,4*M+J-NL+1) = DWK(IDX(1,I),IDX(1,J))
 150        CONTINUE
 160     CONTINUE
         CALL DSVDC (DWK(1,4*M+1),M,LBLKSZ,LBLKSZ,DWK(1,5*M+1),DWK(1,5*M
     $+3),DZERO,0,DZERO,0,DWK(1,5*M+2),0,I)
         IF (I.NE.0) THEN
            IERR = -I
            GOTO 370
         END IF
         DTMP = DZERO
         IF (DWK(1,5*M+1).NE.DZERO) DTMP = DWK(LBLKSZ,5*M+1) / DWK(1,5*M
     $+1)
         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,3) = A v_n and VECS(1,3) = A^T w_n.
C
      DWK(IDX(1,NP1),2*M+IDX(1,N)) = DZERO
      IF (NL.EQ.1) GO TO 180
      IF (NL.EQ.NLSTAR+1) THEN
         DWK(IDX(1,NLSTAR),2*M+IDX(1,N)) = DWK(IDX(1,NLSTAR),M+IDX(1,N))
     $ / DWK(IDX(1,NLSTAR),IDX(1,NLSTAR))
         DTMP = DWK(IDX(1,NLSTAR),2*M+IDX(1,N)) * DWK(IDX(1,NLSTAR),5*M+
     $9) / DWK(IDX(1,N),5*M+9)
         CALL DAXPBY (NLEN,VECS(1,3),DONE,VECS(1,3),-DTMP,VECS(1,IDX(2,
     $NLSTAR)))
         DTMP = DWK(IDX(1,NLSTAR),2*M+IDX(1,N)) * DWK(IDX(1,NLSTAR),5*M+
     $10) / DWK(IDX(1,N),5*M+10) * DWK(IDX(1,N),5*M+8) / DWK(IDX(1,
     $NLSTAR),5*M+8)
CSYM     CALL DAXPBY (NLEN,VECS(1,3),DONE,VECS(1,3),-DTMP,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
         DTMP2 = DZERO
         DO 170 I = NL-1, NLSTAR, -1
            DWK(IDX(1,I),2*M+IDX(1,N)) = DWK(IDX(1,NL-1),M+IDX(1,N)) *
     $DWK(IDX(1,I),3*M+IDX(1,L-1))
            IF (N.NE.NL) GO TO 170
            DTMP1 = DWK(IDX(1,I),3*M+IDX(1,L-1)) * DWK(IDX(1,I),5*M+9)
            CALL DAXPBY (NLEN,VECS(1,IDX(2,NL-1)),DTMP2,VECS(1,IDX(2,NL-
     $1)),DTMP1,VECS(1,IDX(2,I)))
            DTMP1 = DWK(IDX(1,I),3*M+IDX(1,L-1)) * DWK(IDX(1,I),5*M+10)
     $/ DWK(IDX(1,I),5*M+8)
CSYM        CALL DAXPBY (NLEN,VECS(1,IDX(3,NL-1)),DTMP2,VECS(1,IDX(3,NL-1)),DTMP1,VECS(1,IDX(3,I)))
            DTMP2 = DONE
 170     CONTINUE
         DTMP1 = DWK(IDX(1,NL-1),M+IDX(1,N)) / DWK(IDX(1,N),5*M+9)
         CALL DAXPBY (NLEN,VECS(1,3),DONE,VECS(1,3),-DTMP1,VECS(1,IDX(2,
     $NL-1)))
         DTMP1 = DWK(IDX(1,NL-1),M+IDX(1,N)) * DWK(IDX(1,N),5*M+8) /
     $DWK(IDX(1,N),5*M+10)
CSYM     CALL DAXPBY (NLEN,VECS(1,3),DONE,VECS(1,3),-DTMP1,VECS(1,IDX(3,NL-1)))
      END IF
C
C     Compute F_{nn}.
C
 180  DWK(IDX(1,N),M+IDX(1,N)) = DDOT(NLEN,VECS(1,IDX(3,N)),1,VECS(1,3),
     $1) * DWK(IDX(1,N),5*M+9) * DWK(IDX(1,N),5*M+10)
      NORMA    = DMAX1(NORMA,DABS(DWK(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
         DWK(IDX(1,NL),2*M+IDX(1,N)) = DWK(IDX(1,NL),M+IDX(1,N)) /
     $DWK(IDX(1,NL),IDX(1,NL))
      ELSE
         DO 200 J = NL, N
            DWK(J-NL+1,5*M+1) = DWK(IDX(1,J),M+IDX(1,N))
            DO 190 IJ = NL, N
               DWK(J-NL+1,4*M+IJ-NL+1) = DWK(IDX(1,J),IDX(1,IJ))
 190        CONTINUE
 200     CONTINUE
         CALL DQRDC (DWK(1,4*M+1),M,LBLKSZ,LBLKSZ,DWK(1,5*M+3),0,DZERO,0
     $)
         CALL DQRSL (DWK(1,4*M+1),M,LBLKSZ,LBLKSZ,DWK(1,5*M+3),DWK(1,5*M
     $+1),
     $               DZERO,DWK(1,5*M+1),DWK(1,5*M+2),DWK(1,5*M+1),DZERO,
     $100,J)
         DO 210 J = NL, N
            DWK(IDX(1,J),2*M+IDX(1,N)) = DWK(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
      DTMP = DWK(IDX(1,N),2*M+IDX(1,N))
      CALL DAXPBY (NLEN,VECS(1,IDX(2,NP1)),DONE,VECS(1,3),-DTMP,VECS(1,
     $IDX(2,N)))
CSYM  CALL DAXPBY (NLEN,VECS(1,IDX(3,NP1)),DONE,VECS(1,3),-DTMP,VECS(1,IDX(3,N)))
      DO 220 I = NL, N-1
         DTMP = DWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),5*M+9) /
     $DWK(IDX(1,N),5*M+9)
         CALL DAXPBY (NLEN,VECS(1,IDX(2,NP1)),DONE,VECS(1,IDX(2,NP1)),-
     $DTMP,VECS(1,IDX(2,I)))
         DTMP = DWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),5*M+10) /
     $DWK(IDX(1,N),5*M+10) * DWK(IDX(1,N),5*M+8) / DWK(IDX(1,I),5*M+8)
CSYM     CALL DAXPBY (NLEN,VECS(1,IDX(3,NP1)),DONE,VECS(1,IDX(3,NP1)),-DTMP,VECS(1,IDX(3,I)))
 220  CONTINUE
C
C     Compute scale factors for the new vectors.
C
 230  DTMP3      = DNRM2(NLEN,VECS(1,IDX(2,NP1)),1)
CSYM  DTMP4      = DNRM2(NLEN,VECS(1,IDX(3,NP1)),1)
      DTMP4      = DTMP3
      DTMP1      = DWK(IDX(1,N),5*M+9) * DTMP3
      DTMP2      = DWK(IDX(1,N),5*M+10) * DTMP4
      DWK(IDX(1,NP1),2*M+IDX(1,N)) = DTMP1
      IF (DTMP1.LT.TNRM) IERR = IERR + 16
      IF (DTMP2.LT.TNRM) IERR = IERR + 32
      IF (IERR.NE.0) GOTO 360
      DWK(IDX(1,NP1),5*M+8)     = DWK(IDX(1,N),5*M+8) * DTMP1 / DTMP2
      DWK(IDX(1,NP1),IDX(1,NP1)) = DDOT(NLEN,VECS(1,IDX(3,NP1)),1,VECS(1
     $,IDX(2,NP1)),1) / ( DTMP3 * DTMP4 )
      IF ((DTMP3.GE.TMAX).OR.(DTMP3.LE.TMIN)) THEN
         DTMP = DONE / DTMP3
         CALL DAXPBY (NLEN,VECS(1,IDX(2,NP1)),DTMP,VECS(1,IDX(2,NP1)),
     $DZERO,VECS(1,IDX(2,NP1)))
         DTMP3 = DONE
      END IF
      IF ((DTMP4.GE.TMAX).OR.(DTMP4.LE.TMIN)) THEN
         DTMP = DONE / DTMP4
CSYM     CALL DAXPBY (NLEN,VECS(1,IDX(3,NP1)),DTMP,VECS(1,IDX(3,NP1)),DZERO,VECS(1,IDX(3,NP1)))
         DTMP4 = DONE
      END IF
      DWK(IDX(1,NP1),5*M+9) = DONE / DTMP3
      DWK(IDX(1,NP1),5*M+10) = DONE / DTMP4
C
C     Compute the last column of D_l^{-1}.
C
      IF (LBLKSZ.EQ.1) THEN
         DWK(IDX(1,NL),3*M+IDX(1,L)) = DONE / DWK(IDX(1,NL),IDX(1,NL))
      ELSE
         DO 240 I = 1, LBLKSZ-1
            DWK(I,5*M+1) = DZERO
 240     CONTINUE
         DWK(LBLKSZ,5*M+1) = DONE
         CALL DQRSL (DWK(1,4*M+1),M,LBLKSZ,LBLKSZ,DWK(1,5*M+3),DWK(1,5*M
     $+1),
     $               DZERO,DWK(1,5*M+1),DWK(1,5*M+2),DWK(1,5*M+1),DZERO,
     $100,J)
         DO 250 I = NL, N
            DWK(IDX(1,I),3*M+IDX(1,L)) = DWK(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  = DABS(DWK(IDX(1,I),2*M+IDX(1,N)))
         DTMP1 = DTMP1 + DTMP
         DTMP2 = DTMP2 + DTMP / DWK(IDX(1,I),5*M+8)
 260  CONTINUE
      DTMP2 = DTMP2 * DWK(IDX(1,N),5*M+8)
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
      DTMP5 = DWK(IDX(1,NP1),IDX(1,NP1)) * DWK(IDX(1,NP1),2*M+IDX(1,N))
     $* DWK(IDX(1,N),5*M+8) / DWK(IDX(1,NP1),5*M+8)
      DO 270 I = NL, N
         DTMP  = DABS(DTMP5 * DWK(IDX(1,I),3*M+IDX(1,L)))
         DTMP3 = DTMP3 + DTMP
         DTMP4 = DTMP4 + DTMP / DWK(IDX(1,I),5*M+8)
 270  CONTINUE
      DTMP4 = DTMP4 * DWK(IDX(1,NP1),5*M+8)
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),5*M+11) = 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,3) and VECS(1,3).
C
      IBUILT = .TRUE.
      DO 280 I = NL, N
         DWK(IDX(1,I),2*M+IDX(1,NP1)) = DSQMRH(I,N)
         DTMP       = DWK(IDX(1,I),2*M+IDX(1,NP1)) * DWK(IDX(1,I),5*M+9)
     $ / DWK(IDX(1,N),5*M+9)
         CALL DAXPBY (NLEN,VECS(1,3),DONE,VECS(1,3),-DTMP,VECS(1,IDX(2,I
     $)))
         DTMP       = DWK(IDX(1,I),2*M+IDX(1,NP1)) * DWK(IDX(1,I),5*M+10
     $) / DWK(IDX(1,N),5*M+10) * DWK(IDX(1,N),5*M+8) / DWK(IDX(1,I),5*M+
     $8)
CSYM     CALL DAXPBY (NLEN,VECS(1,3),DONE,VECS(1,3),-DTMP,VECS(1,IDX(3,I)))
 280  CONTINUE
      IDTMP3       = DNRM2(NLEN,VECS(1,3),1)
CSYM  IDTMP4       = DNRM2(NLEN,VECS(1,3),1)
      IDTMP4       = IDTMP3
      IDTMP1       = DWK(IDX(1,N),5*M+9) * IDTMP3
      IDTMP2       = DWK(IDX(1,N),5*M+10) * IDTMP4
      DWK(IDX(1,NP1),2*M+IDX(1,NP1)) = IDTMP1
      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
      DTMP = DZERO
      DO 290 J = NLSTAR, NL-1
         DTMP = DTMP + DWK(IDX(1,NL),IDX(1,J)) * DWK(IDX(1,I),2*M+IDX(1,
     $N))
 290  CONTINUE
      DO 300 J = NL, N
         DTMP = DTMP + DWK(IDX(1,NL),IDX(1,J)) * DWK(IDX(1,I),2*M+IDX(1,
     $NP1))
 300  CONTINUE
      DTMP1 = DZERO
      DTMP2 = DZERO
      DTMP3 = DMAX1(DTMP3,DTMP4)
      DTMP  = ( DWK(IDX(1,NL),M+IDX(1,N)) - DTMP ) / DWK(IDX(1,NP1),2*M+
     $IDX(1,NP1))
      DTMP5 = DTMP * DWK(IDX(1,NL),2*M+IDX(1,NL-1)) * DWK(IDX(1,NL-1),
     $5*M+8) / DWK(IDX(1,NL),5*M+8)
      DO 310 I = IWK(IDX(1,L-1+1),1), NL-1
         DTMP  = DABS(DWK(IDX(1,I),3*M+IDX(1,L-1)) * DTMP5)
         DTMP1 = DTMP1 + DTMP
         DTMP2 = DTMP2 + DTMP / DWK(IDX(1,I),5*M+8)
 310  CONTINUE
      DTMP2 = DTMP2 * DWK(IDX(1,N),5*M+8)
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 DSQMR2 (NDIM,NLEN,M,N,L,LSTAR,NL,NLSTAR,VF,IERR,ADJUST,
     $               NORM1,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 DAXPBY (NLEN,VECS(1,IDX(2,NP1)),DONE,VECS(1,3),DZERO,VECS(1,
     $IDX(2,NP1)))
CSYM  CALL DAXPBY (NLEN,VECS(1,IDX(3,NP1)),DONE,VECS(1,3),DZERO,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
            DWK(IDX(1,I),2*M+IDX(1,N)) = DWK(IDX(1,I),2*M+IDX(1,NP1))
 340     CONTINUE
         DTMP1 = IDTMP1
         DTMP2 = IDTMP2
         DTMP3 = IDTMP3
         DTMP4 = IDTMP4
      ELSE
         DO 350 I = NL, N
            DWK(IDX(1,I),2*M+IDX(1,N)) = DSQMRH(I,N)
            DTMP     = DWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),5*M+9)
     $/ DWK(IDX(1,N),5*M+9)
            CALL DAXPBY (NLEN,VECS(1,IDX(2,NP1)),DONE,VECS(1,IDX(2,NP1))
     $,-DTMP,VECS(1,IDX(2,I)))
            DTMP     = DWK(IDX(1,I),2*M+IDX(1,N)) * DWK(IDX(1,I),5*M+10)
     $ / DWK(IDX(1,N),5*M+10) * DWK(IDX(1,N),5*M+8) / DWK(IDX(1,I),5*M+8
     $)
CSYM        CALL DAXPBY (NLEN,VECS(1,IDX(3,NP1)),DONE,VECS(1,IDX(3,NP1)),-DTMP,VECS(1,IDX(3,I)))
 350     CONTINUE
         DTMP3 = DNRM2(NLEN,VECS(1,IDX(2,NP1)),1)
CSYM     DTMP4 = DNRM2(NLEN,VECS(1,IDX(3,NP1)),1)
         DTMP4 = DTMP3
         DTMP1 = DWK(IDX(1,N),5*M+9) * DTMP3
         DTMP2 = DWK(IDX(1,N),5*M+10) * DTMP4
      END IF
      DWK(IDX(1,NP1),2*M+IDX(1,N)) = DTMP1
      IF (DTMP1.LT.TNRM) IERR = IERR + 16
      IF (DTMP2.LT.TNRM) IERR = IERR + 32
      IF (IERR.NE.0) GOTO 360
      DWK(IDX(1,NP1),5*M+8)     = DWK(IDX(1,N),5*M+8) * DTMP1 / DTMP2
      DWK(IDX(1,NP1),IDX(1,NP1)) = DDOT(NLEN,VECS(1,IDX(3,NP1)),1,VECS(1
     $,IDX(2,NP1)),1) / ( DTMP3 * DTMP4 )
      IF ((DTMP3.GE.TMAX).OR.(DTMP3.LE.TMIN)) THEN
         DTMP = DONE / DTMP3
         CALL DAXPBY (NLEN,VECS(1,IDX(2,NP1)),DTMP,VECS(1,IDX(2,NP1)),
     $DZERO,VECS(1,IDX(2,NP1)))
         DTMP3 = DONE
      END IF
      IF ((DTMP4.GE.TMAX).OR.(DTMP4.LE.TMIN)) THEN
         DTMP = DONE / DTMP4
CSYM     CALL DAXPBY (NLEN,VECS(1,IDX(3,NP1)),DTMP,VECS(1,IDX(3,NP1)),DZERO,VECS(1,IDX(3,NP1)))
         DTMP4 = DONE
      END IF
      DWK(IDX(1,NP1),5*M+9) = DONE / DTMP3
      DWK(IDX(1,NP1),5*M+10) = 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 DSQMR2 (NDIM,NLEN,M,N,L,LSTAR,NL,NLSTAR,VF,IERR,
     $                  ADJUST,NORM1,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 "dulal.doc" or "dsqmr.doc".
C
C     External routines used:
C     subroutine daxpby(n,z,a,x,b,y)
C        Library routine, computes z = a * x + b * y.
C     subroutine dqrdc(x,ldx,n,p,qraux,jpvt,work,job)
C        LINPACK routine, computes the QR factorization of x.
C     subroutine dqrsl(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 DAXPBY, DQRDC, DQRSL
C
      INTEGER IERR, L, LSTAR, M, N, NDIM, NL, NLEN, NLSTAR
      INTEGER IDX(3,3), IWK(M,4), VF
      DOUBLE PRECISION ADJUST, DWK(M,5*M+13), NORM1, VECS(NDIM,*)
C
C     Miscellaneous parameters.
C
      DOUBLE PRECISION DONE, DZERO
      PARAMETER (DONE = 1.0D0,DZERO = 0.0D0)
C
C     Local variables.
C
      INTEGER I, IJ, J, LBLKSZ, NP1
      DOUBLE PRECISION DTMP1, DTMP2, SCALV, SCALW
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),5*M+11)
      DO 100 I = NL+1, N
         DTMP2 = DWK(IDX(1,I),5*M+11)
         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),5*M+11) = 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
         DWK(IDX(1,NL),2*M+IDX(1,NP1)) = DWK(IDX(1,NL),2*M+IDX(1,N))
         DWK(IDX(1,NL),2*M+IDX(1,N))   = DWK(IDX(1,NL),M+IDX(1,N)) /
     $DWK(IDX(1,NL),IDX(1,NL))
      ELSE
         DO 120 J = NL, N
            DWK(J-NL+1,5*M+1) = DWK(IDX(1,J),M+IDX(1,N))
            DO 110 IJ = NL, N
               DWK(J-NL+1,4*M+IJ-NL+1) = DWK(IDX(1,J),IDX(1,IJ))
 110        CONTINUE
 120     CONTINUE
         CALL DQRDC (DWK(1,4*M+1),M,LBLKSZ,LBLKSZ,DWK(1,5*M+3),0,DZERO,0
     $)
         CALL DQRSL (DWK(1,4*M+1),M,LBLKSZ,LBLKSZ,DWK(1,5*M+3),DWK(1,5*M
     $+1),
     $               DZERO,DWK(1,5*M+1),DWK(1,5*M+2),DWK(1,5*M+1),DZERO,
     $100,J)
         DO 130 J = NL, N
            DWK(IDX(1,J),2*M+IDX(1,NP1)) = DWK(IDX(1,J),2*M+IDX(1,N))
            DWK(IDX(1,J),2*M+IDX(1,N)) = DWK(J-NL+1,5*M+2)
 130     CONTINUE
      END IF
C
C     Convert inner vectors to regular vectors.
C
      SCALV = DWK(IDX(1,NP1),2*M+IDX(1,N)) * DWK(IDX(1,NP1),5*M+9)
      SCALW = DWK(IDX(1,NP1),2*M+IDX(1,N)) * DWK(IDX(1,NP1),5*M+10) *
     $DWK(IDX(1,N),5*M+8) / DWK(IDX(1,NP1),5*M+8)
      DWK(IDX(1,NP1),2*M+IDX(1,N)) = DZERO
      DO 140 I = NL, N
         DTMP1 = DWK(IDX(1,I),2*M+IDX(1,N)) - DWK(IDX(1,I),2*M+IDX(1,NP1
     $))
         DTMP2 = DTMP1 * DWK(IDX(1,I),5*M+9) / SCALV
         CALL DAXPBY (NLEN,VECS(1,IDX(2,NP1)),DONE,VECS(1,IDX(2,NP1)),-
     $DTMP2,VECS(1,IDX(2,I)))
         DTMP2 = DTMP1 * DWK(IDX(1,I),5*M+10) / SCALW * DWK(IDX(1,N),5*M
     $+8) / DWK(IDX(1,I),5*M+8)
CSYM     CALL DAXPBY (NLEN,VECS(1,IDX(3,NP1)),DONE,VECS(1,IDX(3,NP1)),-DTMP2,VECS(1,IDX(3,I)))
 140  CONTINUE
C
      RETURN
      END
C
C**********************************************************************