subroutine LSOPT_TOP( nn, xx, ff, gg, simul, optline
     $                  , epsx, fmin, epsg
     $                  , iprint, itmax, nfunc, nupdate
     $                  , dd, gold, xdiff
     $                  , loffline
     $                  , ifail )

c     ==================================================================
c     SUBROUTINE lsopt_top
c     ==================================================================
c
c     o uses a set of control variables, their adjoint variables,
c       and a cost function value
c       to compute an improved set of controls with respect to the
c       cost function via a
c       variable-storage Quasi-Newton method
c
c     o Reference: J.C. Gilbert & C. Lemarechal
c                  Some numerical experiments with variable-storage
c                  quasi-Newton algorithms
c                  Mathematical Programming 45 (1989), pp. 407-435
c
c     o started: ??? not reproducible
c
c     o changed: Patrick Heimbach, MIT/EAPS
c                
c     o Version: 2.0, 24-Feb-2000: 
c                    (Version 1.0 is considered as version
c                     starting from which changes were made).
c                   - severe changes in structure including various
c                     bug-fixes to enable multi-optimization runs;
c                   - routine lsoptw incorporated into lsoptv
c                   - optimization iteration loop restructured
c                   - complete restructuring of handling
c                     cold start cases
c                   - number of 3 control flags for error handling
c                     (indic, moderl, ifail) reduced to 1 (ifail)
c                     and homogenized with routine lsline
c
c     o Version: 2.1, 29-Feb-2000:
c                   - handling of case ifail = 6 changed;
c                     leads to stop of optimization
c                     (similar to case ifail = 8)
c                   - logical lphprint included
c
c     ==================================================================
c     SUBROUTINE lsopt_top
c     ==================================================================

      implicit none

ccc#include 

c-----------------------------------------
c declare arguments
c-----------------------------------------
      integer nn, iprint, itmax, nfunc, nupdate, ifail

      double precision  xx(nn), ff, gg(nn), epsx, fmin, epsg
      double precision  dd(nn), gold(nn), xdiff(nn)

cph(
      integer phniter0, phniterold
      double precision phff
      COMMON /PH_OPTI/ phniter0, phniterold, phff
cph)

      external , optline

c-----------------------------------------
C declare local variables
c-----------------------------------------
      logical cold, lphprint, loffline
      parameter (lphprint = .true.)

      integer mm, mupd, jmin, jmax, indic, isize, REAL_BYTE
      integer i, iiter, ifunc

      double precision   fupd
      double precision   r1, tmin, tmax, tact, gnorm, gnorm0, eps1
      double precision   fold, ys
      double precision   dotdg

      external , DNRM2, DSCAL
      double precision     DDOT, DNRM2

c-----------------------------------------
c parameters
c-----------------------------------------

      double precision rmin
      parameter( rmin = 1.e-20 )

      character*(*) iform
      parameter(iform='(i5,2x,1pe8.1,1x,i5,4x,1pe11.4,3(2x,1pe8.1))' )

c     ==================================================================
c
c-----------------------------------------
c initialization
c-----------------------------------------
      cold  = .true.
      fupd  = 1.0e+10
      indic = 0
      tmin  = 0.
      tmax  = 1.0e+10
      tact  = 1.0
cph(
      phniterold = 0
cph)
      iiter = 0
      eps1  = 1.0
      ifunc = 0
      ifail = 0
      gnorm0 = 1.

c-----------------------------------------
c initialization for dd and dds
c-----------------------------------------

      jmin  = 1
      jmax  = 0

      mm    = nn
      mupd  = nupdate

      REAL_BYTE = 4
      isize = REAL_BYTE

c-----------------------------------------
c print information
c-----------------------------------------
      if (iprint .ge. 1) then
         print '(2x,a)',
     $         '==============================================='
         print '(2x,a)',
     $         '===         O P T I M I Z A T I O N         ==='
         print '(2x,a)',
     $         '==============================================='
         print '(a,i9)'
     $        , '  number of control variables.......', nn
         print '(a,e9.2)'
     $        , '  precision on x....................', epsx
         print '(a,e9.2)'
     $        , '  precision on g....................', epsg
         print '(a,e9.2)'
     $        , '  expected optimal function value...', fmin
         print '(a,i9)'
     $        , '  maximal number of iterations......', itmax
         print '(a,i9)'
     $        , '  maximal number of simulations.....', nfunc
         print '(a,i9)'
     $        , '  information level.................', iprint
         print '(a,i9)'
     $        , '  number of updates.................', nupdate
         print '(a,i9)'
     $        , '  size of used memory...............', 3*nn
      endif

c-----------------------------------------
c check arguments
c-----------------------------------------

      if (nn .le. 0) then
         if (iprint.ge.1) then
            print '(a,i6)'  , '  ERROR : n     = ', nn
         endif
         ifail = 1
         goto 999
      endif

      if (itmax .lt. 0) then
         if (iprint.ge.1) then
            print '(a,i6)'  , '  ERROR : itmax = ', itmax
         endif
         ifail = 1
         goto 999
      endif

      if (nfunc .le. 0) then
         if (iprint.ge.10) then
            print '(a,i6)'  , '  ERROR : nfunc  = ', nfunc
         endif
         ifail = 1
         goto 999
      endif

      if (epsx .le. 0.) then
         if (iprint.ge.1) then
            print '(a,e9.2)', '  ERROR : epsx = ', epsx
         endif
         ifail = 1
         goto 999
      endif

      if (epsg .le. 0.) then
         if (iprint.ge.1) then
            print '(a,e9.2)', '  ERROR : epsg  = ', epsg
         endif
         ifail = 1
         goto 999
      endif

      if (epsg .gt. 1.) then
         if (iprint.ge.1) then
            print '(a,e9.2)', '  ERROR : epsg  = ', epsg
         endif
         ifail = 1
         goto 999
      endif

cph(
      print *, 'pathei: vor instore '
cph)
      call INSTORE( mm, fupd, gnorm0, isize, mupd, jmin, jmax, cold,
     &              ifail )

cph(
      phff = fupd
cph)

c-----------------------------------------
c check warm start parameters
c-----------------------------------------
      if (ifail .ne. 0) then
         if (iprint.ge.1) then
            print '(a)', ' ERROR : reading restart file'
         end


if ifail = 2 goto 999 end


if if (isize .ne. REAL_BYTE) then if (iprint.ge.1) then print '(a)', ' ERROR : uncompatible floating point format' end


if ifail = 2 goto 999 end


if if (mupd .lt. 1) then if (iprint .ge. 1) then print '(a)', ' ERROR : m is set too small in instore' endif ifail = 2 goto 999 endif c----------------------------------------- c cold start or warm restart ? c----------------------------------------- if (cold) then c--- start if cold start --- if (lphprint) then print '(a)', 'pathei-lsopt: cold start' end


if print *, 'pathei-lsopt vor simul', nn print *, 'pathei-lsopt xx(1), gg(1) ', xx(1), gg(1) call SIMUL( indic, nn, xx, ff, gg ) print *, 'pathei: nach simul: nn, ff = ', nn, ff print *, 'pathei: nach simul: xx(1), gg(1) = ', xx(1), gg(1) do i = 1, nn xdiff(i) = 1. end


do cph( print *, 'pathei: vor dostore ' cph) call DOSTORE( nn, xx, .true., 1 ) call DOSTORE( nn, gg, .true., 2 ) call DOSTORE( nn, xdiff, .true., 3 ) cph( print *, 'pathei: vor lswri ' cph) cph call lswri( isize, iiter, nn, xx, gg, lphprint ) cph( print *, 'pathei: vor gnorm0 ' cph) gnorm0 = DNRM2( nn, gg, 1 ) cph( print *, 'pathei: gnorm0 = ', gnorm0 cph) if (gnorm0 .lt. rmin) then ifail = 3 goto 1000 endif cph( phff = ff cph) if (lphprint) & print *, 'pathei-lsopt: cold; first call simul: ff = ', & phff c--- end if cold start --- else c--- start if warm start --- if (mm .ne. nn) then if (iprint.ge.1) then print '(a,i6)' $ , ' ERROR : inconsistent nn = ', mm endif ifail = 2 goto 999 endif if (mupd .ne. nupdate) then if (iprint.ge.1) then print '(a,i6)' $ , ' ERROR : inconsistent nupdate = ', mupd endif ifail = 2 goto 999 endif if (jmin .lt. 1) then if (iprint.ge.1) then print '(a,i6)' $ , ' ERROR : inconsistent jmin = ', jmin endif ifail = 2 goto 999 endif if (jmin .gt. mupd) then if (iprint.ge.1) then print '(a,i6)' $ , ' ERROR : inconsistent jmin = ', jmin endif ifail = 2 goto 999 endif if (jmax .gt. mupd) then if (iprint.ge.1) then print '(a,i6)' $ , ' ERROR : inconsistent jmax = ', jmax endif ifail = 2 goto 999 endif if (lphprint) then print *, 'pathei-lsopt: warm start; read via dostore' print * endif call DOSTORE( nn, xx, .false., 1 ) call DOSTORE( nn, gg, .false., 2 ) ff = fupd cph( phff = ff cph) if (lphprint) & print *, 'pathei-lsopt: warm; first dostore read: ff = ', & ff c--- end if warm start --- endif if (iprint .ge. 1) then print '(2a)', ' Itn Step Nfun Objective ' $ , 'Norm G Norm X Norm (X(k-1)-X(k))' end


if c----------------------------------------- c print information line c----------------------------------------- if (cold) then print iform, iiter, tact, ifunc, ff, gnorm0 $ , DNRM2( nn, xx, 1 ), 0. Cml write(94,'(i5,2x,1pe11.4,4(2x,1pe8.1))') Cml & iiter, ff, gnorm0, tact, Cml & DNRM2( nn, xx, 1 ), 0. if ( itmax .EQ. 0 ) then ifail = 10 goto 1000 end


if end


if c======================================================================= c begin of loop c compute x(k+1) out of x(k) + t*d, where t > 0. c======================================================================= do iiter = 1, itmax if (lphprint) then print *, 'pathei-lsopt: ++++++++++++++++++++++++' print *, 'pathei-lsopt: entering iiter =', iiter end


if c----------------------------------------- c store old values c----------------------------------------- do i = 1, nn gold(i) = gg(i) end


do fold = ff cph( phniter0 = iiter phff = ff cph) c----------------------------------------- c compute new dd and xx c----------------------------------------- c call LSUPDXX( & nn, ifail, lphprint & , jmin, jmax, nupdate & , ff, fmin, fold, gnorm0, dotdg & , gg, dd, xx, xdiff & , tmin, tmax, tact, epsx & ) c----------------------------------------- c check whether new direction is a descent one c----------------------------------------- if ( ifail .eq. 4) goto 1000 c----------------------------------------- c optline returns new values of x, f, and g c----------------------------------------- c call OPTLINE( & simul & , nn, ifail, lphprint & , ifunc, nfunc & , ff, dotdg & , tmin, tmax, tact, epsx & , dd, gg, xx, xdiff & ) if (lphprint) print *, 'pathei-lsopt: ', & 'back from optline; ifail = ', ifail if (lphprint) print *, 'pathei-lsopt: ', & 'dostore 1,2 at iiter ', iiter call DOSTORE( nn, xx, .true., 1 ) call DOSTORE( nn, gg, .true., 2 ) cph( cph call lswri( isize, iiter, nn, xx, gg, lphprint ) cph) gnorm = DNRM2( nn, gg, 1 ) c----------------------------------------- c print information line c----------------------------------------- print iform, iiter, tact, ifunc, ff, gnorm $ , DNRM2( nn, xx, 1 ), tact*DNRM2( nn, dd, 1 ) Cml write(94,'(i5,2x,1pe11.4,4(2x,1pe8.1))') Cml & iiter, ff, gnorm, tact, Cml & DNRM2( nn, xx, 1 ), tact*DNRM2( nn, dd, 1 ) c----------------------------------------- c check output mode of ifail c----------------------------------------- if (ifail .eq. 7 & .or. ifail .eq. 8 & .or. ifail .eq. 9) goto 1000 c----------------------------------------- c maximal number of simulation reached c no goto in order to update Hessian c----------------------------------------- if (ifail .eq. 6) ifail = 0 c----------------------------------------- c NOTE: stopping tests are now done c after having updated the matrix, c so that update information can be stored c in case of a later warm restart c----------------------------------------- c----------------------------------------- c compute new s, y c----------------------------------------- do i = 1, nn xdiff(i) = tact*dd(i) end


do c----------------------------------------- c compute ys c----------------------------------------- do i = 1, nn gold(i) = gg(i)-gold(i) end


do ys = DDOT( nn, gold, 1, xdiff, 1 ) if (ys .le. 0.) then ifail = 4 print *, 'pathei-lsopt: ys < 0; ifail = ', ifail goto 1000 endif cph( cph----------------------------------------- cph at this point it is clear that xdiff cph provides a true optimized solution; cph i.e. take new gradient gg to compute new dd cph----------------------------------------- cph) c----------------------------------------- c update pointers for hessupd c----------------------------------------- if (nupdate .gt. 0) then if (jmax .eq. 0) then jmax = jmax+1 if (lphprint) & print *, 'pathei-lsopt: ', & 'first pointer update after cold start; ', & 'iiter, jmin, jmax = ', iiter, jmin, jmax else jmax = jmax+1 if (jmax .gt. nupdate) jmax = jmax-nupdate if (jmin .eq. jmax) then if (lphprint) & print *, 'pathei-lsopt: pointers updated for ', & ' iiter, jmin, jmax = ', iiter, jmin, jmax jmin = jmin+1 if (jmin .gt. nupdate) jmin = jmin-nupdate end


if end


if c----------------------------------------- c compute sbar, ybar store rec = min 4,5 c----------------------------------------- r1 = sqrt(1./ys) call DSCAL( nn, r1, xdiff, 1 ) call DSCAL( nn, r1, gold, 1 ) if (lphprint) & print *, 'pathei-lsopt: dostore at iiter, jmin, jmax ', & iiter, jmin, jmax call DOSTORE( nn, gold, .true., 2*jmax+2 ) call DOSTORE( nn, xdiff, .true., 2*jmax+3 ) c----------------------------------------- c compute the diagonal preconditioner c use dd as temporary array c----------------------------------------- call DGSCALE( nn, gold, xdiff, dd, rmin ) endif c----------------------------------------- c test convergence and stopping criteria c----------------------------------------- eps1 = gnorm / gnorm0 if (eps1 .lt. epsg) then ifail = 11 goto 1000 endif c======================================================================= c return of loop c======================================================================= end


do iiter = iiter - 1 ifail = 5 c----------------------------------------- c loop exit c----------------------------------------- 1000 continue nfunc = ifunc epsg = eps1 c----------------------------------------------------------------------- c save data for warm start c----------------------------------------------------------------------- call OUTSTORE( nn, ff, gnorm0, nupdate, jmin, jmax ) c----------------------------------------------------------------------- c compute dd(i+1), xx(i+1) based on latest available gg(i), xx(i) c for offline version c----------------------------------------------------------------------- if (loffline) then call LSUPDXX( & nn, ifail, lphprint & , jmin, jmax, nupdate & , ff, fmin, fold, gnorm0, dotdg & , gg, dd, xx, xdiff & , tmin, tmax, tact, epsx & ) c Save xx(i+1) to file for offline version. call OPTIM_WRITE_CONTROL( nn, xdiff ) end


if c----------------------------------------- c print final information c----------------------------------------- if (iprint .ge. 5) then print * print '(a,i9)' $ , ' number of iterations..............', iiter print '(a,i9)' $ , ' number of simultations............', nfunc print '(a,e9.2)' $ , ' relative precision on g...........', epsg end


if if (iprint.ge.10) then print * print '(a,e15.8)' $ , ' cost function...............', ff print '(a,e15.8)' $ , ' norm of x...................', DNRM2( nn, xx, 1 ) print '(a,e15.8)' $ , ' norm of g...................', DNRM2( nn, gg, 1 ) end


if c----------------------------------------- c print error message c----------------------------------------- 999 continue if (ifail .ne. 0) then if (iprint .ge. 5) then print * print '(a)', ' optimization stopped because :' if (ifail .lt. 0) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' user request during simul' else if (ifail .eq. 0) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' optimal solution found' else if (ifail .eq. 1) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' an input argument is wrong' else if (ifail .eq. 2) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' warm start file is corrupted' else if (ifail .eq. 3) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' the initial gradient is too small' else if (ifail .eq. 4) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' the search direction is not a descent one' else if (ifail .eq. 5) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' maximal number of iterations reached' else if (ifail .eq. 6) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' maximal number of simulations reached' else if (ifail .eq. 7) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' the linesearch failed' else if (ifail .eq. 8) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' the function could not be improved' else if (ifail .eq. 9) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' optline parameters wrong' else if (ifail .eq. 10) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' cold start, no optimization done' else if (ifail .eq. 11) then print '(2x,a8,I3,a)', 'ifail = ', ifail $ , ' convergence achieved within precision' end


if print * else if (iprint .ge. 1) then print * print '(a,i9)' $ , ' after optimization ifail..........', ifail print * end


if end


if c----------------------------------------- c end of subroutine c----------------------------------------- return end