!   F08PPF Example Program Text
!   Mark 23 Release. NAG Copyright 2011.

    MODULE f08ppfe_mod

!      F08PPF Example Program Module:
!             Parameters and User-defined Routines

!      .. Use Statements ..
       USE nag_library, ONLY : nag_wp
!      .. Implicit None Statement ..
       IMPLICIT NONE
!      .. Parameters ..
       INTEGER, PARAMETER                  :: nb = 64, nin = 5, nout = 6
    CONTAINS
!dec$ attributes offload : mic :: select
       FUNCTION select(w)

!         Logical function select for use with ZGEESX (F08PPF)

!         Returns the value .TRUE. if the real part of the eigenvalue
!         w is positive.

!         .. Implicit None Statement ..
          IMPLICIT NONE
!         .. Function Return Value ..
          LOGICAL                             :: select
!         .. Scalar Arguments ..
          COMPLEX (KIND=nag_wp), INTENT (IN)  :: w
!         .. Local Scalars ..
          LOGICAL                             :: d
!         .. Intrinsic Functions ..
          INTRINSIC                              real
!         .. Executable Statements ..
          IF (real(w)>0.0_nag_wp) THEN
             d = .TRUE.
          ELSE
             d = .FALSE.
          END IF

          select = d

          RETURN
!dec$ attributes offload : mic :: select
       END FUNCTION select
    END MODULE f08ppfe_mod
    PROGRAM f08ppfe

!      F08PPF Example Main Program

!      .. Use Statements ..
       USE nag_library, ONLY : f06uaf, nag_wp, x02ajf, x04daf, zgeesx, zgemm
       USE f08ppfe_mod, ONLY : nb, nin, nout, select
!      .. Implicit None Statement ..
       IMPLICIT NONE
!      .. Local Scalars ..
       COMPLEX (KIND=nag_wp)               :: alpha, beta
       REAL (KIND=nag_wp)                  :: anorm, eps, rconde, rcondv, tol, &
                                              norm
       INTEGER                             :: i, ifail, info, lda, ldc, ldd,   &
                                              ldvs, lwork, n, sdim
!      .. Local Arrays ..
       COMPLEX (KIND=nag_wp), ALLOCATABLE  :: a(:,:), c(:,:), d(:,:), vs(:,:), &
                                              w(:), work(:)
       COMPLEX (KIND=nag_wp)               :: dummy(1)
       REAL (KIND=nag_wp), ALLOCATABLE     :: rwork(:)
       LOGICAL, ALLOCATABLE                :: bwork(:)
!      .. Intrinsic Functions ..
       INTRINSIC                              cmplx, max, nint, real
!      .. Executable Statements ..
       WRITE (nout,*) 'F08PPF Example Program Results'
       WRITE (nout,*)
       FLUSH (nout)

!      Skip heading in data file
       READ (nin,*)
       READ (nin,*) n
       lda = n
       ldc = n
       ldd = n
       ldvs = n
       ALLOCATE (a(lda,n),c(ldc,n),d(ldd,n),vs(ldvs,n),w(n),rwork(n),bwork(n))

!      Use routine workspace query to get optimal workspace.
       lwork = -1
!      The NAG name equivalent of zgeesx is f08ppf
       CALL zgeesx('Vectors (Schur)','Sort',select, &
          'Both reciprocal condition numbers',n,a,lda,sdim,w,vs,ldvs,rconde, &
          rcondv,dummy,lwork,rwork,bwork,info)

!      Make sure that there is enough workspace for blocksize nb.
       lwork = max(n*(nb+1+n/2),nint(real(dummy(1))))
       ALLOCATE (work(lwork))

!      Read in the matrix A
       READ (nin,*) (a(i,1:n),i=1,n)

!      Copy A into D
       d(1:n,1:n) = a(1:n,1:n)

!      Print matrix A
!      ifail: behaviour on error exit
!             =0 for hard exit, =1 for quiet-soft, =-1 for noisy-soft
       ifail = 0
       CALL x04daf('General',' ',n,n,a,lda,'Matrix A',ifail)

!      Find the Frobenius norms of A
       anorm = f06uaf('Frobenius',n,n,a,lda,rwork)

!      Find the Schur factorization of A
!      The NAG name equivalent of zgeesx is f08ppf
       CALL zgeesx('Vectors (Schur)','Sort',select, &
          'Both reciprocal condition numbers',n,a,lda,sdim,w,vs,ldvs,rconde, &
          rcondv,work,lwork,rwork,bwork,info)

       IF (info==0 .OR. info==(n+2)) THEN

!         Compute A - Z*T*Z**H from Schur factorization of A and store in 
!         matrix D. The NAG name equivelent of zgemm is f06zaf.
          alpha = cmplx(1,kind=nag_wp)
          beta = cmplx(0,kind=nag_wp)
          CALL zgemm('N','N',n,n,n,alpha,vs,ldvs,a,lda,beta,c,ldc)
          alpha = cmplx(-1,kind=nag_wp)
          beta = cmplx(1,kind=nag_wp)
          CALL zgemm('N','C',n,n,n,alpha,c,ldc,vs,ldvs,beta,d,ldd)

!         Find norm of matrix D and print warning if it is too large
          norm = f06uaf('O',ldd,n,d,ldd,rwork)
          IF (norm>x02ajf()**0.8_nag_wp) THEN
             WRITE (nout,*)
             WRITE (nout,*) 'Norm of A-(Z*T*Z^H) is much greater than 0.'
             WRITE (nout,*) 'Schur factorization has failed.'
          ELSE

             FLUSH (nout)

             WRITE (nout,*)
!            Print eigenvalues.
             WRITE (nout,*) 'Selected eigenvalues'
             WRITE (nout,99998) (w(i), i=1,sdim)
             WRITE (nout,*)

!            Print out the reciprocal condition numbers
             WRITE (nout,99997) &
                 'Reciprocal of projection norm onto the invariant', &
                 'subspace for the selected eigenvalues', 'RCONDE = ', rconde
             WRITE (nout,*)
             WRITE (nout,99996) &
                 'Reciprocal condition number for the invariant subspace', &
                 'RCONDV = ', rcondv

!            Compute the machine precision
             eps = x02ajf()
             tol = eps*anorm

!            Print out the approximate asymptotic error bound on the
!            average absolute error of the selected eigenvalues given by
!            eps*norm(A)/RCONDE
             WRITE (nout,*)
             WRITE (nout,99995) &
                  'Approximate asymptotic error bound for selected ', &
                  'eigenvalues   = ', tol/rconde

!            Print out an approximate asymptotic bound on the maximum
!            angular error in the computed invariant subspace given by
!            eps*norm(A)/RCONDV
             WRITE (nout,99995) &
                 'Approximate asymptotic error bound for the invariant ', &
                 'subspace = ', tol/rcondv
          END IF
       ELSE
          WRITE (nout,99994) 'Failure in ZGEESX. INFO =', info
       END IF

99999  FORMAT (1X,A,I4/1X,A)
99998  FORMAT (3X,' (',F7.4,',',F7.4,')':)
99997  FORMAT (1X,A/1X,A/1X,A,1P,E8.1)
99996  FORMAT (1X,A/1X,A,1P,E8.1)
99995  FORMAT (1X,2A,1P,E8.1)
99994  FORMAT (1X,A,I4)
    END PROGRAM f08ppfe
