text: #include "blaswrap.h"
  #include "f2c.h"
  
  /* Subroutine */ int zgees_(char *jobvs, char *sort, L_fp select, integer *n, 
  	doublecomplex *a, integer *lda, integer *sdim, doublecomplex *w, 
  	doublecomplex *vs, integer *ldvs, doublecomplex *work, integer *lwork,
  	 doublereal *rwork, logical *bwork, integer *info)
  {
  /*  -- LAPACK driver routine (version 3.0) --   
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,   
         Courant Institute, Argonne National Lab, and Rice University   
         June 30, 1999   
  
  
      Purpose   
      =======   
  
      ZGEES computes for an N-by-N complex nonsymmetric matrix A, the   
      eigenvalues, the Schur form T, and, optionally, the matrix of Schur   
      vectors Z.  This gives the Schur factorization A = Z*T*(Z**H).   
  
      Optionally, it also orders the eigenvalues on the diagonal of the   
      Schur form so that selected eigenvalues are at the top left.   
      The leading columns of Z then form an orthonormal basis for the   
      invariant subspace corresponding to the selected eigenvalues.   
  
      A complex matrix is in Schur form if it is upper triangular.   
  
      Arguments   
      =========   
  
      JOBVS   (input) CHARACTER*1   
              = 'N': Schur vectors are not computed;   
              = 'V': Schur vectors are computed.   
  
      SORT    (input) CHARACTER*1   
              Specifies whether or not to order the eigenvalues on the   
              diagonal of the Schur form.   
              = 'N': Eigenvalues are not ordered:   
              = 'S': Eigenvalues are ordered (see SELECT).   
  
      SELECT  (input) LOGICAL FUNCTION of one COMPLEX*16 argument   
              SELECT must be declared EXTERNAL in the calling subroutine.   
              If SORT = 'S', SELECT is used to select eigenvalues to order   
              to the top left of the Schur form.   
              IF SORT = 'N', SELECT is not referenced.   
              The eigenvalue W(j) is selected if SELECT(W(j)) is true.   
  
      N       (input) INTEGER   
              The order of the matrix A. N >= 0.   
  
      A       (input/output) COMPLEX*16 array, dimension (LDA,N)   
              On entry, the N-by-N matrix A.   
              On exit, A has been overwritten by its Schur form T.   
  
      LDA     (input) INTEGER   
              The leading dimension of the array A.  LDA >= max(1,N).   
  
      SDIM    (output) INTEGER   
              If SORT = 'N', SDIM = 0.   
              If SORT = 'S', SDIM = number of eigenvalues for which   
                             SELECT is true.   
  
      W       (output) COMPLEX*16 array, dimension (N)   
              W contains the computed eigenvalues, in the same order that   
              they appear on the diagonal of the output Schur form T.   
  
      VS      (output) COMPLEX*16 array, dimension (LDVS,N)   
              If JOBVS = 'V', VS contains the unitary matrix Z of Schur   
              vectors.   
              If JOBVS = 'N', VS is not referenced.   
  
      LDVS    (input) INTEGER   
              The leading dimension of the array VS.  LDVS >= 1; if   
              JOBVS = 'V', LDVS >= N.   
  
      WORK    (workspace/output) COMPLEX*16 array, dimension (LWORK)   
              On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
  
      LWORK   (input) INTEGER   
              The dimension of the array WORK.  LWORK >= max(1,2*N).   
              For good performance, LWORK must generally be larger.   
  
              If LWORK = -1, then a workspace query is assumed; the routine   
              only calculates the optimal size of the WORK array, returns   
              this value as the first entry of the WORK array, and no error   
              message related to LWORK is issued by XERBLA.   
  
      RWORK   (workspace) DOUBLE PRECISION array, dimension (N)   
  
      BWORK   (workspace) LOGICAL array, dimension (N)   
              Not referenced if SORT = 'N'.   
  
      INFO    (output) INTEGER   
              = 0: successful exit   
              < 0: if INFO = -i, the i-th argument had an illegal value.   
              > 0: if INFO = i, and i is   
                   <= N:  the QR algorithm failed to compute all the   
                          eigenvalues; elements 1:ILO-1 and i+1:N of W   
                          contain those eigenvalues which have converged;   
                          if JOBVS = 'V', VS contains the matrix which   
                          reduces A to its partially converged Schur form.   
                   = N+1: the eigenvalues could not be reordered because   
                          some eigenvalues were too close to separate (the   
                          problem is very ill-conditioned);   
                   = N+2: after reordering, roundoff changed values of   
                          some complex eigenvalues so that leading   
                          eigenvalues in the Schur form no longer satisfy   
                          SELECT = .TRUE..  This could also be caused by   
                          underflow due to scaling.   
  
      =====================================================================   
  
  
         Test the input arguments   
  
         Parameter adjustments */
      /* Table of constant values */
      static integer c__1 = 1;
      static integer c__0 = 0;
      static integer c__8 = 8;
      static integer c_n1 = -1;
      static integer c__4 = 4;
      
      /* System generated locals */
      integer a_dim1, a_offset, vs_dim1, vs_offset, i__1, i__2, i__3, i__4;
      /* Builtin functions */
      double sqrt(doublereal);
      /* Local variables */
      static integer ibal, maxb;
      static doublereal anrm;
      static integer ierr, itau, iwrk, i__, k;
      static doublereal s;
      static integer icond, ieval;
      extern logical lsame_(char *, char *);
      extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, 
  	    doublecomplex *, integer *), dlabad_(doublereal *, doublereal *);
      static logical scalea;
      extern doublereal dlamch_(char *);
      static doublereal cscale;
      extern /* Subroutine */ int zgebak_(char *, char *, integer *, integer *, 
  	    integer *, doublereal *, integer *, doublecomplex *, integer *, 
  	    integer *), zgebal_(char *, integer *, 
  	    doublecomplex *, integer *, integer *, integer *, doublereal *, 
  	    integer *), xerbla_(char *, integer *);
      extern integer ilaenv_(integer *, char *, char *, integer *, integer *, 
  	    integer *, integer *, ftnlen, ftnlen);
      extern doublereal zlange_(char *, integer *, integer *, doublecomplex *, 
  	    integer *, doublereal *);
      static doublereal bignum;
      extern /* Subroutine */ int zgehrd_(integer *, integer *, integer *, 
  	    doublecomplex *, integer *, doublecomplex *, doublecomplex *, 
  	    integer *, integer *), zlascl_(char *, integer *, integer *, 
  	    doublereal *, doublereal *, integer *, integer *, doublecomplex *,
  	     integer *, integer *), zlacpy_(char *, integer *, 
  	    integer *, doublecomplex *, integer *, doublecomplex *, integer *);
      static integer minwrk, maxwrk;
      static doublereal smlnum;
      extern /* Subroutine */ int zhseqr_(char *, char *, integer *, integer *, 
  	    integer *, doublecomplex *, integer *, doublecomplex *, 
  	    doublecomplex *, integer *, doublecomplex *, integer *, integer *);
      static integer hswork;
      extern /* Subroutine */ int zunghr_(integer *, integer *, integer *, 
  	    doublecomplex *, integer *, doublecomplex *, doublecomplex *, 
  	    integer *, integer *);
      static logical wantst, lquery, wantvs;
      extern /* Subroutine */ int ztrsen_(char *, char *, logical *, integer *, 
  	    doublecomplex *, integer *, doublecomplex *, integer *, 
  	    doublecomplex *, integer *, doublereal *, doublereal *, 
  	    doublecomplex *, integer *, integer *);
      static integer ihi, ilo;
      static doublereal dum[1], eps, sep;
  
  
      a_dim1 = *lda;
      a_offset = 1 + a_dim1 * 1;
      a -= a_offset;
      --w;
      vs_dim1 = *ldvs;
      vs_offset = 1 + vs_dim1 * 1;
      vs -= vs_offset;
      --work;
      --rwork;
      --bwork;
  
      /* Function Body */
      *info = 0;
      lquery = *lwork == -1;
      wantvs = lsame_(jobvs, "V");
      wantst = lsame_(sort, "S");
      if (! wantvs && ! lsame_(jobvs, "N")) {
  	*info = -1;
      } else if (! wantst && ! lsame_(sort, "N")) {
  	*info = -2;
      } else if (*n < 0) {
  	*info = -4;
      } else if (*lda < max(1,*n)) {
  	*info = -6;
      } else if (*ldvs < 1 || wantvs && *ldvs < *n) {
  	*info = -10;
      }
  
  /*     Compute workspace   
          (Note: Comments in the code beginning "Workspace:" describe the   
           minimal amount of workspace needed at that point in the code,   
           as well as the preferred amount for good performance.   
           CWorkspace refers to complex workspace, and RWorkspace to real   
           workspace. NB refers to the optimal block size for the   
           immediately following subroutine, as returned by ILAENV.   
           HSWORK refers to the workspace preferred by ZHSEQR, as   
           calculated below. HSWORK is computed assuming ILO=1 and IHI=N,   
           the worst case.) */
  
      minwrk = 1;
      if (*info == 0 && (*lwork >= 1 || lquery)) {
  	maxwrk = *n + *n * ilaenv_(&c__1, "ZGEHRD", " ", n, &c__1, n, &c__0, (
  		ftnlen)6, (ftnlen)1);
  /* Computing MAX */
  	i__1 = 1, i__2 = *n << 1;
  	minwrk = max(i__1,i__2);
  	if (! wantvs) {
  /* Computing MAX */
  	    i__1 = ilaenv_(&c__8, "ZHSEQR", "SN", n, &c__1, n, &c_n1, (ftnlen)
  		    6, (ftnlen)2);
  	    maxb = max(i__1,2);
  /* Computing MIN   
     Computing MAX */
  	    i__3 = 2, i__4 = ilaenv_(&c__4, "ZHSEQR", "SN", n, &c__1, n, &
  		    c_n1, (ftnlen)6, (ftnlen)2);
  	    i__1 = min(maxb,*n), i__2 = max(i__3,i__4);
  	    k = min(i__1,i__2);
  /* Computing MAX */
  	    i__1 = k * (k + 2), i__2 = *n << 1;
  	    hswork = max(i__1,i__2);
  /* Computing MAX */
  	    i__1 = max(maxwrk,hswork);
  	    maxwrk = max(i__1,1);
  	} else {
  /* Computing MAX */
  	    i__1 = maxwrk, i__2 = *n + (*n - 1) * ilaenv_(&c__1, "ZUNGHR", 
  		    " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)1);
  	    maxwrk = max(i__1,i__2);
  /* Computing MAX */
  	    i__1 = ilaenv_(&c__8, "ZHSEQR", "EN", n, &c__1, n, &c_n1, (ftnlen)
  		    6, (ftnlen)2);
  	    maxb = max(i__1,2);
  /* Computing MIN   
     Computing MAX */
  	    i__3 = 2, i__4 = ilaenv_(&c__4, "ZHSEQR", "EN", n, &c__1, n, &
  		    c_n1, (ftnlen)6, (ftnlen)2);
  	    i__1 = min(maxb,*n), i__2 = max(i__3,i__4);
  	    k = min(i__1,i__2);
  /* Computing MAX */
  	    i__1 = k * (k + 2), i__2 = *n << 1;
  	    hswork = max(i__1,i__2);
  /* Computing MAX */
  	    i__1 = max(maxwrk,hswork);
  	    maxwrk = max(i__1,1);
  	}
  	work[1].r = (doublereal) maxwrk, work[1].i = 0.;
      }
      if (*lwork < minwrk && ! lquery) {
  	*info = -12;
      }
      if (*info != 0) {
  	i__1 = -(*info);
  	xerbla_("ZGEES ", &i__1);
  	return 0;
      } else if (lquery) {
  	return 0;
      }
  
  /*     Quick return if possible */
  
      if (*n == 0) {
  	*sdim = 0;
  	return 0;
      }
  
  /*     Get machine constants */
  
      eps = dlamch_("P");
      smlnum = dlamch_("S");
      bignum = 1. / smlnum;
      dlabad_(&smlnum, &bignum);
      smlnum = sqrt(smlnum) / eps;
      bignum = 1. / smlnum;
  
  /*     Scale A if max element outside range [SMLNUM,BIGNUM] */
  
      anrm = zlange_("M", n, n, &a[a_offset], lda, dum);
      scalea = FALSE_;
      if (anrm > 0. && anrm < smlnum) {
  	scalea = TRUE_;
  	cscale = smlnum;
      } else if (anrm > bignum) {
  	scalea = TRUE_;
  	cscale = bignum;
      }
      if (scalea) {
  	zlascl_("G", &c__0, &c__0, &anrm, &cscale, n, n, &a[a_offset], lda, &
  		ierr);
      }
  
  /*     Permute the matrix to make it more nearly triangular   
         (CWorkspace: none)   
         (RWorkspace: need N) */
  
      ibal = 1;
      zgebal_("P", n, &a[a_offset], lda, &ilo, &ihi, &rwork[ibal], &ierr);
  
  /*     Reduce to upper Hessenberg form   
         (CWorkspace: need 2*N, prefer N+N*NB)   
         (RWorkspace: none) */
  
      itau = 1;
      iwrk = *n + itau;
      i__1 = *lwork - iwrk + 1;
      zgehrd_(n, &ilo, &ihi, &a[a_offset], lda, &work[itau], &work[iwrk], &i__1,
  	     &ierr);
  
      if (wantvs) {
  
  /*        Copy Householder vectors to VS */
  
  	zlacpy_("L", n, n, &a[a_offset], lda, &vs[vs_offset], ldvs)
  		;
  
  /*        Generate unitary matrix in VS   
            (CWorkspace: need 2*N-1, prefer N+(N-1)*NB)   
            (RWorkspace: none) */
  
  	i__1 = *lwork - iwrk + 1;
  	zunghr_(n, &ilo, &ihi, &vs[vs_offset], ldvs, &work[itau], &work[iwrk],
  		 &i__1, &ierr);
      }
  
      *sdim = 0;
  
  /*     Perform QR iteration, accumulating Schur vectors in VS if desired   
         (CWorkspace: need 1, prefer HSWORK (see comments) )   
         (RWorkspace: none) */
  
      iwrk = itau;
      i__1 = *lwork - iwrk + 1;
      zhseqr_("S", jobvs, n, &ilo, &ihi, &a[a_offset], lda, &w[1], &vs[
  	    vs_offset], ldvs, &work[iwrk], &i__1, &ieval);
      if (ieval > 0) {
  	*info = ieval;
      }
  
  /*     Sort eigenvalues if desired */
  
      if (wantst && *info == 0) {
  	if (scalea) {
  	    zlascl_("G", &c__0, &c__0, &cscale, &anrm, n, &c__1, &w[1], n, &
  		    ierr);
  	}
  	i__1 = *n;
  	for (i__ = 1; i__ <= i__1; ++i__) {
  	    bwork[i__] = (*select)(&w[i__]);
  /* L10: */
  	}
  
  /*        Reorder eigenvalues and transform Schur vectors   
            (CWorkspace: none)   
            (RWorkspace: none) */
  
  	i__1 = *lwork - iwrk + 1;
  	ztrsen_("N", jobvs, &bwork[1], n, &a[a_offset], lda, &vs[vs_offset], 
  		ldvs, &w[1], sdim, &s, &sep, &work[iwrk], &i__1, &icond);
      }
  
      if (wantvs) {
  
  /*        Undo balancing   
            (CWorkspace: none)   
            (RWorkspace: need N) */
  
  	zgebak_("P", "R", n, &ilo, &ihi, &rwork[ibal], n, &vs[vs_offset], 
  		ldvs, &ierr);
      }
  
      if (scalea) {
  
  /*        Undo scaling for the Schur form of A */
  
  	zlascl_("U", &c__0, &c__0, &cscale, &anrm, n, n, &a[a_offset], lda, &
  		ierr);
  	i__1 = *lda + 1;
  	zcopy_(n, &a[a_offset], &i__1, &w[1], &c__1);
      }
  
      work[1].r = (doublereal) maxwrk, work[1].i = 0.;
      return 0;
  
  /*     End of ZGEES */
  
  } /* zgees_ */
  
  