      subroutine dsubsp (nmax,n,a,b,z,ftest,eps,ndim,fail,ind)
      external ftest
      integer nmax,n,ftest,ndim,ind(n)
      logical fail
      double precision a(nmax,n),b(nmax,n),z(nmax,n),eps
c!purpose
c  given the upper triangular matrix b and upper hessenberg matrix a
c  with 1x1 or 2x2 diagonal blocks, this routine reorders the diagonal
c  blocks along with their generalized eigenvalues by constructing equi-
c  valence transformations qt and zt. the row transformation zt is also
c  performed on the given (initial) transformation z (resulting from a
c  possible previous step or initialized with the identity matrix).
c  after reordering, the eigenvalues inside the region specified by the
c  function ftest appear at the top. if ndim is their number then the
c  ndim first columns of z span the requested subspace.
c!calling sequence
c
c     subroutine dsubsp (nmax,n,a,b,z,ftest,eps,ndim,fail,ind)
c     integer nmax,n,ftest,ndim,ind(n)
c     logical fail
c     double precision a(nmax,n),b(nmax,n),z(nmax,n),eps
c
c     nmax     the first dimension of a, b and z
c     n        the order of a, b and z
c    *a,*b     the matrix pair whose blocks are to be reordered.
c    *z        upon return this array is multiplied by the column
c              transformation zt.
c     ftest(ls,alpha,beta,s,p) an integer function describing the
c              spectrum of the deflating subspace to be computed:
c              when ls=1 ftest checks if alpha/beta is in that spectrum
c              when ls=2 ftest checks if the two complex conjugate
c              roots with sum s and product p are in that spectrum
c              if the answer is positive, ftest=1, otherwise ftest=-1
c     eps      the required absolute accuracy of the result
c    *ndim     an integer giving the dimension of the computed
c              deflating subspace
c    *fail     a logical variable which is false on a normal return,
c              true otherwise (when exchqz fails)
c    *ind      an integer working array of dimension at least n
c
c!auxiliary routines
c     exchqz
c     ftest  (user defined)
c!author Paul van Dooren
c
      integer l,ls,ls1,ls2,l1,ll,num,is,l2i,l2k,i,k,ii,istep,ifirst
      double precision s,p,d,alpha,beta
      integer         iero
      common /ierinv/ iero
      iero=0

      fail=.true.
      ndim=0
      num=0
      l=0
      ls=1
c ** construct array ind(i) where :
c **      abs(ind(i)) is the size of the block i
c **     sign(ind(i)) indicates the location of its eigenvalues
c **                  (as determined by ftest).
c ** num is the number of elements in this array
      do 40 ll=1,n
        l=l+ls
        if(l.gt.n) go to 50
        l1=l+1
        if(l1.gt.n) go to 20
        if(a(l1,l).eq.0.0d+0) go to 20
c  here a 2x2  block is checked *
        ls=2
        d=b(l,l)*b(l1,l1)
        s=(a(l,l)*b(l1,l1)+a(l1,l1)*b(l,l)-a(l1,l)*b(l,l1))/d
        p=(a(l,l)*a(l1,l1)-a(l,l1)*a(l1,l))/d
        is=ftest(ls,alpha,beta,s,p)
        if(iero.gt.0) return
        go to 30
c  here a 1x1  block is checked *
 20     ls=1
        is=ftest(ls,a(l,l),b(l,l),s,p)
        if(iero.gt.0) return
 30     num=num+1
        if(is.eq.1) ndim=ndim+ls
 40     ind(num)=ls*is
c **  reorder blocks such that those with positive value
c **    of ind(.) appear first.
 50   l2i=1
      do 90 i=1,num
        if(ind(i).gt.0) go to 90
c  if a negative ind(i) is encountered, then search for the first
c  positive ind(k) following on it
        l2k=l2i
        do 60 k=i,num
          if(ind(k).lt.0) go to 60
          go to 70
 60       l2k=l2k-ind(k)
c  if there are no positive indices following on a negative one
c  then stop
        go to 100
c  if a positive ind(k) follows on a negative ind(i) then
c  interchange block k before block i by performing k-i swaps
 70     istep=k-i
        ls2=ind(k)
        l=l2k
        do 80 ii=1,istep
          ifirst=k-ii
          ls1=-ind(ifirst)
          l=l-ls1
          call exchqz (nmax,n,a,b,z,l,ls1,ls2,eps,fail)
          if (fail) return
 80       ind(ifirst+1)=ind(ifirst)
        ind(i)=ls2
 90     l2i=l2i+ind(i)
 100  fail=.false.
      return
      end
