      subroutine sszer(n,m,p,a,na,b,c,nc,d,eps,zeror,zeroi,nu,irank,af,
     &                 naf,bf,mplusn,wrka,wrk1,nwrk1,wrk2,nwrk2,ierr)
C
C! calling sequence
C
C        subroutine sszer(n,m,p,a,na,b,c,nc,d,zeror,zeroi,nu,irank,
C     1       af,naf,bf,mplusn,wrka,wrk1,nwrk1,wrk2,nwrk2,ierr)
C
C        integer n,m,p,na,nc,nu,irank,nabf,mplusn,nwrk1,nwrk2,ierr
C
C        double precision a(na,n),b(na,m),c(nc,n),d(nc,m),wrka(na,n)
C        double precision af(naf,mplusn),bf(naf,mplusn)
C        double precision wrk1(nwrk1),wrk2(nwrk2)
C        double precision zeror(n),zeroi(n)
C
C arguments in
C
C        n       integer
C                -the number of state variables in the system
C
C        m       integer
C                -the number of inputs to the system
C
C        p       integer
C                -the number of outputs from the system
C
C        a       double precision (n,n)
C                -the state dynamics matrix of the system
C
C        na      integer
C                -the declared first dimension of matrices a and b
C
C        b       double precision (n,m)
C                -the  input/state  matrix of the system
C
C        c       double precision (p,n)
C                -the  state/output  matrix of the system
C
C        nc      integer
C                -the declared first dimension of matrices  c and d
C
C        d       double precision (p,m)
C                -the  input/output  matrix of the system
C
C        naf     integer
C                -the declared first dimension of matrices  af and bf
C                 naf must be at least  n + p
C
C        mplusn  integer
C                -the second dimension of  af and bf.  mplusn  must be
C                at least  m + n .
C
C        nwrk1   integer
C                -the length of work vector wrk1.
C                nwrk1  must be at least  max(m,p)
C
C        nwrk2   integer
C                -the length of work vector  wrk2.
C                nwrk2  must be at least  max(n,m,p)+1
C
C arguments out
C
C        nu      integer
C                -the number of (finite) invariant zeros
C
C        irank   integer
C                -the normal rank of the transfer function
C
C        zeror   double precision (n)
C        zeroi   double precision (n)
C                -the real  and imaginary parts of the zeros
C
C        af      double precision ( n+p , m+n )
C        bf      double precision ( n+p , m+n )
C                -the coefficient matrices of the reduced pencil
C
C        ierr    integer
C                -error indicator
C
C                ierr = 0        successful return
C
C                ierr = 1        incorrect dimensions of matrices
C
C                ierr = 2        attempt to divide by zero
C
C                ierr = i > 2    ierr value i-2 from qitz (eispack)
C
C!working space
C
C        wrka    double precision (na,n)
C
C        wrk1    double precision (nwrk1)
C
C        wrk2    double precision (nwrk2)
C
C!purpose
C
C        to compute the invariant zeros of a linear multivariable
C        system given in state space form.
C
C!method
C
C        this routine extracts from the system matrix of a state-space
C        system  a,b,c,d  a regular pencil   lambda * bf  -  af
C        which has the invariant zeros of the system as generalized
C        eigenvalues.
C
C!reference
C
C        emami-naeini, a. and van dooren, p.
C        'computation of zeros of linear multivariable systems'
C        report na-80-03, computer science department, stanford univ.
C
C!originator
C
C                a.emami-naeini, computer science department,
C                stanford university.
C     Copyrigth SLICE
C
      integer n,m,p,na,nc,nu,irank,naf,mplusn,nwrk1,nwrk2,ierr
C
      double precision a(na,n),b(na,m),c(nc,n),d(nc,m)
      double precision wrka(na,n),zeror(n),zeroi(n)
      double precision af(naf,mplusn),bf(naf,mplusn),wrk1(nwrk1),
     &                 wrk2(nwrk2)
      double precision eps,sum,heps,xxx(1,1)
C
C       local variables:
C
      logical zero,matq,matz
C
      integer mm,nn,pp,mu,iro,isigma,numu,mnu,numu1,mnu1,i,j,j1
      integer mj,ni,nu1
C
      double precision s
      ierr = 1
      if (na .lt. n) return
      if (nc .lt. p) return
      if (naf .lt. n+p) return
      if (nwrk1 .lt. m) return
      if (nwrk1 .lt. p) return
      if (nwrk2 .lt. n) return
      if (nwrk2 .lt. m) return
      if (nwrk2 .lt. p) return
      if (mplusn .lt. m+n) return
      ierr = 0
C       construct the compound matrix (b      a) of dimension
C                                     (d      c)
C       (n + p) * (m + n)
C
      sum = 0.0d+0
      do 30 i = 1,n
        do 10 j = 1,m
          bf(i,j) = b(i,j)
          sum = sum + (b(i,j)*b(i,j))
 10     continue
        do 30 j = 1,n
          mj = m + j
          bf(i,mj) = a(i,j)
          sum = sum + (a(i,j)*a(i,j))
 30   continue
C
      do 60 i = 1,p
        ni = n + i
        do 40 j = 1,m
          bf(ni,j) = d(i,j)
          sum = sum + (d(i,j)*d(i,j))
 40     continue
        do 60 j = 1,n
          mj = m + j
          bf(ni,mj) = c(i,j)
          sum = sum + (c(i,j)*c(i,j))
 60   continue
C
      heps = eps * sqrt(sum)
C
C       reduce this system to one with the same invariant zeros and with
C       d full row rank mu (the normal rank of the original system)
C
      iro = p
      isigma = 0
C
      call preduc(bf,naf,mplusn,m,n,p,heps,iro,isigma,mu,nu,wrk1,nwrk1,
     &            wrk2,nwrk2)
C
      irank = mu
      if (nu .eq. 0) return
C
C       pertranspose the system
C
      numu = nu + mu
      mnu = m + nu
      numu1 = numu + 1
      mnu1 = mnu + 1
      do 70 i = 1,numu
        ni = numu1 - i
        do 70 j = 1,mnu
          mj = mnu1 - j
          af(mj,ni) = bf(i,j)
 70   continue
C
      mm = m
      nn = n
      pp = p
      if (mu .eq. mm) goto 80
      pp = mm
      nn = nu
      mm = mu
C
C       reduce the system to one with the same invariant zeros and with
C       d square and of full rank
C
      iro = pp - mm
      isigma = mm
C
      call preduc(af,naf,mplusn,mm,nn,pp,heps,iro,isigma,mu,nu,wrk1,
     &            nwrk1,wrk2,nwrk2)
C
      if (nu .eq. 0) return
      mnu = mm + nu
 80   continue
      do 100 i = 1,nu
        ni = mm + i
        do 90 j = 1,mnu
          bf(i,j) = 0.0d+0
 90     continue
        bf(i,ni) = 1.0d+0
 100  continue
C
      if (irank .eq. 0) return
      nu1 = nu + 1
      numu = nu + mu
      j1 = mm
      do 120 i = 1,mm
        j1 = j1 - 1
        do 110 j = 1,nu1
          mj = j1 + j
          wrk2(j) = af(numu,mj)
 110    continue
C
        call house(wrk2,nu1,nu1,heps,zero,s)
        call tr2(af,naf,mplusn,wrk2,s,1,numu,j1,nu1)
        call tr2(bf,naf,mplusn,wrk2,s,1,nu,j1,nu1)
C
        numu = numu - 1
 120  continue
      matz = .false.
      matq = .false.
Cc
      call qhesz(naf,nu,af,bf,matq,xxx,matz,wrka)
      call qitz(naf,nu,af,bf,eps,matq,xxx,matz,wrka,ierr)
      if (ierr .ne. 0) goto 150
Cc
      call qvalz(naf,nu,af,bf,eps,zeror,zeroi,wrk2,matq,xxx,matz,wrka)
Cc
C         do 130 i = 1,nu
C            if (wrk2(i) .eq. 0.0d+0) go to 140
C            zeror(i) = zeror(i)/wrk2(i)
C            zeroi(i) = zeroi(i)/wrk2(i)
C  130       continue
Cc
Cc       successful completion
Cc
      ierr = 0
      return
Cc
Cc       attempt to divide by zero
Cc
C  140    ierr = 2
C         return
Cc
Cc       failure in subroutine qzit
Cc
 150  ierr = ierr + 2
      return
      end
        subroutine preduc(abf,naf,mplusn,m,n,p,heps,iro,isigma,mu,nu,
     1                    wrk1,nwrk1,wrk2,nwrk2)
c%calling sequence
c       subroutine preduc(abf,naf,mplusn,m,n,p,heps,iro,isigma,mu,nu,
c    1                    wrk1,nwrk1,wrk2,nwrk2)
c       integer naf,mplusn,m,n,p,iro,isigma,mu,nu,nwrk1,nwrk2
c       double precision abf(naf,mplusn),wrk1(nwrk1),wrk2(nwrk2)
c
c%purpose
c
c     this routine is only to be called from slice routine sszer
c%
        integer naf,mplusn,m,n,p,iro,isigma,mu,nu,nwrk1,nwrk2
c
        double precision abf(naf,mplusn),wrk1(nwrk1),wrk2(nwrk2)
c
c       local variables:
c
        integer i,j,i1,m1,n1,i2,mm1,mn1,irj,itau,iro1,icol
        integer ibar,numu,irow
c
        logical zero
c
        double precision s,temp
c
        double precision sum,heps
c
c
        mu = p
        nu = n
 10     if (mu .eq. 0) return
        iro1 = iro
        mnu = m + nu
        numu = nu + mu
        if (m .eq. 0) go to 120
        iro1 = iro1 + 1
        irow = nu
        if (isigma .le. 1) go to 40
c
c       compress rows of d: first exploit triangular shape
c
        m1 = isigma - 1
        do 30 icol = 1,m1
           do 20 j = 1,iro1
              irj = irow + j
              wrk2(j) = abf(irj,icol)
 20           continue
c
           call house(wrk2,iro1,1,heps,zero,s)
c
           call tr1(abf,naf,mplusn,wrk2,s,irow,iro1,icol,mnu)
c
           irow = irow + 1
 30        continue
c
c       continue with householder transformation with pivoting
c
 40     if (isigma .ne. 0) go to 45
        isigma = 1
        iro1 = iro1 - 1
 45     if (isigma .eq. m) go to 60
        do 55 icol = isigma,m
           sum = 0.0d+0
           do 50 j = 1,iro1
              irj = irow + j
              sum = sum + (abf(irj,icol) * abf(irj,icol) )
 50           continue
           wrk1(icol) = sum
 55        continue
c
 60     continue
        do 100 icol = isigma,m
c
c          pivot if necessary
c
           if (icol .eq. m) go to 80
c
           call pivot(wrk1,temp,ibar,icol,m)
c
           if (ibar .eq. icol) go to 80
           wrk1(ibar) = wrk1(icol)
           wrk1(icol) = temp
           do 70 i = 1,numu
              temp = abf(i,icol)
              abf(i,icol) = abf(i,ibar)
 70           abf(i,ibar) = temp
c
c          perform householder transformation
c
 80        continue
           do 90 i = 1,iro1
              irj = irow + i
 90           wrk2(i) = abf(irj,icol)
c
           call house(wrk2,iro1,1,heps,zero,s)
c
           if (zero) go to 120
           if (iro1 .eq. 1) return
c
           call tr1(abf,naf,mplusn,wrk2,s,irow,iro1,icol,mnu)
c
           irow = irow + 1
           iro1 = iro1 - 1
           do 100 j = icol,m
 100          wrk1(j) = wrk1(j) - (abf(irow,j) * abf(irow,j) )
c
 120    itau = iro1
        isigma = mu - itau
c
c       compress the columns of c
c
        i1 = nu + isigma
        mm1 = m + 1
        n1 = nu
        if (itau .eq. 1) go to 140
        do 135 i = 1,itau
           irj = i1 + i
           sum = 0.0d+0
           do 130 j = mm1,mnu
 130          sum = sum + (abf(irj,j) * abf(irj,j) )
 135       wrk1(i) = sum
c
 140    continue
        do 200 iro1 = 1,itau
           iro = iro1 - 1
           i = itau - iro
           i2 = i + i1
c
c          pivot if necessary
c
           if (i .eq. 1) go to 160
c
           call pivot(wrk1,temp,ibar,1,i)
c
           if (ibar .eq. i) go to 160
           wrk1(ibar) = wrk1(i)
           wrk1(i) = temp
           irj = ibar + i1
           do 150 j = mm1,mnu
              temp = abf(i2,j)
              abf(i2,j) = abf(irj,j)
 150          abf(irj,j) = temp
c
c          perform householder transformation
c
 160       do 170 j = 1,n1
              irj = m + j
 170          wrk2(j) = abf(i2,irj)
c
           call house(wrk2,n1,n1,heps,zero,s)
c
           if (zero) go to 210
           if (n1 .eq. 1) go to 220
c
           call tr2(abf,naf,mplusn,wrk2,s,1,i2,m,n1)
c
           mn1 = m + n1
c
           call tr1(abf,naf,mplusn,wrk2,s,0,n1,1,mn1)
c
           do 190 j = 1,i
              irj = i1 + j
 190          wrk1(j) = wrk1(j) - (abf(irj,mn1) * abf(irj,mn1) )
           mnu = mnu - 1
 200       n1 = n1 - 1
c
        iro = itau
 210    nu = nu - iro
        mu = isigma + iro
        if (iro .eq. 0) return
        go to 10
c
 220    mu = isigma
        nu = 0
c
        return
        end
        subroutine house(wrk2,k,j,heps,zero,s)
c
c  warning - this routine is only to be called from slice routine
c            sszer
c
c% purpose
c       this routine constructs a householder transformation h = i-s.uu
c       that 'mirrors' a vector wrk2(1,...,k) to the j-th unit vector.
c       if norm(wrk2) < heps, zero is put equal to .true.
c       upon return, u is stored in wrk2
c
c%
        integer k,j
c
        double precision wrk2(k),heps,s
c
        logical zero
c
c       local variables:
c
        integer i
c
        double precision alfa,dum1
c
        double precision sum
c
c
        zero = .true.
        sum = 0.0d+0
        do 10 i = 1,k
 10        sum = sum + (wrk2(i) * wrk2(i) )
c
        alfa = sqrt(sum)
        if (alfa .le. heps) return
c
        zero = .false.
        dum1 = wrk2(j)
        if (dum1 .gt. 0.0d+0) alfa = -alfa
        wrk2(j) = dum1 - alfa
        s = 1.0d+0 / (sum - (alfa * dum1) )
c
        return
        end

        subroutine tr1(a,na,n,u,s,i1,i2,j1,j2)
c% calling sequence
c
c        subroutine tr1(a,na,n,u,s,i1,i2,j1,j2)
c
c%purpose
c
c       this subroutine performs the householder transformation
c                       h = i - s.uu
c       on the rows i1 + 1 to i1 + i2 of a, this from columns j1 to j2.
c% comments
c
c  warning - this routine is only to be called from slice routine
c            sszer
c
c%
        integer na,n,i1,i2,j1,j2
c
        double precision a(na,n),u(i2),s
c
c       local variables:
c
        integer i,j,irj
c
        double precision y
c
        double precision sum
c
c
        do 20 j = j1,j2
           sum = 0.0d+0
           do 10 i = 1,i2
              irj = i1 + i
 10           sum = sum + (u(i) * a(irj,j) )
c
           y = sum * s
c
           do 20 i = 1,i2
              irj = i1 + i
 20           a(irj,j) = a(irj,j) - (u(i) * y)
c
        return
        end

        subroutine tr2(a,na,n,u,s,i1,i2,j1,j2)
c% calling sequence
c
c        subroutine tr2(a,na,n,u,s,i1,i2,j1,j2)
c%purpose
c
c       this routine performs the householder transformation h = i-s.uu
c       on the columns j1 + 1 to j1 + j2 of a, this from rows i1 to i2.
c
c% comments
c
c  warning - this routine is only to be called from slice routine
c            sszer
c%
        integer na,n,i1,i2,j1,j2
c
        double precision a(na,n),u(j2),s
c
c       local variables:
c
        integer i,j,irj
c
        double precision y
c
        double precision sum
c
c
        do 20 i = i1,i2
          sum = 0.0d+0
           do 10 j = 1,j2
              irj = j1 + j
 10           sum = sum + (u(j) * a(i,irj) )
c
           y = sum * s
c
           do 20 j = 1,j2
              irj = j1 + j
 20           a(i,irj) = a(i,irj) - (u(j) * y)
c
        return
        end

        subroutine pivot(vec,vmax,ibar,i1,i2)
c% calling sequence
c       subroutine pivot(vec,vmax,ibar,i1,i2)
c       integer ibar,i1,i2
c       double precision vec(i2),vmax
c
c% purpose
c
c       this subroutine computes the maximal norm element (vthe max)
c       of the vector vec(i1,...,i2), and its location ibar
c
c       this routine is only to be called from slice routine sszer
c
c%
        integer ibar,i1,i2
c
        double precision vec(i2),vmax
c
c       local variables:
c
        integer i,i11
c
c
        ibar = i1
        vmax = vec(i1)
        if (i1 .ge. i2) go to 20
        i11 = i1 + 1
        do 10 i = i11,i2
           if (abs(vec(i) ) .lt. vmax) go to 10
           vmax = abs (vec(i) )
           ibar = i
  10       continue
c
  20    if (vec(ibar) .lt. 0.0d+0) vmax = -vmax
c
        return
        end
