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

    MODULE e04ugae_mod

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

!      .. Use Statements ..
       USE nag_library, ONLY : nag_wp
!      .. Implicit None Statement ..
       IMPLICIT NONE
!      .. Parameters ..
       INTEGER, PARAMETER                  :: lcwsav = 1, liwsav = 550,        &
                                              llwsav = 20, lrwsav = 550,       &
                                              nin = 5, nout = 6
    CONTAINS
!dec$ attributes offload : mic :: confun
       SUBROUTINE confun(mode,ncnln,njnln,nnzjac,x,f,fjac,nstate,iuser,ruser)
!         Computes the nonlinear constraint functions and their Jacobian.

!         .. Implicit None Statement ..
          IMPLICIT NONE
!         .. Scalar Arguments ..
          INTEGER, INTENT (INOUT)             :: mode
          INTEGER, INTENT (IN)                :: ncnln, njnln, nnzjac, nstate
!         .. Array Arguments ..
          REAL (KIND=nag_wp), INTENT (OUT)    :: f(ncnln)
          REAL (KIND=nag_wp), INTENT (INOUT)  :: fjac(nnzjac), ruser(*)
          REAL (KIND=nag_wp), INTENT (IN)     :: x(njnln)
          INTEGER, INTENT (INOUT)             :: iuser(*)
!         .. Intrinsic Functions ..
          INTRINSIC                              cos, sin
!         .. Executable Statements ..
          IF (mode==0 .OR. mode==2) THEN
             f(1) = 1000.0E+0_nag_wp*sin(-x(1)-0.25E+0_nag_wp) + &
                1000.0E+0_nag_wp*sin(-x(2)-0.25E+0_nag_wp)
             f(2) = 1000.0E+0_nag_wp*sin(x(1)-0.25E+0_nag_wp) + &
                1000.0E+0_nag_wp*sin(x(1)-x(2)-0.25E+0_nag_wp)
             f(3) = 1000.0E+0_nag_wp*sin(x(2)-x(1)-0.25E+0_nag_wp) + &
                1000.0E+0_nag_wp*sin(x(2)-0.25E+0_nag_wp)
          END IF

          IF (mode==1 .OR. mode==2) THEN

!            Nonlinear Jacobian elements for column 1.

             fjac(1) = -1000.0E+0_nag_wp*cos(-x(1)-0.25E+0_nag_wp)
             fjac(2) = 1000.0E+0_nag_wp*cos(x(1)-0.25E+0_nag_wp) + &
                1000.0E+0_nag_wp*cos(x(1)-x(2)-0.25E+0_nag_wp)
             fjac(3) = -1000.0E+0_nag_wp*cos(x(2)-x(1)-0.25E+0_nag_wp)

!            Nonlinear Jacobian elements for column 2.

             fjac(4) = -1000.0E+0_nag_wp*cos(-x(2)-0.25E+0_nag_wp)
             fjac(5) = -1000.0E+0_nag_wp*cos(x(1)-x(2)-0.25E+0_nag_wp)
             fjac(6) = 1000.0E+0_nag_wp*cos(x(2)-x(1)-0.25E+0_nag_wp) + &
                1000.0E+0_nag_wp*cos(x(2)-0.25E+0_nag_wp)
          END IF

          RETURN

!dec$ attributes offload : mic :: confun
       END SUBROUTINE confun
!dec$ attributes offload : mic :: objfun
       SUBROUTINE objfun(mode,nonln,x,objf,objgrd,nstate,iuser,ruser)
!         Computes the nonlinear part of the objective function and its
!         gradient

!         .. Implicit None Statement ..
          IMPLICIT NONE
!         .. Scalar Arguments ..
          REAL (KIND=nag_wp), INTENT (OUT)    :: objf
          INTEGER, INTENT (INOUT)             :: mode
          INTEGER, INTENT (IN)                :: nonln, nstate
!         .. Array Arguments ..
          REAL (KIND=nag_wp), INTENT (INOUT)  :: objgrd(nonln), ruser(*)
          REAL (KIND=nag_wp), INTENT (IN)     :: x(nonln)
          INTEGER, INTENT (INOUT)             :: iuser(*)
!         .. Executable Statements ..
          IF (mode==0 .OR. mode==2) THEN
             objf = 1.0E-6_nag_wp*x(3)**3 + 2.0E-6_nag_wp*x(4)**3/ &
                3.0E+0_nag_wp
          END IF

          IF (mode==1 .OR. mode==2) THEN
             objgrd(1) = 0.0E+0_nag_wp
             objgrd(2) = 0.0E+0_nag_wp
             objgrd(3) = 3.0E-6_nag_wp*x(3)**2
             objgrd(4) = 2.0E-6_nag_wp*x(4)**2
          END IF

          RETURN

!dec$ attributes offload : mic :: objfun
       END SUBROUTINE objfun
    END MODULE e04ugae_mod
    PROGRAM e04ugae

!      E04UGA Example Main Program

!      .. Use Statements ..
       USE nag_library, ONLY : e04uga, e04wbf, nag_wp
       USE e04ugae_mod, ONLY : confun, lcwsav, liwsav, llwsav, lrwsav, nin,    &
                               nout, objfun
!      .. Implicit None Statement ..
       IMPLICIT NONE
!      .. Local Scalars ..
       REAL (KIND=nag_wp)                  :: obj, sinf
       INTEGER                             :: i, icol, ifail, iobj, j, jcol,   &
                                              leniz, lenz, m, miniz, minz, n,  &
                                              ncnln, ninf, njnln, nname, nnz,  &
                                              nonln, ns
       CHARACTER (1)                       :: start
!      .. Local Arrays ..
       REAL (KIND=nag_wp), ALLOCATABLE     :: a(:), bl(:), bu(:), clamda(:),   &
                                              xs(:), z(:)
       REAL (KIND=nag_wp)                  :: rwsav(lrwsav), user(1)
       INTEGER, ALLOCATABLE                :: ha(:), istate(:), iz(:), ka(:)
       INTEGER                             :: iuser(1), iwsav(liwsav)
       LOGICAL                             :: lwsav(llwsav)
       CHARACTER (80)                      :: cwsav(lcwsav)
       CHARACTER (8), ALLOCATABLE          :: names(:)
!      .. Intrinsic Functions ..
       INTRINSIC                              max
!      .. Executable Statements ..
       WRITE (nout,*) 'E04UGA Example Program Results'

!      Skip heading in data file.
       READ (nin,*)

       READ (nin,*) n, m
       READ (nin,*) ncnln, nonln, njnln
       READ (nin,*) nnz, iobj, start, nname
       ALLOCATE (ha(nnz),ka(n+1),istate(n+m),a(nnz),bl(n+m),bu(n+m),xs(n+m), &
          clamda(n+m),names(nname))

       READ (nin,*) names(1:nname)

!      Read the matrix A from data file. Set up KA.

       jcol = 1
       ka(jcol) = 1

       DO i = 1, nnz

!         Element ( HA( I ), ICOL ) is stored in A( I ).

          READ (nin,*) a(i), ha(i), icol

          IF (icol<jcol) THEN

!            Elements not ordered by increasing column index.

             WRITE (nout,99999) 'Element in column', icol, &
                ' found after element in column', jcol, '. Problem', &
                ' abandoned.'
             GO TO 20
          ELSE IF (icol==jcol+1) THEN

!            Index in A of the start of the ICOL-th column equals I.

             ka(icol) = i
             jcol = icol
          ELSE IF (icol>jcol+1) THEN

!            Index in A of the start of the ICOL-th column equals I,
!            but columns JCOL+1,JCOL+2,...,ICOL-1 are empty. Set the
!            corresponding elements of KA to I.

             ka((jcol+1):icol) = i
             jcol = icol
          END IF

       END DO

       ka(n+1) = nnz + 1

!      Columns N,N-1,...,ICOL+1 are empty. Set the corresponding
!      elements of KA accordingly.

       DO i = n, icol + 1, -1
          ka(i) = ka(i+1)
       END DO

       READ (nin,*) bl(1:(n+m))
       READ (nin,*) bu(1:(n+m))

       IF (start=='C') THEN
          READ (nin,*) istate(1:n)
       ELSE IF (start=='W') THEN
          READ (nin,*) istate(1:(n+m))
       END IF

       READ (nin,*) xs(1:n)

       IF (ncnln>0) THEN
          READ (nin,*) clamda((n+1):(n+ncnln))
       END IF

!      Initialise E04UGA

       ifail = 0
       CALL e04wbf('E04UGA',cwsav,lcwsav,lwsav,llwsav,iwsav,liwsav,rwsav, &
          lrwsav,ifail)

!      Solve the problem.
!      First call is a workspace query

       leniz = max(500,n+m)
       lenz = 500
       ALLOCATE (iz(leniz),z(lenz))

       ifail = 1
       CALL e04uga(confun,objfun,n,m,ncnln,nonln,njnln,iobj,nnz,a,ha,ka,bl,bu, &
          start,nname,names,ns,xs,istate,clamda,miniz,minz,ninf,sinf,obj,iz, &
          leniz,z,lenz,iuser,user,lwsav,iwsav,rwsav,ifail)

       IF (ifail/=0 .AND. ifail/=15 .AND. ifail/=16) THEN
          WRITE (nout,99990) 'Query call to E04UGA failed with IFAIL =', ifail
          GO TO 20
       END IF

       DEALLOCATE (iz,z)

!      The length of the workspace required for the basis factors in this
!      problem is longer than the minimum returned by the query

       lenz = 2*minz
       leniz = 2*miniz
       ALLOCATE (iz(leniz),z(lenz))

       ifail = -1
       CALL e04uga(confun,objfun,n,m,ncnln,nonln,njnln,iobj,nnz,a,ha,ka,bl,bu, &
          start,nname,names,ns,xs,istate,clamda,miniz,minz,ninf,sinf,obj,iz, &
          leniz,z,lenz,iuser,user,lwsav,iwsav,rwsav,ifail)

       SELECT CASE (ifail)
       CASE (0:6)
          WRITE (nout,*)
          WRITE (nout,99998)
          WRITE (nout,*)

          DO i = 1, n
             WRITE (nout,99997) i, istate(i), xs(i), clamda(i)
          END DO

          WRITE (nout,*)
          WRITE (nout,*)
          WRITE (nout,99995)
          WRITE (nout,*)

          IF (ncnln>0) THEN

             DO i = n + 1, n + ncnln
                j = i - n
                WRITE (nout,99994) j, istate(i), xs(i), clamda(i)
             END DO

          END IF

          IF ((ncnln==0) .AND. (m==1) .AND. (a(1)==0.0E0_nag_wp)) THEN
             WRITE (nout,99992) istate(n+1), xs(n+1), clamda(n+1)
          ELSE IF (m>ncnln) THEN

             DO i = n + ncnln + 1, n + m
                j = i - n - ncnln

                IF (i-n==iobj) THEN
                   WRITE (nout,99993) istate(i), xs(i), clamda(i)
                ELSE
                   WRITE (nout,99996) j, istate(i), xs(i), clamda(i)
                END IF

             END DO

          END IF

          WRITE (nout,*)
          WRITE (nout,*)
          WRITE (nout,99991) obj
       END SELECT

20     CONTINUE

99999  FORMAT (/1X,A,I5,A,I5,A,A)
99998  FORMAT (1X,'Variable',2X,'Istate',5X,'Value',9X,'Lagr Mult')
99997  FORMAT (1X,'Varble',1X,I2,1X,I3,4X,1P,G14.6,2X,1P,G12.4)
99996  FORMAT (1X,'LinCon',1X,I2,1X,I3,4X,1P,G14.6,2X,1P,G12.4)
99995  FORMAT (1X,'Constrnt',2X,'Istate',5X,'Value',9X,'Lagr Mult')
99994  FORMAT (1X,'NlnCon',1X,I2,1X,I3,4X,1P,G14.6,2X,1P,G12.4)
99993  FORMAT (1X,'Free Row',2X,I3,4X,1P,G14.6,2X,1P,G12.4)
99992  FORMAT (1X,'DummyRow',2X,I3,4X,1P,G14.6,2X,1P,G12.4)
99991  FORMAT (1X,'Final objective value = ',1P,G15.7)
99990  FORMAT (1X,A,I5)
    END PROGRAM e04ugae
