The ParaMonte Documentation Website
Current view: top level - kernel - Optimization_mod.f90 (source / functions) Hit Total Coverage
Test: ParaMonte 1.5.1 :: Coarray Parallel Kernel - Code Coverage Report Lines: 174 185 94.1 %
Date: 2021-01-08 12:59:07 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       2             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       3             : !!!!
       4             : !!!!   MIT License
       5             : !!!!
       6             : !!!!   ParaMonte: plain powerful parallel Monte Carlo library.
       7             : !!!!
       8             : !!!!   Copyright (C) 2012-present, The Computational Data Science Lab
       9             : !!!!
      10             : !!!!   This file is part of the ParaMonte library.
      11             : !!!!
      12             : !!!!   Permission is hereby granted, free of charge, to any person obtaining a
      13             : !!!!   copy of this software and associated documentation files (the "Software"),
      14             : !!!!   to deal in the Software without restriction, including without limitation
      15             : !!!!   the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             : !!!!   and/or sell copies of the Software, and to permit persons to whom the
      17             : !!!!   Software is furnished to do so, subject to the following conditions:
      18             : !!!!
      19             : !!!!   The above copyright notice and this permission notice shall be
      20             : !!!!   included in all copies or substantial portions of the Software.
      21             : !!!!
      22             : !!!!   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      23             : !!!!   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      24             : !!!!   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      25             : !!!!   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
      26             : !!!!   DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
      27             : !!!!   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
      28             : !!!!   OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      29             : !!!!
      30             : !!!!   ACKNOWLEDGMENT
      31             : !!!!
      32             : !!!!   ParaMonte is an honor-ware and its currency is acknowledgment and citations.
      33             : !!!!   As per the ParaMonte library license agreement terms, if you use any parts of
      34             : !!!!   this library for any purposes, kindly acknowledge the use of ParaMonte in your
      35             : !!!!   work (education/research/industry/development/...) by citing the ParaMonte
      36             : !!!!   library as described on this page:
      37             : !!!!
      38             : !!!!       https://github.com/cdslaborg/paramonte/blob/main/ACKNOWLEDGMENT.md
      39             : !!!!
      40             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      41             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      42             : 
      43             : !>  \brief This module contains numerical optimization procedures.
      44             : !>  \author Amir Shahmoradi
      45             : 
      46             : module Optimization_mod
      47             : 
      48             :     use Constants_mod, only: IK, RK
      49             :     use Err_mod, only: Err_type
      50             : 
      51             :     implicit none
      52             : 
      53             :     character(*), parameter :: MODULE_NAME = "@Optimization_mod"
      54             : 
      55             : #if defined OS_IS_WSL
      56             :     procedure(getFuncMD_proc), pointer  :: getFuncMD_WSL                    !< This madness bypasses the Microsoft Subsystem for Linux Internal Function call GFortran Segmentation Fault error.
      57             :     real(RK), allocatable               :: StartVec_WSL(:), DirVec_WSL(:)   !< This madness bypasses the Microsoft Subsystem for Linux Internal Function call GFortran Segmentation Fault error.
      58             :     integer(IK)                         :: ndim_WSL                         !< This madness bypasses the Microsoft Subsystem for Linux Internal Function call GFortran Segmentation Fault error.
      59             : #endif
      60             : 
      61             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      62             : 
      63             :     !> The Brent minimizer class.
      64             :     type :: BrentMinimum_type
      65             :         integer(IK)     :: niter                        !< the number of iterations to reach the minimum of the function
      66             :         real(RK)        :: Bracket(3)                   !< the initial 3 Bracketing points that envelop the minimum
      67             :         real(RK)        :: xtol = sqrt(epsilon(1._RK))  !< the stopping rule tolerance
      68             :         real(RK)        :: xmin                         !< the x-value at the minimum of the function
      69             :         real(RK)        :: fmin                         !< the minimum of the function
      70             :         type(Err_type)  :: Err
      71             :     end type BrentMinimum_type
      72             : 
      73             :     ! overload Brent
      74             : 
      75             :     interface BrentMinimum_type
      76             :         module procedure :: minimizeBrent
      77             :     end interface BrentMinimum_type
      78             : 
      79             :     ! interfaces of the objective functions
      80             : 
      81             :     abstract interface
      82             :         function getFunc1D_proc(x) result(funcVal)
      83             :             import :: RK
      84             :             real(RK)    , intent(in)    :: x
      85             :             real(RK)                    :: funcVal
      86             :         end function getFunc1D_proc
      87             :     end interface
      88             : 
      89             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      90             : 
      91             :     !> The Powell minimizer class.
      92             :     type :: PowellMinimum_type
      93             :         integer(IK)             :: niter                        !< The number of iterations to reach the minimum of the function.
      94             :         integer(IK)             :: ndim                         !< The number of dimensions of the function.
      95             :         real(RK)                :: ftol = sqrt(epsilon(1._RK))  !< The stopping rule tolerance for the value of function.
      96             :         real(RK), allocatable   :: xmin(:)                      !< The x-value at the minimum of the function.
      97             :         real(RK), allocatable   :: DirMat(:,:)                  !< An initial `(ndim,ndim)` matrix whose columns contain the initial set of directions (usually the `ndim` unit vectors).
      98             :        !real(RK), allocatable   :: StartVec(:)                  !< An initial vector of size `ndim` representing the start of the search.
      99             :         real(RK)                :: fmin                         !< The minimum of the function.
     100             :         type(Err_type)          :: Err
     101             :     end type PowellMinimum_type
     102             : 
     103             :     ! overload Powell
     104             : 
     105             :     interface PowellMinimum_type
     106             :         module procedure :: minimizePowell
     107             :     end interface PowellMinimum_type
     108             : 
     109             :     abstract interface
     110             :         function getFuncMD_proc(ndim,Point) result(funcVal)
     111             :             import :: RK, IK
     112             :             integer(IK) , intent(in)    :: ndim
     113             :             real(RK)    , intent(in)    :: Point(ndim)
     114             :             real(RK)                    :: funcVal
     115             :         end function getFuncMD_proc
     116             :     end interface
     117             : 
     118             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     119             : 
     120             :     interface minimize
     121             :         module procedure :: minimizeBrent, minimizePowell
     122             :     end interface minimize
     123             : 
     124             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     125             : 
     126             : contains
     127             : 
     128             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     129             : 
     130             :     !> The constructor of the class [BrentMinimum_type](@ref brentminimum_type).
     131             :     !> Compute the minimum of the input 1-dimensional function isolated to
     132             :     !> a fractional precision of about xtol using Brent's method.
     133             :     !>
     134             :     !> @param[in]   getFunc :   The 1-dimensional function which will have to be minimized.
     135             :     !> @param[in]   x0      :   The lower point in the set of optional bracketing triplet of abscissas that
     136             :     !>                          bracket the minimum of the function such that, `x0 < x1 < x2` and
     137             :     !>                          `getFunc(x0) > getFunc(x1) < getFunc(x2)` (**optional**).
     138             :     !> @param[in]   x1      :   The middle point in the set of optional bracketing triplet of abscissas that
     139             :     !>                          bracket the minimum of the function such that, `x0 < x1 < x2` and
     140             :     !>                          `getFunc(x0) > getFunc(x1) < getFunc(x2)` (**optional**).
     141             :     !> @param[in]   x2      :   The upper point in the set of optional bracketing triplet of abscissas that
     142             :     !>                          bracket the minimum of the function such that, `x0 < x1 < x2` and
     143             :     !>                          `getFunc(x0) > getFunc(x1) < getFunc(x2)` (**optional**).
     144             :     !> @param[in]   xtol    :   An optional fractional precision within which is the minimum is returned.
     145             :     !>                          The default value is sqrt(epsilon(1._RK)).
     146             :     !>
     147             :     !> \return
     148             :     !> `BrentMinimum` : An object of class [BrentMinimum_type](@ref brentminimum_type) that contains the minimum of the
     149             :     !>                  function (`xmin`) and the function value at the minimum (`fmin`) as well as other relevant information.
     150        2783 :     function minimizeBrent(getFunc, x0, x1, x2, xtol) result(BrentMinimum)
     151             : #if INTEL_COMPILER_ENABLED && defined DLL_ENABLED && (OS_IS_WINDOWS || defined OS_IS_DARWIN)
     152             :         !DEC$ ATTRIBUTES DLLEXPORT :: minimizeBrent
     153             : #endif
     154             :         use Constants_mod, only: IK, RK
     155             :         procedure(getFunc1D_proc)           :: getFunc
     156             :         real(RK)    , intent(in), optional  :: x0, x1, x2
     157             :         real(RK)    , intent(in), optional  :: xtol
     158             :         type(BrentMinimum_type)             :: BrentMinimum
     159             : 
     160             :         character(*), parameter             :: PROCEDURE_NAME = MODULE_NAME//"@minimizeBrent"
     161             :         integer(IK) , parameter             :: ITMAX = 1000_IK                  ! the maximum number of iterations
     162             :         real(RK)    , parameter             :: CGOLD = 0.3819660_RK             ! Golden Section switch criterion
     163             :         real(RK)    , parameter             :: ZEPS = sqrt(epsilon(1._RK))**3   ! tiny nonzero value
     164             : 
     165             :         integer(IK) :: iter
     166             :         logical     :: isPresentX0, isPresentX1, isPresentX2
     167        2783 :         real(RK)    :: a, b, d, e, etemp, fu, fv, fw, fx, p, q, r, tol1, tol2, u, v, w, x, xm
     168        2783 :         real(RK)    :: ax, bx, cx, fa, fb, fc
     169             : 
     170        2783 :         BrentMinimum%Err%occurred = .false.
     171             : 
     172        2783 :         if (present(xtol)) BrentMinimum%xtol = xtol
     173             : 
     174        2783 :         isPresentX0 = present(x0)
     175        2783 :         isPresentX1 = present(x1)
     176        2783 :         isPresentX2 = present(x2)
     177        2783 :         if (isPresentX0 .and. isPresentX1 .and. isPresentX2) then
     178       11120 :             BrentMinimum%Bracket = [x0, x1, x2]
     179             :         else
     180           3 :             if (isPresentX0) then
     181           0 :                 ax = x0
     182             :             else
     183           3 :                 ax = 0._RK ! assume an initial starting point of zero. This is the worst cae scenario.
     184             :             end if
     185           3 :             if (isPresentX1) then
     186           0 :                 bx = x1
     187             :             else
     188           3 :                 bx = ax + 1._RK
     189             :             end if
     190             :             call getBracket ( ax = ax &
     191             :                             , bx = bx &
     192             :                             , cx = cx &
     193             :                             , fa = fa &
     194             :                             , fb = fb &
     195             :                             , fc = fc &
     196             :                             , getFunc = getFunc &
     197           3 :                             )
     198          12 :             BrentMinimum%Bracket = [ax, bx, cx]
     199             :         end if
     200             : 
     201        2783 :         a = min( BrentMinimum%Bracket(1), BrentMinimum%Bracket(3) )
     202        2783 :         b = max( BrentMinimum%Bracket(1), BrentMinimum%Bracket(3) )
     203        2783 :         v = BrentMinimum%Bracket(2)
     204        2783 :         w = v
     205        2783 :         x = v
     206        2783 :         e = 0._RK
     207        2783 :         fx = getFunc(x)
     208        2783 :         fv = fx
     209        2783 :         fw = fx
     210       64143 :         do iter = 1, ITMAX
     211       64143 :             BrentMinimum%niter = iter
     212       64143 :             xm = 0.5_RK * (a+b)
     213       64143 :             tol1 = xtol*abs(x) + ZEPS
     214       64143 :             tol2 = 2.0_RK*tol1
     215       64143 :             if (abs(x-xm) <= (tol2-0.5_RK*(b-a))) then
     216        2783 :                 BrentMinimum%xmin = x
     217        2783 :                 BrentMinimum%fmin = fx
     218        2783 :                 return
     219             :             end if
     220       61360 :             if (abs(e) > tol1) then
     221       57815 :                 r = (x-w)*(fx-fv)
     222       57815 :                 q = (x-v)*(fx-fw)
     223       57815 :                 p = (x-v)*q-(x-w)*r
     224       57815 :                 q = 2.0_RK*(q-r)
     225       57815 :                 if (q > 0._RK) p = -p
     226       57815 :                 q = abs(q)
     227       57815 :                 etemp = e
     228       57815 :                 e = d
     229       57815 :                 if (abs(p) >= abs(0.5_RK*q*etemp) .or. p <= q*(a-x) .or. p >= q*(b-x)) then
     230       36665 :                     e = merge(a-x,b-x, x >= xm )
     231       36665 :                     d = cgold*e
     232             :                 else
     233       21150 :                     d = p/q
     234       21150 :                     u = x+d
     235       21150 :                     if (u-a < tol2 .or. b-u < tol2) d = sign(tol1,xm-x)
     236             :                 end if
     237             :             else
     238        3545 :                 e = merge(a-x,b-x, x >= xm )
     239        3545 :                 d = cgold*e
     240             :             end if
     241       61360 :             u = merge(x+d,x+sign(tol1,d), abs(d) >= tol1 )
     242       61360 :             fu = getFunc(u)
     243       61360 :             if (fu <= fx) then
     244       23011 :                 if (u >= x) then
     245       10214 :                     a = x
     246             :                 else
     247       12797 :                     b = x
     248             :                 end if
     249       23011 :                 call shft(v,w,x,u)
     250       23011 :                 call shft(fv,fw,fx,fu)
     251             :             else
     252       38349 :                 if (u < x) then
     253       18296 :                     a = u
     254             :                 else
     255       20053 :                     b = u
     256             :                 end if
     257       38349 :                 if (fu <= fw .or. w == x) then
     258       11800 :                     v = w
     259       11800 :                     fv = fw
     260       11800 :                     w = u
     261       11800 :                     fw = fu
     262       26549 :                 else if (fu <= fv .or. v == x .or. v == w) then
     263        7133 :                     v = u
     264        7133 :                     fv = fu
     265             :                 end if
     266             :             end if
     267             :         end do
     268             : 
     269             :         ! LCOV_EXCL_START
     270             :         BrentMinimum%Err%occurred = .true.
     271             :         BrentMinimum%Err%msg = PROCEDURE_NAME//": maximum number of iterations exceeded."
     272             :         ! LCOV_EXCL_STOP
     273        2783 :         return
     274             : 
     275             :     contains
     276             : 
     277       46022 :         subroutine shft(a,b,c,d)
     278             :             implicit none
     279             :             real(RK), intent(out) :: a
     280             :             real(RK), intent(inout) :: b,c
     281             :             real(RK), intent(in) :: d
     282       46022 :             a = b
     283       46022 :             b = c
     284       46022 :             c = d
     285        2783 :         end subroutine shft
     286             : 
     287             :     end function minimizeBrent
     288             : 
     289             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     290             : 
     291        2780 :     subroutine getBracket(ax,bx,cx,fa,fb,fc,getFunc)
     292             : #if INTEL_COMPILER_ENABLED && defined DLL_ENABLED && (OS_IS_WINDOWS || defined OS_IS_DARWIN)
     293             :         !DEC$ ATTRIBUTES DLLEXPORT :: getBracket
     294             : #endif
     295             :         use Constants_mod, only: IK, RK, TINY_RK
     296             :         use Misc_mod, only : swap
     297             :         implicit none
     298             : 
     299             :         real(RK), intent(inout)     :: ax, bx
     300             :         real(RK), intent(out)       :: cx, fa, fb, fc
     301             :         procedure(getFunc1D_proc)   :: getFunc
     302             : 
     303             :         real(RK), parameter         :: GOLD = 1.618034_RK
     304             :         real(RK), parameter         :: GLIMIT = 100.0_RK
     305             :         real(RK), parameter         :: TINY = TINY_RK ! 1.0e-20_RK
     306        2780 :         real(RK)                    :: fu, q, r, u, ulim
     307             : 
     308        5560 :         fa = getFunc(ax)
     309        2780 :         fb = getFunc(bx)
     310        2780 :         if (fb > fa) then
     311        2296 :             call swap(ax,bx)
     312        2296 :             call swap(fa,fb)
     313             :         end if
     314             : 
     315        2780 :         cx = bx + GOLD*(bx-ax)
     316        2780 :         fc = getFunc(cx)
     317        3024 :         do
     318        3024 :             if (fb < fc) return
     319         380 :             r = (bx-ax)*(fb-fc)
     320         380 :             q = (bx-cx)*(fb-fa)
     321         380 :             u = bx-((bx-cx)*q-(bx-ax)*r)/(2._RK*sign(max(abs(q-r),TINY),q-r))
     322         380 :             ulim = bx+GLIMIT*(cx-bx)
     323         380 :             if ((bx-u)*(u-cx) > 0._RK) then
     324         156 :                 fu = getFunc(u)
     325         156 :                 if (fu < fc) then
     326         136 :                     ax = bx
     327         136 :                     fa = fb
     328         136 :                     bx = u
     329         136 :                     fb = fu
     330         136 :                     return
     331          20 :                 else if (fu > fb) then
     332           0 :                     cx = u
     333           0 :                     fc = fu
     334           0 :                     return
     335             :                 end if
     336          20 :                 u = cx+GOLD*(cx-bx)
     337          20 :                 fu = getFunc(u)
     338         224 :             else if ((cx-u)*(u-ulim) > 0._RK) then
     339         224 :                 fu = getFunc(u)
     340         224 :                 if (fu < fc) then
     341         224 :                     bx = cx
     342         224 :                     cx = u
     343         224 :                     u = cx+GOLD*(cx-bx)
     344         224 :                     call shft(fb,fc,fu,getFunc(u))
     345             :                 end if
     346           0 :             else if ((u-ulim)*(ulim-cx) >= 0._RK) then
     347           0 :                 u = ulim
     348           0 :                 fu = getFunc(u)
     349             :             else
     350           0 :                 u = cx+GOLD*(cx-bx)
     351           0 :                 fu = getFunc(u)
     352             :             end if
     353         244 :             call shft(ax,bx,cx,u)
     354         244 :             call shft(fa,fb,fc,fu)
     355             :         end do
     356             : 
     357             :     contains
     358             : 
     359         712 :         subroutine shft(a,b,c,d)
     360             :             real(RK), intent(out) :: a
     361             :             real(RK), intent(inout) :: b,c
     362             :             real(RK), intent(in) :: d
     363         712 :             a = b
     364         712 :             b = c
     365         712 :             c = d
     366        2780 :         end subroutine shft
     367             : 
     368             :     end subroutine getBracket
     369             : 
     370             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     371             : 
     372             :     !> The constructor of the class [PowellMinimum_type](@ref powellminimum_type).
     373         221 :     function minimizePowell(ndim, getFuncMD, StartVec, DirMat, ftol) result(PowellMinimum)
     374             : #if INTEL_COMPILER_ENABLED && defined DLL_ENABLED && (OS_IS_WINDOWS || defined OS_IS_DARWIN)
     375             :         !DEC$ ATTRIBUTES DLLEXPORT :: minimizePowell
     376             : #endif
     377             :         use Constants_mod, only: IK, RK, TINY_RK ! tiny = 1.0e-25_RK
     378             :         implicit none
     379             : 
     380             :         procedure(getFuncMD_proc)               :: getFuncMD
     381             :         integer(IK) , intent(in)                :: ndim
     382             :         real(RK)    , intent(in)                :: StartVec(ndim)
     383             :         real(RK)    , intent(in)    , optional  :: DirMat(ndim,ndim)
     384             :         real(RK)    , intent(in)    , optional  :: ftol
     385             :         type(PowellMinimum_type)                :: PowellMinimum
     386             : 
     387             :         character(*), parameter                 :: PROCEDURE_NAME = MODULE_NAME//"@minimizeBrent"
     388             :         integer(IK), parameter                  :: ITMAX = 1000
     389             : 
     390             :         integer(IK)                             :: i, ibig
     391         442 :         real(RK)                                :: del,fp,fptt,t
     392        1547 :         real(RK)                                :: pt(ndim), ptt(ndim), xit(ndim)
     393             : 
     394         221 :         PowellMinimum%ndim = ndim
     395         221 :         PowellMinimum%Err%occurred = .false.
     396             : 
     397         663 :         allocate(PowellMinimum%xmin, source = StartVec)
     398             : 
     399         221 :         if (present(DirMat)) then
     400           0 :             PowellMinimum%DirMat = DirMat
     401             :         else
     402        1547 :             allocate(PowellMinimum%DirMat(ndim,ndim), source = 0._RK)
     403         663 :             do i = 1, ndim
     404         663 :                 PowellMinimum%DirMat(i,i) = 1._RK
     405             :             end do
     406             :         end if
     407         221 :         if (present(ftol)) PowellMinimum%ftol = ftol
     408             : 
     409         221 :         PowellMinimum%fmin = getFuncMD(ndim,PowellMinimum%xmin)
     410         663 :         pt = PowellMinimum%xmin
     411         221 :         PowellMinimum%niter = 0
     412         353 :         do
     413             : 
     414        1212 :             PowellMinimum%niter = PowellMinimum%niter + 1
     415        1212 :             fp = PowellMinimum%fmin
     416        1212 :             ibig = 0
     417        1212 :             del = 0._RK
     418        3636 :             do i = 1, ndim
     419        7272 :                 xit = PowellMinimum%DirMat(1:ndim,i)
     420        2424 :                 fptt = PowellMinimum%fmin
     421        2424 :                 call linmin(getFuncMD, ndim, PowellMinimum%xmin, xit, PowellMinimum%fmin, PowellMinimum%Err)
     422        2424 :                 if (PowellMinimum%Err%occurred) then
     423             :                 ! LCOV_EXCL_START
     424             :                     PowellMinimum%Err%msg = PROCEDURE_NAME//PowellMinimum%Err%msg
     425             :                     return
     426             :                 end if
     427             :                 ! LCOV_EXCL_STOP
     428        6060 :                 if (fptt - PowellMinimum%fmin > del) then
     429        1391 :                     del = fptt - PowellMinimum%fmin
     430        1391 :                     ibig = i
     431             :                 end if
     432             :             end do
     433             : 
     434        1212 :             if ( 2._RK*(fp-PowellMinimum%fmin) <= PowellMinimum%ftol*(abs(fp)+abs(PowellMinimum%fmin)) + TINY_RK ) return
     435             : 
     436         991 :             if (PowellMinimum%niter == ITMAX) then
     437             :             ! LCOV_EXCL_START
     438             :                 PowellMinimum%Err%occurred = .true.
     439             :                 PowellMinimum%Err%msg = PROCEDURE_NAME//": maximum number of iterations exceeded."
     440             :                 return
     441             :             end if
     442             :             ! LCOV_EXCL_STOP
     443             : 
     444        2973 :             ptt = 2._RK * PowellMinimum%xmin - pt
     445        2973 :             xit = PowellMinimum%xmin - pt
     446        2973 :             pt = PowellMinimum%xmin
     447         991 :             fptt = getFuncMD(ndim,ptt)
     448         991 :             if (fptt >= fp) cycle
     449         436 :             t = 2._RK * (fp-2._RK*PowellMinimum%fmin+fptt) * (fp-PowellMinimum%fmin-del)**2 - del*(fp-fptt)**2
     450         436 :             if (t >= 0.0) cycle
     451         353 :             call linmin(getFuncMD, ndim, PowellMinimum%xmin, xit, PowellMinimum%fmin, PowellMinimum%Err)
     452         353 :             if (PowellMinimum%Err%occurred) then
     453             :             ! LCOV_EXCL_START
     454             :                 PowellMinimum%Err%msg = PROCEDURE_NAME//PowellMinimum%Err%msg
     455             :                 return
     456             :             end if
     457             :             ! LCOV_EXCL_STOP
     458        1059 :             PowellMinimum%DirMat(1:ndim,ibig) = PowellMinimum%DirMat(1:ndim,ndim)
     459        1142 :             PowellMinimum%DirMat(1:ndim,ndim) = xit
     460             : 
     461             :         end do
     462             : 
     463         221 :     end function minimizePowell
     464             : 
     465             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     466             : 
     467        2777 :     subroutine linmin(getFuncMD, ndim, StartVec, DirVec, fmin, Err)
     468             : #if INTEL_COMPILER_ENABLED && defined DLL_ENABLED && (OS_IS_WINDOWS || defined OS_IS_DARWIN)
     469             :         !DEC$ ATTRIBUTES DLLEXPORT :: linmin
     470             : #endif
     471         221 :         use Constants_mod, only: IK, RK
     472             :         use Err_mod, only: Err_type
     473             :         implicit none
     474             :         procedure(getFuncMD_proc)       :: getFuncMD
     475             :         integer(IK)     , intent(in)    :: ndim
     476             :         real(RK)        , intent(inout) :: StartVec(ndim), DirVec(ndim)
     477             :         real(RK)        , intent(out)   :: fmin
     478             :         type(Err_type)  , intent(out)   :: Err
     479             :         real(RK)        , parameter     :: XTOL = 1.0e-8_RK
     480        2777 :         real(RK)                        :: ax, bx, fa, fb, fx, xx
     481        2777 :         type(BrentMinimum_type)         :: BrentMinimum
     482             : #if defined OS_IS_WSL
     483             :         getFuncMD_WSL => getFuncMD
     484             :         DirVec_WSL = DirVec
     485             :         StartVec_WSL = StartVec
     486             :         ndim_WSL = ndim
     487             : #endif
     488        2777 :         ax = 0.0
     489        2777 :         xx = 1.0
     490        2777 :         call getBracket(ax,xx,bx,fa,fx,fb,getFunc1D)
     491        2777 :         BrentMinimum = minimizeBrent(getFunc1D, ax, xx, bx, XTOL)
     492        2777 :         if (BrentMinimum%Err%occurred) then
     493             :         ! LCOV_EXCL_START
     494             :             Err = BrentMinimum%Err
     495             :             return
     496             :         ! LCOV_EXCL_STOP
     497             :         else
     498        2777 :             Err%occurred = .false.
     499             :         end if
     500        2777 :         fmin = BrentMinimum%fmin
     501        8331 :         DirVec = BrentMinimum%xmin * DirVec
     502        8331 :         StartVec = StartVec + DirVec
     503             : #if defined OS_IS_WSL
     504             :         nullify(getFuncMD_WSL)
     505             : #else
     506             :     contains
     507       73026 :         function getFunc1D(x) result(funcVal)
     508             :             implicit none
     509             :             real(RK), intent(in)    :: x
     510             :             real(RK)                :: funcVal
     511             :             real(RK), allocatable   :: xt(:)
     512      292101 :             xt = StartVec + x * DirVec
     513       73026 :             funcVal = getFuncMD(ndim,xt)
     514       75803 :         end function getFunc1D
     515             : #endif
     516             :     end subroutine linmin
     517             : 
     518             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     519             : 
     520             : #if defined OS_IS_WSL
     521             :         !> \brief
     522             :         !> Bypass the Microsoft Subsystem for Linux Internal Function call GFortran Segmentation Fault error.
     523             :         function getFunc1D(x) result(funcVal)
     524             : #if INTEL_COMPILER_ENABLED && defined DLL_ENABLED && (OS_IS_WINDOWS || defined OS_IS_DARWIN)
     525             :         !DEC$ ATTRIBUTES DLLEXPORT :: getFunc1D
     526             : #endif
     527             :             implicit none
     528             :             real(RK), intent(in)    :: x
     529             :             real(RK)                :: funcVal
     530             :             real(RK), allocatable   :: xt(:)
     531             :             xt = StartVec_WSL + x * DirVec_WSL
     532             :             funcVal = getFuncMD_WSL(ndim_WSL,xt)
     533             :         end function getFunc1D
     534             : #endif
     535             : 
     536             : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     537             : 
     538             : end module Optimization_mod ! LCOV_EXCL_LINE

ParaMonte: Plain Powerful Parallel Monte Carlo Library 
The Computational Data Science Lab
© Copyright 2012 - 2021