      SUBROUTINE BSTREXC( N, T, LDT, IFST, ILST, NITRAF, ITRAF,
     $                    NDTRAF, DTRAF, WORK, INFO )
      IMPLICIT NONE
*
*
*  -- LAPACK routine (version 3.0) --
*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
*     Courant Institute, Argonne National Lab, and Rice University
*     March 31, 1993
*
*     .. Scalar Arguments ..
      INTEGER            IFST, ILST, INFO, LDT, N, NDTRAF, NITRAF
*     ..
*     .. Array Arguments ..
      INTEGER            ITRAF( * )
      REAL               DTRAF( * ), T( LDT, * ), WORK( * )
*     ..
*
*  Purpose
*  =======
*
*  BSTREXC reorders the real Schur factorization of a real matrix
*  A = Q*T*Q**T, so that the diagonal block of T with row index IFST is
*  moved to row ILST.
*
*  The real Schur form T is reordered by an orthogonal similarity
*  transformation Z**T*T*Z. In contrast to the LAPACK routine DTREXC,
*  the orthogonal matrix Z is not explicitly constructed but
*  represented by paramaters contained in the arrays ITRAF and DTRAF,
*  see further details.
*
*  T must be in Schur canonical form (as returned by DHSEQR), that is,
*  block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each
*  2-by-2 diagonal block has its diagonal elements equal and its
*  off-diagonal elements of opposite sign.
*
*  Arguments
*  =========
*
*  N       (input) INTEGER
*          The order of the matrix T. N >= 0.
*
*  T       (input/output) REAL             array, dimension (LDT,N)
*          On entry, the upper quasi-triangular matrix T, in Schur
*          Schur canonical form.
*          On exit, the reordered upper quasi-triangular matrix, again
*          in Schur canonical form.
*
*  LDT     (input) INTEGER
*          The leading dimension of the array T. LDT >= max(1,N).
*
*  IFST    (input/output) INTEGER
*  ILST    (input/output) INTEGER
*          Specify the reordering of the diagonal blocks of T.
*          The block with row index IFST is moved to row ILST, by a
*          sequence of transpositions between adjacent blocks.
*          On exit, if IFST pointed on entry to the second row of a
*          2-by-2 block, it is changed to point to the first row; ILST
*          always points to the first row of the block in its final
*          position (which may differ from its input value by +1 or -1).
*          1 <= IFST <= N; 1 <= ILST <= N.
*
*  NITRAF  (input/output) INTEGER
*          On entry, length of the array ITRAF.
*          As a minimum requirement, NITRAF >= max(1,|ILST-IFST|).
*          If there are 2-by-2 blocks in T then NITRAF must be larger;
*          a safe choice is NITRAF >= max(1,2*|ILST-IFST|).
*          On exit, actual length of the array ITRAF.
*
*  ITRAF   (output) INTEGER array, length NITRAF
*          List of parameters for representing the transformation
*          matrix Z, see further details.
*
*  NDTRAF  (input/output) INTEGER
*          On entry, length of the array DTRAF.
*          As a minimum requirement, NDTRAF >= max(1,2*|ILST-IFST|).
*          If there are 2-by-2 blocks in T then NDTRAF must be larger;
*          a safe choice is NDTRAF >= max(1,5*|ILST-IFST|).
*          On exit, actual length of the array DTRAF.
*
*  DTRAF   (output) REAL             array, length NDTRAF
*          List of parameters for representing the transformation
*          matrix Z, see further details.
*
*  WORK    (workspace) REAL             array, dimension (N)
*
*  INFO    (output) INTEGER
*          = 0:  successful exit
*          < 0:  if INFO = -i, the i-th argument had an illegal value
*          = 1:  two adjacent blocks were too close to swap (the problem
*                is very ill-conditioned); T may have been partially
*                reordered, and ILST points to the first row of the
*                current position of the block being moved.
*          = 2:  the 2 by 2 block to be reordered split into two 1 by 1
*                blocks and the second block failed to swap with an
*                adjacent block. ILST points to the first row of the
*                current position of the whole block being moved.
*
*  Further Details
*  ===============
*
*  The orthogonal transformation matrix Z is a product of NITRAF
*  elementary orthogonal transformations. The parameters defining these
*  transformations are stored in the arrays ITRAF and DTRAF as follows:
*
*  Consider the i-th transformation acting on rows/columns POS,
*  POS+1, ... If this transformation is
*
*     (1) a Givens rotation with cosine C and sine S then
*
*           ITRAF(i) = POS,
*           DTRAF(j) = C,    DTRAF(j+1) = S;
*
*     (2) a Householder reflector H = I - tau * v * v' with
*         v = [ 1; v2; v3 ] then
*
*           ITRAF(i) = N + POS,
*           DTRAF(j) = tau,  DTRAF(j+1) = v2,  DTRAF(j+2) = v3;
*
*     (3) a Householder reflector H = I - tau * v * v' with
*         v = [ v1; v2; 1 ] then
*
*           ITRAF(i) = 2*N + POS,
*           DTRAF(j) = v1,  DTRAF(j+1) = v2,  DTRAF(j+2) = tau;
*
*  Note that the parameters in DTRAF are stored consecutively.
*
*  =====================================================================
*
*     .. Parameters ..
      REAL               ZERO
      PARAMETER          ( ZERO = 0.0E+0 )
      INTEGER            DLNGTH(3), ILNGTH(3)
*     ..
*     .. Local Scalars ..
      INTEGER            CDTRAF, CITRAF, LDTRAF, LITRAF, HERE, I, NBF,
     $                   NBL, NBNEXT
*     ..
*     .. External Functions ..
      LOGICAL            LSAME
      EXTERNAL           LSAME
*     ..
*     .. External Subroutines ..
      EXTERNAL           BSLAEXC, XERBLA
*     ..
*     .. Intrinsic Functions ..
      INTRINSIC          ABS, MAX
*     .. Data Statements ..
c      DATA ( ILNGTH(I), I = 1, 3 ) / 1, 2, 4 /
c      DATA ( DLNGTH(I), I = 1, 3 ) / 2, 5, 10 /
      DATA ILNGTH(1)/1/, ILNGTH(2)/2/, ILNGTH(3)/4/
      DATA DLNGTH(1)/2/, DLNGTH(2)/5/, DLNGTH(3)/10/
*     ..
*     .. Executable Statements ..
*
*     Decode and test the input arguments.
*
      INFO = 0
      IF( N.LT.0 ) THEN
         INFO = -1
      ELSE IF( LDT.LT.MAX( 1, N ) ) THEN
         INFO = -3
      ELSE IF( IFST.LT.1 .OR. IFST.GT.N ) THEN
         INFO = -4
      ELSE IF( ILST.LT.1 .OR. ILST.GT.N ) THEN
         INFO = -5
      ELSE IF ( NITRAF.LT.MAX( 1, ABS( ILST-IFST ) ) ) THEN
         INFO = -6
      ELSE IF ( NDTRAF.LT.MAX( 1, 2*ABS( ILST-IFST ) ) ) THEN
         INFO = -8
      END IF
      IF( INFO.NE.0 ) THEN
         CALL XERBLA( 'DTREXC', -INFO )
         RETURN
      END IF
*
*     Quick return if possible
*
      IF( N.LE.1 )
     $   RETURN
      CITRAF = 1
      CDTRAF = 1
*
*     Determine the first row of specified block
*     and find out it is 1 by 1 or 2 by 2.
*
      IF( IFST.GT.1 ) THEN
         IF( T( IFST, IFST-1 ).NE.ZERO )
     $      IFST = IFST - 1
      END IF
      NBF = 1
      IF( IFST.LT.N ) THEN
         IF( T( IFST+1, IFST ).NE.ZERO )
     $      NBF = 2
      END IF
*
*     Determine the first row of the final block
*     and find out it is 1 by 1 or 2 by 2.
*
      IF( ILST.GT.1 ) THEN
         IF( T( ILST, ILST-1 ).NE.ZERO )
     $      ILST = ILST - 1
      END IF
      NBL = 1
      IF( ILST.LT.N ) THEN
         IF( T( ILST+1, ILST ).NE.ZERO )
     $      NBL = 2
      END IF
*
      IF( IFST.EQ.ILST )
     $   RETURN
*
      IF( IFST.LT.ILST ) THEN
*
*        Update ILST
*
         IF( NBF.EQ.2 .AND. NBL.EQ.1 )
     $      ILST = ILST - 1
         IF( NBF.EQ.1 .AND. NBL.EQ.2 )
     $      ILST = ILST + 1
*
         HERE = IFST
*
   10    CONTINUE
*
*        Swap block with next one below
*
         IF( NBF.EQ.1 .OR. NBF.EQ.2 ) THEN
*
*           Current block either 1 by 1 or 2 by 2
*
            NBNEXT = 1
            IF( HERE+NBF+1.LE.N ) THEN
               IF( T( HERE+NBF+1, HERE+NBF ).NE.ZERO )
     $            NBNEXT = 2
            END IF
*
            LITRAF = ILNGTH(NBF+NBNEXT-1)
            LDTRAF = DLNGTH(NBF+NBNEXT-1)
            IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
               INFO = -6
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
               INFO = -8
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            CALL BSLAEXC( N, T, LDT, HERE, NBF, NBNEXT, ITRAF(CITRAF),
     $                    DTRAF(CDTRAF), WORK, INFO )
            IF( INFO.NE.0 ) THEN
               ILST = HERE
               NITRAF = CITRAF - 1
               NDTRAF = CDTRAF - 1
               RETURN
            END IF
            CITRAF = CITRAF + LITRAF
            CDTRAF = CDTRAF + LDTRAF
            HERE = HERE + NBNEXT
*
*           Test if 2 by 2 block breaks into two 1 by 1 blocks
*
            IF( NBF.EQ.2 ) THEN
               IF( T( HERE+1, HERE ).EQ.ZERO )
     $            NBF = 3
            END IF
*
         ELSE
*
*           Current block consists of two 1 by 1 blocks each of which
*           must be swapped individually
*
            NBNEXT = 1
            IF( HERE+3.LE.N ) THEN
               IF( T( HERE+3, HERE+2 ).NE.ZERO )
     $            NBNEXT = 2
            END IF
            LITRAF = ILNGTH(NBNEXT)
            LDTRAF = DLNGTH(NBNEXT)
            IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
               INFO = -6
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
               INFO = -8
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            CALL BSLAEXC( N, T, LDT, HERE+1, 1, NBNEXT, ITRAF(CITRAF),
     $                    DTRAF(CDTRAF), WORK, INFO )
            IF( INFO.NE.0 ) THEN
               ILST = HERE
               NITRAF = CITRAF - 1
               NDTRAF = CDTRAF - 1
               RETURN
            END IF
            CITRAF = CITRAF + LITRAF
            CDTRAF = CDTRAF + LDTRAF
*
            IF( NBNEXT.EQ.1 ) THEN
*
*              Swap two 1 by 1 blocks, no problems possible
*
               LITRAF = ILNGTH(1)
               LDTRAF = DLNGTH(1)
               IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
                  INFO = -6
                  CALL XERBLA( 'BSTREXC', -INFO )
                  RETURN
               END IF
               IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
                  INFO = -8
                  CALL XERBLA( 'BSTREXC', -INFO )
                  RETURN
               END IF
               CALL BSLAEXC( N, T, LDT, HERE, 1, NBNEXT, ITRAF(CITRAF),
     $                       DTRAF(CDTRAF), WORK, INFO )
               CITRAF = CITRAF + LITRAF
               CDTRAF = CDTRAF + LDTRAF
               HERE = HERE + 1
            ELSE
*
*              Recompute NBNEXT in case 2 by 2 split
*
               IF( T( HERE+2, HERE+1 ).EQ.ZERO )
     $            NBNEXT = 1
               IF( NBNEXT.EQ.2 ) THEN
*
*                 2 by 2 Block did not split
*
                  LITRAF = ILNGTH(2)
                  LDTRAF = DLNGTH(2)
                  IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
                     INFO = -6
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
                     INFO = -8
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  CALL BSLAEXC( N, T, LDT, HERE, 1, NBNEXT,
     $                          ITRAF(CITRAF), DTRAF(CDTRAF), WORK,
     $                          INFO )
                  IF( INFO.NE.0 ) THEN
                     INFO = 2
                     ILST = HERE
                     NITRAF = CITRAF - 1
                     NDTRAF = CDTRAF - 1
                     RETURN
                  END IF
                  CITRAF = CITRAF + LITRAF
                  CDTRAF = CDTRAF + LDTRAF
                  HERE = HERE + 2
               ELSE
*
*                 2 by 2 Block did split
*
                  LITRAF = ILNGTH(1)
                  LDTRAF = DLNGTH(1)
                  IF( CITRAF+2*LITRAF-1.GT.NITRAF ) THEN
                     INFO = -6
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  IF( CDTRAF+2*LDTRAF-1.GT.NDTRAF ) THEN
                     INFO = -8
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  CALL BSLAEXC( N, T, LDT, HERE, 1, 1, ITRAF(CITRAF),
     $                          DTRAF(CDTRAF), WORK, INFO )
                  CITRAF = CITRAF + LITRAF
                  CDTRAF = CDTRAF + LDTRAF
                  CALL BSLAEXC( N, T, LDT, HERE+1, 1, 1, ITRAF(CITRAF),
     $                          DTRAF(CDTRAF), WORK, INFO )
                  CITRAF = CITRAF + LITRAF
                  CDTRAF = CDTRAF + LDTRAF
                  HERE = HERE + 2
               END IF
            END IF
         END IF
         IF( HERE.LT.ILST )
     $      GO TO 10
*
      ELSE
*
         HERE = IFST
   20    CONTINUE
*
*        Swap block with next one above
*
         IF( NBF.EQ.1 .OR. NBF.EQ.2 ) THEN
*
*           Current block either 1 by 1 or 2 by 2
*
            NBNEXT = 1
            IF( HERE.GE.3 ) THEN
               IF( T( HERE-1, HERE-2 ).NE.ZERO )
     $            NBNEXT = 2
            END IF
*
            LITRAF = ILNGTH(NBF+NBNEXT-1)
            LDTRAF = DLNGTH(NBF+NBNEXT-1)
            IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
               INFO = -6
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
               INFO = -8
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            CALL BSLAEXC( N, T, LDT, HERE-NBNEXT, NBNEXT, NBF,
     $                    ITRAF(CITRAF), DTRAF(CDTRAF), WORK, INFO )
            IF( INFO.NE.0 ) THEN
               ILST = HERE
               NITRAF = CITRAF - 1
               NDTRAF = CDTRAF - 1
               RETURN
            END IF
            CITRAF = CITRAF + LITRAF
            CDTRAF = CDTRAF + LDTRAF
            HERE = HERE - NBNEXT
*
*           Test if 2 by 2 block breaks into two 1 by 1 blocks
*
            IF( NBF.EQ.2 ) THEN
               IF( T( HERE+1, HERE ).EQ.ZERO )
     $            NBF = 3
            END IF
*
         ELSE
*
*           Current block consists of two 1 by 1 blocks each of which
*           must be swapped individually
*
            NBNEXT = 1
            IF( HERE.GE.3 ) THEN
               IF( T( HERE-1, HERE-2 ).NE.ZERO )
     $            NBNEXT = 2
            END IF
            LITRAF = ILNGTH(NBNEXT)
            LDTRAF = DLNGTH(NBNEXT)
            IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
               INFO = -6
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
               INFO = -8
               CALL XERBLA( 'BSTREXC', -INFO )
               RETURN
            END IF
            CALL BSLAEXC( N, T, LDT, HERE-NBNEXT, NBNEXT, 1,
     $                    ITRAF(CITRAF), DTRAF(CDTRAF), WORK, INFO )
            IF( INFO.NE.0 ) THEN
               ILST = HERE
               NITRAF = CITRAF - 1
               NDTRAF = CDTRAF - 1
               RETURN
            END IF
            CITRAF = CITRAF + LITRAF
            CDTRAF = CDTRAF + LDTRAF
*
            IF( NBNEXT.EQ.1 ) THEN
*
*              Swap two 1 by 1 blocks, no problems possible
*
               LITRAF = ILNGTH(1)
               LDTRAF = DLNGTH(1)
               IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
                  INFO = -6
                  CALL XERBLA( 'BSTREXC', -INFO )
                  RETURN
               END IF
               IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
                  INFO = -8
                  CALL XERBLA( 'BSTREXC', -INFO )
                  RETURN
               END IF
               CALL BSLAEXC( N, T, LDT, HERE, NBNEXT, 1, ITRAF(CITRAF),
     $                       DTRAF(CDTRAF), WORK, INFO )
               CITRAF = CITRAF + LITRAF
               CDTRAF = CDTRAF + LDTRAF
               HERE = HERE - 1
            ELSE
*
*              Recompute NBNEXT in case 2 by 2 split
*
               IF( T( HERE, HERE-1 ).EQ.ZERO )
     $            NBNEXT = 1
               IF( NBNEXT.EQ.2 ) THEN
*
*                 2 by 2 Block did not split
*
                  LITRAF = ILNGTH(2)
                  LDTRAF = DLNGTH(2)
                  IF( CITRAF+LITRAF-1.GT.NITRAF ) THEN
                     INFO = -6
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  IF( CDTRAF+LDTRAF-1.GT.NDTRAF ) THEN
                     INFO = -8
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  CALL BSLAEXC( N, T, LDT, HERE-1, 2, 1, ITRAF(CITRAF),
     $                          DTRAF(CDTRAF), WORK, INFO )
                  IF( INFO.NE.0 ) THEN
                     INFO = 2
                     ILST = HERE
                     NITRAF = CITRAF - 1
                     NDTRAF = CDTRAF - 1
                     RETURN
                  END IF
                  CITRAF = CITRAF + LITRAF
                  CDTRAF = CDTRAF + LDTRAF
                  HERE = HERE - 2
               ELSE
*
*                 2 by 2 Block did split
*
                  LITRAF = ILNGTH(1)
                  LDTRAF = DLNGTH(1)
                  IF( CITRAF+2*LITRAF-1.GT.NITRAF ) THEN
                     INFO = -6
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  IF( CDTRAF+2*LDTRAF-1.GT.NDTRAF ) THEN
                     INFO = -8
                     CALL XERBLA( 'BSTREXC', -INFO )
                     RETURN
                  END IF
                  CALL BSLAEXC( N, T, LDT, HERE, 1, 1, ITRAF(CITRAF),
     $                          DTRAF(CDTRAF), WORK, INFO )
                  CITRAF = CITRAF + LITRAF
                  CDTRAF = CDTRAF + LDTRAF
                  CALL BSLAEXC( N, T, LDT, HERE-1, 1, 1, ITRAF(CITRAF),
     $                          DTRAF(CDTRAF), WORK, INFO )
                  CITRAF = CITRAF + LITRAF
                  CDTRAF = CDTRAF + LDTRAF
                  HERE = HERE - 2
               END IF
            END IF
         END IF
         IF( HERE.GT.ILST )
     $      GO TO 20
      END IF
      ILST = HERE
      NITRAF = CITRAF - 1
      NDTRAF = CDTRAF - 1
*
      RETURN
*
*     End of BSTREXC
*
      END
