Line data Source code
1 : !!****m* ABINIT/m_lbfgs
2 : !! NAME
3 : !! m_lbfgs
4 : !!
5 : !! FUNCTION
6 : !! This module provides several routines for the application of a
7 : !! Limited-memory Broyden-Fletcher-Goldfarb-Shanno (LBFGS) minimization algorithm.
8 : !! The working routines were based on the original implementation of J. Nocera available on netlib.org
9 : !! They have been reshaped and translated into modern fortran here.
10 : !!
11 : !! COPYRIGHT
12 : !! Copyright (C) 2012-2026 ABINIT group (FB)
13 : !! This file is distributed under the terms of the
14 : !! GNU General Public License, see ~abinit/COPYING
15 : !! or http://www.gnu.org/copyleft/gpl.txt .
16 : !!
17 : !! SOURCE
18 :
19 : #if defined HAVE_CONFIG_H
20 : #include "config.h"
21 : #endif
22 :
23 : #include "abi_common.h"
24 :
25 : module m_lbfgs
26 :
27 : use defs_basis
28 : use m_abicore
29 :
30 : implicit none
31 :
32 : type,public :: lbfgs_internal
33 : integer :: lbfgs_status
34 : integer :: ndim
35 : integer :: history_record
36 : integer :: iter
37 : real(dp) :: gtol
38 : real(dp),allocatable :: diag(:)
39 : real(dp),allocatable :: work(:)
40 : real(dp) :: line_stp
41 : real(dp) :: line_stpmin
42 : real(dp) :: line_stpmax
43 : integer :: line_info
44 : integer :: line_infoc
45 : integer :: line_nfev
46 : real(dp) :: line_dginit
47 : real(dp) :: line_finit
48 : real(dp) :: line_stx
49 : real(dp) :: line_fx
50 : real(dp) :: line_dgx
51 : real(dp) :: line_sty
52 : real(dp) :: line_fy
53 : real(dp) :: line_dgy
54 : real(dp) :: line_stmin
55 : real(dp) :: line_stmax
56 : logical :: line_bracket
57 : logical :: line_stage1
58 : end type lbfgs_internal
59 :
60 : type(lbfgs_internal),save,public :: lbfgs_plan
61 :
62 : !!***
63 :
64 : contains
65 :
66 : !----------------------------------------------------------------------
67 :
68 : !!****f* m_lbfgs/lbfgs_init
69 : !! NAME
70 : !! lbfgs_init
71 : !!
72 : !! FUNCTION
73 : !! Initialize the internal object lbfgs_internal for LBFGS minimization
74 : !!
75 : !! INPUTS
76 : !!
77 : !! OUTPUT
78 : !!
79 : !! SIDE EFFECTS
80 : !!
81 : !! SOURCE
82 :
83 1 : subroutine lbfgs_init(ndim,history_record,diag_guess)
84 :
85 : integer,intent(in) :: ndim
86 : integer,intent(in) :: history_record
87 : real(dp),intent(in) :: diag_guess(ndim)
88 :
89 : integer :: nwork
90 :
91 1 : lbfgs_plan%lbfgs_status = 0
92 1 : lbfgs_plan%iter = 0
93 1 : lbfgs_plan%ndim = ndim
94 1 : lbfgs_plan%history_record = history_record
95 3 : ABI_MALLOC(lbfgs_plan%diag,(ndim))
96 :
97 1 : nwork = ndim * ( 2 * history_record + 1 ) + 2 * history_record
98 3 : ABI_MALLOC(lbfgs_plan%work,(nwork))
99 :
100 1 : lbfgs_plan%gtol = 0.9
101 1 : lbfgs_plan%line_stpmin = 1.0e-20
102 1 : lbfgs_plan%line_stpmax = 1.0e+20
103 1 : lbfgs_plan%line_stp = 1.0
104 :
105 28 : lbfgs_plan%diag(:) = diag_guess(:)
106 :
107 1 : end subroutine lbfgs_init
108 : !!***
109 :
110 :
111 : !----------------------------------------------------------------------
112 :
113 : !!****f* m_lbfgs/lbfgs_destroy
114 : !! NAME
115 : !! lbfgs_destroy
116 : !!
117 : !! FUNCTION
118 : !! Free the memory of the internal object lbfgs_internal for LBFGS minimization
119 : !!
120 : !! INPUTS
121 : !!
122 : !! OUTPUT
123 : !!
124 : !! SOURCE
125 :
126 1 : subroutine lbfgs_destroy()
127 :
128 1 : ABI_SFREE(lbfgs_plan%work)
129 1 : ABI_SFREE(lbfgs_plan%diag)
130 :
131 1 : end subroutine lbfgs_destroy
132 : !!***
133 :
134 : !----------------------------------------------------------------------
135 :
136 : !!****f* m_lbfgs/lbfgs_execute
137 : !! NAME
138 : !! lbfgs_execute
139 : !!
140 : !! FUNCTION
141 : !! Perform one-step of LBFGS minimization
142 : !! all the internal information are stored in the lbfgs_internal object
143 : !!
144 : !! INPUTS
145 : !! x: input and output position vector (atomic reduced coordinates + cell parameters)
146 : !! f: total energy
147 : !! gradf: gradient of the total energy (=negative forces)
148 : !!
149 : !! OUTPUT
150 : !!
151 : !! SOURCE
152 :
153 11 : function lbfgs_execute(x,f,gradf)
154 :
155 : real(dp),intent(inout) :: x(lbfgs_plan%ndim)
156 : real(dp),intent(in) :: f
157 : real(dp),intent(in) :: gradf(lbfgs_plan%ndim)
158 : integer :: lbfgs_execute
159 :
160 : call lbfgs(lbfgs_plan%ndim, lbfgs_plan%history_record, x, f, gradf, lbfgs_plan%diag, lbfgs_plan%work, lbfgs_plan%lbfgs_status, &
161 : lbfgs_plan%gtol, lbfgs_plan%line_stpmin, lbfgs_plan%line_stpmax, lbfgs_plan%line_stp, lbfgs_plan%iter, &
162 : lbfgs_plan%line_info, lbfgs_plan%line_nfev, &
163 : lbfgs_plan%line_dginit, lbfgs_plan%line_finit, &
164 : lbfgs_plan%line_stx, lbfgs_plan%line_fx, lbfgs_plan%line_dgx, &
165 : lbfgs_plan%line_sty, lbfgs_plan%line_fy, lbfgs_plan%line_dgy, &
166 : lbfgs_plan%line_stmin, lbfgs_plan%line_stmax, &
167 11 : lbfgs_plan%line_bracket, lbfgs_plan%line_stage1, lbfgs_plan%line_infoc)
168 :
169 :
170 : !lbfgs_execute = lbfgs_plan%lbfgs_status
171 11 : lbfgs_execute = lbfgs_plan%line_info
172 :
173 11 : end function lbfgs_execute
174 : !!***
175 :
176 :
177 : !----------------------------------------------------------------------
178 :
179 : !!****f* m_lbfgs/lbfgs
180 : !! NAME
181 : !! lbfgs
182 : !!
183 : !! FUNCTION
184 : !! Perform the LBFGS step
185 : !! Fortran90 rewritting of the original subroutine by J. Nocera
186 : !!
187 : !! INPUTS
188 : !!
189 : !! OUTPUT
190 : !!
191 : !! SIDE EFFECTS
192 : !!
193 : !! SOURCE
194 :
195 11 : subroutine lbfgs(N,M,X,F,G,DIAG,W,IFLAG, &
196 : GTOL,STPMIN,STPMAX,STP,ITER, &
197 : INFO, NFEV, &
198 : LINE_DGINIT,LINE_FINIT, &
199 : LINE_STX,LINE_FX,LINE_DGX, &
200 : LINE_STY,LINE_FY,LINE_DGY, &
201 : LINE_STMIN,LINE_STMAX, &
202 : LINE_BRACKT,LINE_STAGE1,LINE_INFOC)
203 :
204 : !Arguments ------------------------------------
205 : !scalars
206 : integer,intent(inout) :: LINE_INFOC
207 : integer,intent(inout) :: ITER,IFLAG,INFO,NFEV
208 : integer,intent(in) :: N,M
209 : real(dp),intent(inout) :: GTOL
210 : real(dp),intent(in) :: STPMIN,STPMAX
211 : real(dp),intent(inout) :: STP
212 : real(dp),intent(in) :: F
213 : real(dp),intent(inout) :: LINE_DGINIT,LINE_FINIT
214 : real(dp),intent(inout) :: LINE_STX,LINE_FX,LINE_DGX
215 : real(dp),intent(inout) :: LINE_STY,LINE_FY,LINE_DGY
216 : real(dp),intent(inout) :: LINE_STMIN,LINE_STMAX
217 : logical,intent(inout) :: LINE_BRACKT,LINE_STAGE1
218 : !arrays
219 : real(dp),intent(inout) :: X(N),DIAG(N),W(N*(2*M+1)+2*M)
220 : real(dp),intent(in) :: G(N)
221 :
222 : !Local variables-------------------------------
223 : !scalars
224 : real(dp) :: FTOL,YS,YY,SQ,YR,BETA
225 : integer :: POINT,ISPT,IYPT,MAXFEV, &
226 : BOUND,NPT,CP,I,INMC,IYCN,ISCN
227 : !***************************************************************************
228 :
229 :
230 : !
231 : ! Initialize
232 : !-----------
233 :
234 : ! Parameters for line search routine
235 11 : FTOL = 1.0D-4
236 11 : MAXFEV = 20
237 :
238 11 : ISPT = N + 2 * M
239 11 : IYPT = ISPT + N * M
240 11 : POINT = MAX( 0 , MOD(ITER-1,M) )
241 11 : NPT = POINT * N
242 11 : ITER = ITER + 1
243 11 : BOUND = MIN( ITER-1 , M)
244 :
245 :
246 : !
247 : ! Entering the subroutine with a new position and gradient
248 : ! or entering for the first time ever
249 11 : if( IFLAG /= 1 ) then
250 28 : W(ISPT+1:ISPT+N) = -G(1:N) * DIAG(1:N)
251 :
252 : else
253 :
254 : call MCSRCH(N,X,F,G,W(ISPT+POINT*N+1),STP,FTOL,MAXFEV,INFO,NFEV, &
255 : DIAG,GTOL,STPMIN,STPMAX,LINE_DGINIT,LINE_FINIT, &
256 : LINE_STX,LINE_FX,LINE_DGX, &
257 : LINE_STY,LINE_FY,LINE_DGY, &
258 : LINE_STMIN,LINE_STMAX, &
259 10 : LINE_BRACKT,LINE_STAGE1,LINE_INFOC)
260 : !
261 : ! Compute the new step and gradient change
262 : !
263 10 : NPT = POINT * N
264 280 : W(ISPT+NPT+1:ISPT+NPT+N) = STP * W(ISPT+NPT+1:ISPT+NPT+N)
265 550 : W(IYPT+NPT+1:IYPT+NPT+N) = G(1:N) - W(1:N)
266 :
267 280 : YS = DOT_PRODUCT( W(IYPT+NPT+1:IYPT+NPT+N) , W(ISPT+NPT+1:ISPT+NPT+N) )
268 280 : YY = DOT_PRODUCT( W(IYPT+NPT+1:IYPT+NPT+N) , W(IYPT+NPT+1:IYPT+NPT+N) )
269 280 : DIAG(1:N)= YS / YY
270 :
271 : !
272 : ! COMPUTE -H*G USING THE FORMULA GIVEN IN: Nocedal, J. 1980,
273 : ! "Updating quasi-Newton matrices with limited storage",
274 : ! Mathematics of Computation, Vol.24, No.151, pp. 773-782.
275 : ! ---------------------------------------------------------
276 : !
277 10 : POINT = MODULO(ITER - 1,M)
278 10 : CP = POINT
279 10 : if (POINT == 0) CP = M
280 :
281 10 : W(N+CP) = one / YS
282 280 : W(1:N) = -G(1:N)
283 :
284 : CP = POINT
285 50 : do I= 1,BOUND
286 40 : CP = CP - 1
287 40 : if (CP == -1) CP = M - 1
288 1120 : SQ = DOT_PRODUCT(W(ISPT+CP*N+1:ISPT+CP*N+N),W(1:N))
289 40 : INMC = N + M + CP + 1
290 40 : IYCN = IYPT + CP * N
291 40 : W(INMC)= W(N+CP+1) * SQ
292 1130 : W(1:N) = W(1:N) - W(INMC) * W(IYCN+1:IYCN+N)
293 : enddo
294 :
295 280 : W(1:N) = DIAG(1:N) * W(1:N)
296 :
297 50 : do I=1,BOUND
298 1120 : YR = DOT_PRODUCT(W(IYPT+CP*N+1:IYPT+CP*N+N),W(1:N))
299 40 : BETA = W(N+CP+1) * YR
300 40 : INMC = N + M + CP + 1
301 40 : BETA = W(INMC) - BETA
302 40 : ISCN = ISPT + CP * N
303 1120 : W(1:N) = W(1:N) + BETA * W(ISCN+1:ISCN+N)
304 40 : CP = CP + 1
305 50 : if (CP == M) CP = 0
306 : enddo
307 :
308 : !
309 : ! STORE THE NEW SEARCH DIRECTION
310 550 : W(ISPT+POINT*N+1:ISPT+POINT*N+N) = W(1:N)
311 :
312 : endif
313 :
314 : !
315 : ! Obtain the one-dimensional minimizer of the function
316 : ! by using the line search routine mcsrch
317 : !----------------------------------------------------
318 11 : NFEV = 0
319 11 : STP = one
320 308 : W(1:N) = G(1:N)
321 :
322 11 : INFO = 0
323 :
324 : call MCSRCH(N,X,F,G,W(ISPT+POINT*N+1),STP,FTOL,MAXFEV,INFO,NFEV, &
325 : DIAG,GTOL,STPMIN,STPMAX,LINE_DGINIT,LINE_FINIT, &
326 : LINE_STX,LINE_FX,LINE_DGX, &
327 : LINE_STY,LINE_FY,LINE_DGY, &
328 : LINE_STMIN,LINE_STMAX, &
329 11 : LINE_BRACKT,LINE_STAGE1,LINE_INFOC)
330 :
331 11 : if (INFO == -1) then
332 11 : IFLAG = 1
333 11 : return
334 : else
335 0 : IFLAG = -1
336 0 : return
337 : endif
338 :
339 : end subroutine lbfgs
340 : !!***
341 :
342 : !----------------------------------------------------------------------
343 :
344 : !!****f* m_lbfgs/mcsrch
345 : !! NAME
346 : !! mcsrch
347 : !!
348 : !! FUNCTION
349 : !! Perform the line minimization step
350 : !! Fortran90 rewritting of the original subroutine by J. Nocera
351 : !!
352 : !! INPUTS
353 : !!
354 : !! OUTPUT
355 : !!
356 : !! SIDE EFFECTS
357 : !!
358 : !! SOURCE
359 :
360 21 : subroutine mcsrch(N,X,F,G,S,STP,FTOL,MAXFEV,INFO,NFEV,WA, &
361 : GTOL,STPMIN,STPMAX,DGINIT,FINIT, &
362 : STX,FX,DGX,STY,FY,DGY,STMIN,STMAX, &
363 : BRACKT,STAGE1,INFOC)
364 :
365 : !Arguments ------------------------------------
366 : !scalars
367 : integer,intent(in) :: N,MAXFEV
368 : integer,intent(inout) :: INFO,NFEV
369 : integer,intent(inout) :: INFOC
370 : real(dp),intent(in) :: GTOL,STPMIN,STPMAX
371 : real(dp),intent(in) :: F,FTOL
372 : real(dp),intent(inout) :: STP,DGINIT,FINIT
373 : real(dp),intent(inout) :: STX,FX,DGX
374 : real(dp),intent(inout) :: STY,FY,DGY
375 : real(dp),intent(inout) :: STMIN,STMAX
376 : logical,intent(inout) :: BRACKT,STAGE1
377 : !arrays
378 : real(dp),intent(in) :: G(N)
379 : real(dp),intent(inout) :: X(N),S(N),WA(N)
380 :
381 : !Local variables-------------------------------
382 : !scalars
383 : real(dp),parameter :: XTOL=1.0e-17_dp
384 : real(dp),parameter :: P5 = 0.50_dp
385 : real(dp),parameter :: P66 = 0.66_dp
386 : real(dp),parameter :: XTRAPF = 4.00_dp
387 : real(dp) :: DG,DGM,DGTEST,DGXM,DGYM, &
388 : FTEST1,FM,FXM,FYM,WIDTH,WIDTH1
389 : !***************************************************************************
390 :
391 21 : DGTEST = FTOL * DGINIT
392 21 : WIDTH = STPMAX - STPMIN
393 21 : WIDTH1 = WIDTH / P5
394 :
395 : ! Is it a first entry (info == 0)
396 : ! or a second entry (info == -1)?
397 21 : if( INFO == -1 ) then
398 :
399 : ! Reset INFO
400 10 : INFO = 0
401 :
402 10 : NFEV = NFEV + 1
403 280 : DG = SUM( G(:) * S(:) )
404 10 : FTEST1 = FINIT + STP * DGTEST
405 : !
406 : ! TEST FOR CONVERGENCE.
407 : !
408 : if ((BRACKT .AND. (STP <= STMIN .OR. STP >= STMAX)) &
409 10 : .OR. INFOC == 0) INFO = 6
410 : if (STP == STPMAX .AND. &
411 10 : F <= FTEST1 .AND. DG <= DGTEST) INFO = 5
412 10 : if (STP == STPMIN .AND. &
413 0 : (F > FTEST1 .OR. DG >= DGTEST)) INFO = 4
414 10 : if (NFEV >= MAXFEV) INFO = 3
415 10 : if (BRACKT .AND. STMAX-STMIN <= XTOL*STMAX) INFO = 2
416 10 : if (F <= FTEST1 .AND. ABS(DG) <= GTOL*(-DGINIT)) INFO = 1
417 : !
418 : ! CHECK FOR TERMINATION.
419 : !
420 10 : if (INFO /= 0) return
421 : !
422 : ! IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED
423 : ! FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE.
424 : !
425 1 : if (STAGE1 .AND. F <= FTEST1 .AND. &
426 0 : DG >= MIN(FTOL,GTOL)*DGINIT) STAGE1 = .FALSE.
427 : !
428 : ! A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF
429 : ! WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED
430 : ! FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE
431 : ! DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN
432 : ! OBTAINED BUT THE DECREASE IS NOT SUFFICIENT.
433 : !
434 1 : if (STAGE1 .AND. F <= FX .AND. F > FTEST1) then
435 : !
436 : ! DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES.
437 : !
438 0 : FM = F - STP * DGTEST
439 0 : FXM = FX - STX * DGTEST
440 0 : FYM = FY - STY * DGTEST
441 0 : DGM = DG - DGTEST
442 0 : DGXM = DGX - DGTEST
443 0 : DGYM = DGY - DGTEST
444 : !
445 : ! CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
446 : ! AND TO COMPUTE THE NEW STEP.
447 : !
448 0 : call mcstep(STX,FXM,DGXM,STY,FYM,DGYM,STP,FM,DGM,BRACKT,STMIN,STMAX,INFOC)
449 : !
450 : ! RESET THE FUNCTION AND GRADIENT VALUES FOR F.
451 : !
452 0 : FX = FXM + STX * DGTEST
453 0 : FY = FYM + STY * DGTEST
454 0 : DGX = DGXM + DGTEST
455 0 : DGY = DGYM + DGTEST
456 : else
457 : !
458 : ! CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
459 : ! AND TO COMPUTE THE NEW STEP.
460 : !
461 1 : call mcstep(STX,FX,DGX,STY,FY,DGY,STP,F,DG,BRACKT,STMIN,STMAX,INFOC)
462 : endif
463 : !
464 : ! FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE
465 : ! INTERVAL OF UNCERTAINTY.
466 : !
467 1 : if (BRACKT) then
468 1 : if (ABS(STY-STX) >= P66 * WIDTH1) STP = STX + P5 * (STY - STX)
469 12 : WIDTH1 = WIDTH
470 12 : WIDTH = ABS(STY-STX)
471 : endif
472 :
473 : else
474 :
475 11 : INFOC = 1
476 : !
477 : ! CHECK THE INPUT PARAMETERS FOR ERRORS.
478 : !
479 : if ( STP <= zero .OR. FTOL < zero .OR. &
480 : GTOL < zero .OR. XTOL < zero .OR. STPMIN < zero &
481 11 : .OR. STPMAX < STPMIN ) return
482 : !
483 : ! COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION
484 : ! AND CHECK THAT S IS A DESCENT DIRECTION.
485 : !
486 308 : DGINIT = DOT_PRODUCT( G , S )
487 :
488 11 : if (DGINIT > zero) then
489 : return
490 : endif
491 : !
492 : ! INITIALIZE LOCAL VARIABLES.
493 : !
494 :
495 11 : BRACKT = .FALSE.
496 11 : STAGE1 = .TRUE.
497 11 : NFEV = 0
498 11 : FINIT = F
499 11 : DGTEST = FTOL * DGINIT
500 308 : WA(:) = X(:)
501 :
502 :
503 : !
504 : ! THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP,
505 : ! FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP.
506 : ! THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP,
507 : ! FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF
508 : ! THE INTERVAL OF UNCERTAINTY.
509 : ! THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP,
510 : ! FUNCTION, AND DERIVATIVE AT THE CURRENT STEP.
511 : !
512 11 : STX = zero
513 11 : FX = FINIT
514 11 : DGX = DGINIT
515 11 : STY = zero
516 11 : FY = FINIT
517 11 : DGY = DGINIT
518 : endif
519 :
520 : !
521 : !SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND
522 : !TO THE PRESENT INTERVAL OF UNCERTAINTY.
523 : !
524 12 : if (BRACKT) then
525 1 : STMIN = MIN(STX,STY)
526 1 : STMAX = MAX(STX,STY)
527 : else
528 11 : STMIN = STX
529 11 : STMAX = STP + XTRAPF*(STP - STX)
530 : endif
531 : !
532 : !FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN.
533 : !
534 12 : STP = MAX(STPMIN,STP)
535 12 : STP = MIN(STP,STPMAX)
536 : !
537 : !IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET
538 : !STP BE THE LOWEST POINT OBTAINED SO FAR.
539 : !
540 : if ((BRACKT .AND. (STP <= STMIN .OR. STP >= STMAX)) &
541 : .OR. NFEV >= MAXFEV-1 .OR. INFOC == 0 &
542 12 : .OR. (BRACKT .AND. STMAX-STMIN <= XTOL*STMAX)) STP = STX
543 :
544 : !
545 : !Evaluate the function and gradient at STP
546 : !and compute the directional derivative.
547 : !We return to main program to obtain F and G.
548 : !
549 336 : X(:) = WA(:) + STP * S(:)
550 :
551 12 : INFO = -1
552 :
553 : end subroutine mcsrch
554 : !!***
555 :
556 : !----------------------------------------------------------------------
557 :
558 : !!****f* m_lbfgs/mcstep
559 : !! NAME
560 : !! mcstep
561 : !!
562 : !! FUNCTION
563 : !! Perform the step choice in line minimization
564 : !! Fortran90 rewritting of the original subroutine by J. Nocera
565 : !!
566 : !! INPUTS
567 : !!
568 : !! OUTPUT
569 : !!
570 : !! SIDE EFFECTS
571 : !!
572 : !! SOURCE
573 :
574 1 : subroutine mcstep(STX,FX,DX,STY,FY,DY,STP,FP,DG,BRACKT,STPMIN,STPMAX,INFO)
575 :
576 : !Arguments ------------------------------------
577 : !scalars
578 : integer,intent(inout) :: INFO
579 : real(dp),intent(in) :: FP
580 : real(dp),intent(inout) :: STX,FX,DX,STY,FY,DY,STP,DG,STPMIN,STPMAX
581 : logical,intent(inout) :: BRACKT
582 :
583 : !Local variables-------------------------------
584 : !scalars
585 : logical BOUND
586 : real(dp) GAM,P,Q,R,S,SGND,STPC,STPF,STPQ,THETA
587 : !***************************************************************************
588 :
589 1 : INFO = 0
590 : !
591 : ! CHECK THE INPUT PARAMETERS FOR ERRORS.
592 : !
593 : IF ((BRACKT .AND. (STP <= MIN(STX,STY) .OR. &
594 : STP >= MAX(STX,STY))) .OR. &
595 1 : DX*(STP-STX) >= 0.0 .OR. STPMAX < STPMIN) RETURN
596 : !
597 : ! Determine if the derivatives have opposite sign
598 : !
599 1 : SGND = DG * ( DX / ABS(DX) )
600 :
601 : ! FIRST CASE. A HIGHER FUNCTION VALUE.
602 : ! THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER
603 : ! TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN,
604 : ! ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN.
605 : !
606 1 : IF (FP > FX) THEN
607 1 : INFO = 1
608 1 : BOUND = .TRUE.
609 1 : THETA = 3*(FX - FP)/(STP - STX) + DX + DG
610 1 : S = MAX(ABS(THETA),ABS(DX),ABS(DG))
611 1 : GAM = S * SQRT( (THETA/S)**2 - (DX/S)*(DG/S) )
612 1 : IF (STP < STX) GAM = -GAM
613 1 : P = (GAM - DX) + THETA
614 1 : Q = ((GAM - DX) + GAM) + DG
615 1 : R = P / Q
616 1 : STPC = STX + R*(STP - STX)
617 1 : STPQ = STX + ( ( DX / ( ( FX - FP ) / ( STP - STX ) + DX ) ) / 2 ) * ( STP - STX )
618 1 : IF (ABS(STPC-STX) < ABS(STPQ-STX)) THEN
619 : STPF = STPC
620 : ELSE
621 0 : STPF = STPC + (STPQ - STPC) / 2
622 : END IF
623 1 : BRACKT = .TRUE.
624 : !
625 : ! SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF
626 : ! OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC
627 : ! STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP,
628 : ! THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN.
629 : !
630 0 : ELSE IF (SGND < 0.0) THEN
631 0 : INFO = 2
632 0 : BOUND = .FALSE.
633 0 : THETA = 3*(FX - FP)/(STP - STX) + DX + DG
634 0 : S = MAX(ABS(THETA),ABS(DX),ABS(DG))
635 0 : GAM = S * SQRT( (THETA/S)**2 - (DX/S)*(DG/S) )
636 0 : IF (STP > STX) GAM = -GAM
637 0 : P = (GAM - DG) + THETA
638 0 : Q = ((GAM - DG) + GAM) + DX
639 0 : R = P/Q
640 0 : STPC = STP + R*(STX - STP)
641 0 : STPQ = STP + (DG/(DG-DX))*(STX - STP)
642 0 : IF (ABS(STPC-STP) > ABS(STPQ-STP)) THEN
643 : STPF = STPC
644 : ELSE
645 0 : STPF = STPQ
646 : END IF
647 0 : BRACKT = .TRUE.
648 : !
649 : ! THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
650 : ! SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES.
651 : ! THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY
652 : ! IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC
653 : ! IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE
654 : ! EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO
655 : ! COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP
656 : ! CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN.
657 : !
658 0 : ELSE IF (ABS(DG) < ABS(DX)) THEN
659 0 : INFO = 3
660 0 : BOUND = .TRUE.
661 0 : THETA = 3*(FX - FP)/(STP - STX) + DX + DG
662 0 : S = MAX(ABS(THETA),ABS(DX),ABS(DG))
663 : !
664 : ! THE CASE GAM = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND
665 : ! TO INFINITY IN THE DIRECTION OF THE STEP.
666 : !
667 0 : GAM = S * SQRT( MAX(0.0D0,(THETA/S)**2 - (DX/S)*(DG/S)) )
668 0 : IF (STP > STX) GAM = -GAM
669 0 : P = (GAM - DG) + THETA
670 0 : Q = (GAM + (DX - DG)) + GAM
671 0 : R = P/Q
672 0 : IF (R < 0.0 .AND. GAM .NE. 0.0) THEN
673 0 : STPC = STP + R*(STX - STP)
674 0 : ELSE IF (STP > STX) THEN
675 : STPC = STPMAX
676 : ELSE
677 0 : STPC = STPMIN
678 : END IF
679 0 : STPQ = STP + (DG/(DG-DX))*(STX - STP)
680 0 : IF (BRACKT) THEN
681 0 : IF (ABS(STP-STPC) < ABS(STP-STPQ)) THEN
682 : STPF = STPC
683 : ELSE
684 0 : STPF = STPQ
685 : END IF
686 : ELSE
687 0 : IF (ABS(STP-STPC) > ABS(STP-STPQ)) THEN
688 : STPF = STPC
689 : ELSE
690 0 : STPF = STPQ
691 : END IF
692 : END IF
693 : !
694 : ! FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
695 : ! SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES
696 : ! NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP
697 : ! IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN.
698 : !
699 : ELSE
700 0 : INFO = 4
701 0 : BOUND = .FALSE.
702 0 : IF (BRACKT) THEN
703 0 : THETA = 3*(FP - FY)/(STY - STP) + DY + DG
704 0 : S = MAX(ABS(THETA),ABS(DY),ABS(DG))
705 0 : GAM = S * SQRT( (THETA/S)**2 - (DY/S)*(DG/S) )
706 0 : IF (STP > STY) GAM = -GAM
707 0 : P = (GAM - DG) + THETA
708 0 : Q = ((GAM - DG) + GAM) + DY
709 0 : R = P/Q
710 0 : STPC = STP + R*(STY - STP)
711 0 : STPF = STPC
712 0 : ELSE IF (STP > STX) THEN
713 : STPF = STPMAX
714 : ELSE
715 0 : STPF = STPMIN
716 : END IF
717 : END IF
718 :
719 : !
720 : ! Update the interval of uncertainty. this update does not
721 : ! depend on the new step or the case analysis above.
722 : !
723 1 : IF (FP > FX) THEN
724 1 : STY = STP
725 1 : FY = FP
726 1 : DY = DG
727 : ELSE
728 0 : IF (SGND < 0.0) THEN
729 0 : STY = STX
730 0 : FY = FX
731 0 : DY = DX
732 : END IF
733 0 : STX = STP
734 0 : FX = FP
735 0 : DX = DG
736 : END IF
737 :
738 : !
739 : ! Compute the new step and safeguard it.
740 : !
741 1 : STPF = MIN(STPMAX,STPF)
742 1 : STPF = MAX(STPMIN,STPF)
743 1 : STP = STPF
744 1 : IF (BRACKT .AND. BOUND) THEN
745 1 : IF (STY > STX) THEN
746 1 : STP = MIN( STX + 0.66 * (STY-STX) , STP)
747 : ELSE
748 0 : STP = MAX( STX + 0.66 * (STY-STX) , STP)
749 : END IF
750 : END IF
751 :
752 :
753 : end subroutine mcstep
754 : !!***
755 :
756 0 : end module m_lbfgs
757 : !!***
|