This subroutine computes a safeguarded step for a search procedure and updates an interval that contains a step that satisfies a sufficient decrease and a curvature condition.
The parameter stx contains the step with the least function
value. If brackt is set to .true. then a minimizer has
been bracketed in an interval with endpoints stx and sty.
The parameter stp contains the current step.
The subroutine assumes that if brackt is set to .true. then
min(stx,sty) < stp < max(stx,sty)
and that the derivative at stx is negative in the direction
of the step.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | Stx |
On entry |
||
| real(kind=wp), | intent(inout) | :: | Fx |
On entry |
||
| real(kind=wp), | intent(inout) | :: | Dx |
On entry |
||
| real(kind=wp), | intent(inout) | :: | Sty |
On entry |
||
| real(kind=wp), | intent(inout) | :: | Fy |
On entry |
||
| real(kind=wp), | intent(inout) | :: | Dy |
On entry |
||
| real(kind=wp), | intent(inout) | :: | Stp |
On entry |
||
| real(kind=wp), | intent(in) | :: | Fp |
the function at |
||
| real(kind=wp), | intent(in) | :: | Dp |
the derivative of the function at |
||
| logical, | intent(inout) | :: | Brackt |
On entry |
||
| real(kind=wp), | intent(in) | :: | Stpmin |
a lower bound for the step. |
||
| real(kind=wp), | intent(in) | :: | Stpmax |
an upper bound for the step. |
subroutine dcstep(Stx,Fx,Dx,Sty,Fy,Dy,Stp,Fp,Dp,Brackt,Stpmin, & Stpmax) implicit none logical,intent(inout) :: Brackt !! On entry `brackt` specifies if a minimizer has been bracketed. !! Initially `brackt` must be set to .false. !! On exit `brackt` specifies if a minimizer has been bracketed. !! When a minimizer is bracketed `brackt` is set to .true. real(wp),intent(inout) :: Stx !! On entry `stx` is the best step obtained so far and is an !! endpoint of the interval that contains the minimizer. !! On exit `stx is the updated best step. real(wp),intent(inout) :: Fx !! On entry `fx` is the function at `stx`. !! On exit `fx` is the function at `stx`. real(wp),intent(inout) :: Dx !! On entry `dx` is the derivative of the function at !! `stx`. The derivative must be negative in the direction of !! the step, that is, `dx` and `stp - stx` must have opposite !! signs. !! On exit `dx` is the derivative of the function at `stx`. real(wp),intent(inout) :: Sty !! On entry `sty` is the second endpoint of the interval that contains the minimizer. !! On exit `sty` is the updated endpoint of the interval that contains the minimizer. real(wp),intent(inout) :: Fy !! On entry `fy` is the function at `sty`. !! On exit `fy` is the function at `sty`. real(wp),intent(inout) :: Dy !! On entry `dy` is the derivative of the function at `sty`. !! On exit `dy` is the derivative of the function at the exit `sty`. real(wp),intent(inout) :: Stp !! On entry `stp` is the current step. If `brackt` is set to .true. !! then on input `stp` must be between `stx` and `sty`. !! On exit `stp` is a new trial step. real(wp),intent(in) :: Fp !! the function at `stp`. real(wp),intent(in) :: Dp !! the derivative of the function at `stp`. real(wp),intent(in) :: Stpmin !! a lower bound for the step. real(wp),intent(in) :: Stpmax !! an upper bound for the step. real(wp),parameter :: p66 = 0.66_wp real(wp) :: gamma , p , q , r , s , sgnd , stpc , stpf , & stpq , theta sgnd = Dp*(Dx/abs(Dx)) ! First case: A higher function value. The minimum is bracketed. ! If the cubic step is closer to stx than the quadratic step, the ! cubic step is taken, otherwise the average of the cubic and ! quadratic steps is taken. if ( Fp>Fx ) then theta = three*(Fx-Fp)/(Stp-Stx) + Dx + Dp s = max(abs(theta),abs(Dx),abs(Dp)) gamma = s*sqrt((theta/s)**2-(Dx/s)*(Dp/s)) if ( Stp<Stx ) gamma = -gamma p = (gamma-Dx) + theta q = ((gamma-Dx)+gamma) + Dp r = p/q stpc = Stx + r*(Stp-Stx) stpq = Stx + ((Dx/((Fx-Fp)/(Stp-Stx)+Dx))/two)*(Stp-Stx) if ( abs(stpc-Stx)<abs(stpq-Stx) ) then stpf = stpc else stpf = stpc + (stpq-stpc)/two endif Brackt = .true. ! Second case: A lower function value and derivatives of opposite ! sign. The minimum is bracketed. If the cubic step is farther from ! stp than the secant step, the cubic step is taken, otherwise the ! secant step is taken. else if ( sgnd<zero ) then theta = three*(Fx-Fp)/(Stp-Stx) + Dx + Dp s = max(abs(theta),abs(Dx),abs(Dp)) gamma = s*sqrt((theta/s)**2-(Dx/s)*(Dp/s)) if ( Stp>Stx ) gamma = -gamma p = (gamma-Dp) + theta q = ((gamma-Dp)+gamma) + Dx r = p/q stpc = Stp + r*(Stx-Stp) stpq = Stp + (Dp/(Dp-Dx))*(Stx-Stp) if ( abs(stpc-Stp)>abs(stpq-Stp) ) then stpf = stpc else stpf = stpq endif Brackt = .true. ! Third case: A lower function value, derivatives of the same sign, ! and the magnitude of the derivative decreases. else if ( abs(Dp)<abs(Dx) ) then ! The cubic step is computed only if the cubic tends to infinity ! in the direction of the step or if the minimum of the cubic ! is beyond stp. Otherwise the cubic step is defined to be the ! secant step. theta = three*(Fx-Fp)/(Stp-Stx) + Dx + Dp s = max(abs(theta),abs(Dx),abs(Dp)) ! The case gamma = 0 only arises if the cubic does not tend ! to infinity in the direction of the step. gamma = s*sqrt(max(zero,(theta/s)**2-(Dx/s)*(Dp/s))) if ( Stp>Stx ) gamma = -gamma p = (gamma-Dp) + theta q = (gamma+(Dx-Dp)) + gamma r = p/q if ( r<zero .and. gamma/=zero ) then stpc = Stp + r*(Stx-Stp) else if ( Stp>Stx ) then stpc = Stpmax else stpc = Stpmin endif stpq = Stp + (Dp/(Dp-Dx))*(Stx-Stp) if ( Brackt ) then ! A minimizer has been bracketed. If the cubic step is ! closer to stp than the secant step, the cubic step is ! taken, otherwise the secant step is taken. if ( abs(stpc-Stp)<abs(stpq-Stp) ) then stpf = stpc else stpf = stpq endif if ( Stp>Stx ) then stpf = min(Stp+p66*(Sty-Stp),stpf) else stpf = max(Stp+p66*(Sty-Stp),stpf) endif else ! A minimizer has not been bracketed. If the cubic step is ! farther from stp than the secant step, the cubic step is ! taken, otherwise the secant step is taken. if ( abs(stpc-Stp)>abs(stpq-Stp) ) then stpf = stpc else stpf = stpq endif stpf = min(Stpmax,stpf) stpf = max(Stpmin,stpf) endif ! Fourth case: A lower function value, derivatives of the same sign, ! and the magnitude of the derivative does not decrease. If the ! minimum is not bracketed, the step is either stpmin or stpmax, ! otherwise the cubic step is taken. else if ( Brackt ) then theta = three*(Fp-Fy)/(Sty-Stp) + Dy + Dp s = max(abs(theta),abs(Dy),abs(Dp)) gamma = s*sqrt((theta/s)**2-(Dy/s)*(Dp/s)) if ( Stp>Sty ) gamma = -gamma p = (gamma-Dp) + theta q = ((gamma-Dp)+gamma) + Dy r = p/q stpc = Stp + r*(Sty-Stp) stpf = stpc else if ( Stp>Stx ) then stpf = Stpmax else stpf = Stpmin endif endif ! Update the interval which contains a minimizer. if ( Fp>Fx ) then Sty = Stp Fy = Fp Dy = Dp else if ( sgnd<zero ) then Sty = Stx Fy = Fx Dy = Dx endif Stx = Stp Fx = Fp Dx = Dp endif ! Compute the new step. Stp = stpf end subroutine dcstep