LCOV - code coverage report
Current view: top level - src/45_geomoptim - m_lbfgs.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 66.8 % 223 149
Test Date: 2026-09-20 15:27:41 Functions: 75.0 % 8 6

            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              : !!***
        

Generated by: LCOV version 2.3-1