L-BFGS-B  3.0
Large-scale Bound-constrained Optimization
driver3.f90

This time-controlled driver shows that it is possible to terminate a run by elapsed CPU time, and yet be able to print all desired information. This driver also illustrates the use of two stopping criteria that may be used in conjunction with a limit on execution time. The sample problem used here is the same as in driver1 and driver2 (the extended Rosenbrock function with bounds on the variables). (Fortran-90 version)

1 !> \file driver3.f90
2 
3 !
4 ! L-BFGS-B is released under the "New BSD License" (aka "Modified BSD License"
5 ! or "3-clause license")
6 ! Please read attached file License.txt
7 !
8 ! DRIVER 3 in Fortran 90
9 ! --------------------------------------------------------------
10 ! TIME-CONTROLLED DRIVER FOR L-BFGS-B
11 ! --------------------------------------------------------------
12 !
13 ! L-BFGS-B is a code for solving large nonlinear optimization
14 ! problems with simple bounds on the variables.
15 !
16 ! The code can also be used for unconstrained problems and is
17 ! as efficient for these problems as the earlier limited memory
18 ! code L-BFGS.
19 !
20 ! This driver shows how to terminate a run after some prescribed
21 ! CPU time has elapsed, and how to print the desired information
22 ! before exiting.
23 !
24 ! References:
25 !
26 ! [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
27 ! memory algorithm for bound constrained optimization'',
28 ! SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
29 !
30 ! [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN
31 ! Subroutines for Large Scale Bound Constrained Optimization''
32 ! Tech. Report, NAM-11, EECS Department, Northwestern University,
33 ! 1994.
34 !
35 !
36 ! (Postscript files of these papers are available via anonymous
37 ! ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
38 !
39 ! * * *
40 !
41 ! February 2011 (latest revision)
42 ! Optimization Center at Northwestern University
43 ! Instituto Tecnologico Autonomo de Mexico
44 !
45 ! Jorge Nocedal and Jose Luis Morales
46 !
47 ! **************
48 
49  program driver
50  use json_writer, only: json_write_aggregate
51 
52 ! This time-controlled driver shows that it is possible to terminate
53 ! a run by elapsed CPU time, and yet be able to print all desired
54 ! information. This driver also illustrates the use of two
55 ! stopping criteria that may be used in conjunction with a limit
56 ! on execution time. The sample problem used here is the same as in
57 ! driver1 and driver2 (the extended Rosenbrock function with bounds
58 ! on the variables).
59 
60  implicit none
61 
62 ! We specify a limit on the CPU time (tlimit = 10 seconds)
63 !
64 ! We suppress the default output (iprint = -1). The user could
65 ! also elect to use the default output by choosing iprint >= 0.)
66 ! We suppress the code-supplied stopping tests because we will
67 ! provide our own termination conditions
68 ! We specify the dimension n of the sample problem and the number
69 ! m of limited memory corrections stored.
70 
71  integer, parameter :: n = 1000, m = 10, iprint = -1
72  integer, parameter :: dp = kind(1.0d0)
73  real(dp), parameter :: factr = 0.0d0, pgtol = 0.0d0
74  real(dp) :: tlimit
75 !
76  character(len=60) :: task, csave
77  logical :: lsave(4)
78  integer :: isave(44)
79  real(dp) :: f
80  real(dp) :: dsave(29)
81  integer, allocatable :: nbd(:), iwa(:)
82  real(dp), allocatable :: x(:), l(:), u(:), g(:), wa(:)
83 !
84  real(dp) :: t1, t2, time1, time2
85  integer :: i, j
86 
87 ! Test instrumentation: dump per-iteration state to JSON when the
88 ! environment variable LBFGSB_JSON_OUTPUT is set. No-op otherwise.
89 ! LBFGSB_TLIMIT optionally overrides tlimit for reproducibility.
90  character(len=512) :: lbfgsb_json
91  character(len=64) :: env_tlimit
92  logical :: json_active
93 
94  allocate ( nbd(n), x(n), l(n), u(n), g(n) )
95  allocate ( iwa(3*n) )
96  allocate ( wa(2*m*n + 5*n + 11*m*m + 8*m) )
97 
98 ! This time-controlled driver shows that it is possible to terminate
99 ! a run by elapsed CPU time, and yet be able to print all desired
100 ! information. This driver also illustrates the use of two
101 ! stopping criteria that may be used in conjunction with a limit
102 ! on execution time. The sample problem used here is the same as in
103 ! driver1 and driver2 (the extended Rosenbrock function with bounds
104 ! on the variables).
105 
106 ! We now specify nbd which defines the bounds on the variables:
107 ! l specifies the lower bounds,
108 ! u specifies the upper bounds.
109 
110 ! First set bounds on the odd-numbered variables.
111 
112  do 10 i=1, n,2
113  nbd(i)=2
114  l(i)=1.0d0
115  u(i)=1.0d2
116  10 continue
117 
118 ! Next set bounds on the even-numbered variables.
119 
120  do 12 i=2, n,2
121  nbd(i)=2
122  l(i)=-1.0d2
123  u(i)=1.0d2
124  12 continue
125 
126 ! We now define the starting point.
127 
128  do 14 i=1, n
129  x(i)=3.0d0
130  14 continue
131 
132 ! We now write the heading of the output.
133 
134  write (6,16)
135  16 format(/,5x, 'Solving sample problem.',&
136  /,5x, ' (f = 0.0 at the optimal solution.)',/)
137 
138 ! We start the iteration by initializing task.
139 
140  task = 'START'
141 
142 ! Initialise tlimit (with optional override from LBFGSB_TLIMIT) and
143 ! enable JSON output if LBFGSB_JSON_OUTPUT is set.
144  tlimit = 10.0d0
145  call get_environment_variable('LBFGSB_TLIMIT', env_tlimit)
146  if (len_trim(env_tlimit) > 0) read(env_tlimit, *) tlimit
147  call get_environment_variable('LBFGSB_JSON_OUTPUT', lbfgsb_json)
148  json_active = (len_trim(lbfgsb_json) > 0)
149 
150 ! ------- the beginning of the loop ----------
151 
152 ! We begin counting the CPU time.
153 
154  call timer(time1)
155 
156  do while( task(1:2).eq.'FG'.or.task.eq.'NEW_X'.or. &
157  task.eq.'START')
158 
159 ! This is the call to the L-BFGS-B code.
160 
161  call setulb(n,m,x,l,u,nbd,f,g,factr,pgtol,wa,iwa, &
162  task,iprint, csave,lsave,isave,dsave)
163 
164  if (task(1:2) .eq. 'FG') then
165 
166 ! the minimization routine has returned to request the
167 ! function f and gradient g values at the current x.
168 ! Before evaluating f and g we check the CPU time spent.
169 
170  call timer(time2)
171  if (time2-time1 .gt. tlimit) then
172  task='STOP: CPU EXCEEDING THE TIME LIMIT.'
173 
174 ! Note: Assigning task(1:4)='STOP' will terminate the run;
175 ! setting task(7:9)='CPU' will restore the information at
176 ! the latest iterate generated by the code so that it can
177 ! be correctly printed by the driver.
178 
179 ! In this driver we have chosen to disable the
180 ! printing options of the code (we set iprint=-1);
181 ! instead we are using customized output: we print the
182 ! latest value of x, the corresponding function value f and
183 ! the norm of the projected gradient |proj g|.
184 
185 ! We print out the information contained in task.
186 
187  write (6,*) task
188 
189 ! We print the latest iterate contained in wa(j+1:j+n), where
190 
191  j = 3*n+2*m*n+11*m**2
192  write (6,*) 'Latest iterate X ='
193  write (6,'((1x,1p, 6(1x,d11.4)))') (wa(i),i = j+1,j+n)
194 
195 ! We print the function value f and the norm of the projected
196 ! gradient |proj g| at the last iterate; they are stored in
197 ! dsave(2) and dsave(13) respectively.
198 
199  write (6,'(a,1p,d12.5,4x,a,1p,d12.5)') &
200  'At latest iterate f =',dsave(2),'|proj g| =',dsave(13)
201  else
202 
203 ! The time limit has not been reached and we compute
204 ! the function value f for the sample problem.
205 
206  f=.25d0*(x(1)-1.d0)**2
207  do 20 i=2, n
208  f=f+(x(i)-x(i-1)**2)**2
209  20 continue
210  f=4.d0*f
211 
212 ! Compute gradient g for the sample problem.
213 
214  t1 = x(2) - x(1)**2
215  g(1) = 2.d0*(x(1)-1.d0)-1.6d1*x(1)*t1
216  do 22 i=2,n-1
217  t2=t1
218  t1=x(i+1)-x(i)**2
219  g(i)=8.d0*t2-1.6d1*x(i)*t1
220  22 continue
221  g(n)=8.d0*t1
222  endif
223 
224 ! go back to the minimization routine.
225  else
226 
227  if (task(1:5) .eq. 'NEW_X') then
228 
229 ! the minimization routine has returned with a new iterate.
230 ! The time limit has not been reached, and we test whether
231 ! the following two stopping tests are satisfied:
232 
233 ! 1) Terminate if the total number of f and g evaluations
234 ! exceeds 900.
235 
236  if (isave(34) .ge. 900) &
237  task='STOP: TOTAL NO. of f AND g EVALUATIONS EXCEEDS LIMIT'
238 
239 ! 2) Terminate if |proj g|/(1+|f|) < 1.0d-10.
240 
241  if (dsave(13) .le. 1.d-10*(1.0d0 + abs(f))) &
242  task='STOP: THE PROJECTED GRADIENT IS SUFFICIENTLY SMALL'
243 
244 ! We wish to print the following information at each iteration:
245 ! 1) the current iteration number, isave(30),
246 ! 2) the total number of f and g evaluations, isave(34),
247 ! 3) the value of the objective function f,
248 ! 4) the norm of the projected gradient, dsve(13)
249 !
250 ! See the comments at the end of driver1 for a description
251 ! of the variables isave and dsave.
252 
253  write (6,'(2(a,i5,4x),a,1p,d12.5,4x,a,1p,d12.5)') 'Iterate' &
254  ,isave(30),'nfg =',isave(34),'f =',f,'|proj g| =',dsave(13)
255 
256 ! If the run is to be terminated, we print also the information
257 ! contained in task as well as the final value of x.
258 
259  if (task(1:4) .eq. 'STOP') then
260  write (6,*) task
261  write (6,*) 'Final X='
262  write (6,'((1x,1p, 6(1x,d11.4)))') (x(i),i = 1,n)
263  endif
264 
265  endif
266  end if
267  end do
268 
269 ! If task is neither FG nor NEW_X we terminate execution.
270 
271  if (json_active) &
272  call json_write_aggregate(trim(lbfgsb_json), task, f, dsave(13), n, x)
273 
274  end program driver
275 
276 !======================= The end of driver3 ============================
277 
subroutine setulb(n, m, x, l, u, nbd, f, g, factr, pgtol, wa, iwa, task, iprint, csave, lsave, isave, dsave)
This subroutine partitions the working arrays wa and iwa, and then uses the limited memory BFGS metho...
Definition: setulb.f:190
subroutine timer(ttime)
This routine computes cpu time in double precision.
Definition: timer.f:11