muller Subroutine

private subroutine muller(me, Ioptn, Nparm, Numgr, Dvec, Fun, Ifun, Pttbl, Iptb, Indm, Zwork, Tolcon, Iphse, Iwork, Liwrk, Work, Lwrk, Parwrk, Err1, p1, f1, Procor, Emin)

In this subroutine we are given a base vector zwork, a direction vector dvec, a scalar procor with emin = f(procor) = (the maximum type -2 and -1 error with parameters zwork + procor*dvec) < -tolcon, and a scalar p1 with p1 < procor and f1 = f(p1) > tolcon. we do a revised mullers method approach (with a solution contained in a shrinking interval) to attempt to adjust procor so that -tolcon <= f(procor) <= tolcon, but if we are not successful we return with the leftmost procor found satisfying emin = f(procor) < -tolcon on the theory that overcorrection is better than no correction. note that when corrct calls this subroutine it will have lumped the type -1 constraints in with the type -2 constraints using jcntyp, which is carried through this subroutine into subroutine ercmp1 in iwork.

Type Bound

conmax_solver

Arguments

Type IntentOptional Attributes Name
class(conmax_solver), intent(inout) :: me
integer :: Ioptn
integer, intent(in) :: Nparm
integer, intent(in) :: Numgr
real(kind=wp) :: Dvec(Nparm)
real(kind=wp) :: Fun(Ifun)
integer, intent(in) :: Ifun
real(kind=wp) :: Pttbl(Iptb,Indm)
integer, intent(in) :: Iptb
integer, intent(in) :: Indm
real(kind=wp) :: Zwork(Nparm)
real(kind=wp) :: Tolcon
integer :: Iphse
integer :: Iwork(Liwrk)
integer :: Liwrk
real(kind=wp) :: Work(Lwrk)
integer, intent(in) :: Lwrk
real(kind=wp) :: Parwrk(Nparm)
real(kind=wp) :: Err1(Numgr+3)
real(kind=wp) :: p1
real(kind=wp) :: f1
real(kind=wp) :: Procor
real(kind=wp) :: Emin

Calls

proc~~muller~~CallsGraph proc~muller conmax_solver%muller proc~ercmp1 conmax_solver%ercmp1 proc~muller->proc~ercmp1 proc~iloc iloc proc~muller->proc~iloc proc~ercmp1->proc~iloc fnset fnset proc~ercmp1->fnset

Called by

proc~~muller~~CalledByGraph proc~muller conmax_solver%muller proc~corrct conmax_solver%corrct proc~corrct->proc~muller proc~rkcon conmax_solver%rkcon proc~rkcon->proc~corrct proc~rkpar conmax_solver%rkpar proc~rkcon->proc~rkpar proc~searsl conmax_solver%searsl proc~rkcon->proc~searsl proc~rkpar->proc~corrct proc~searsl->proc~corrct proc~conmax conmax_solver%conmax proc~conmax->proc~rkcon proc~slpcon conmax_solver%slpcon proc~conmax->proc~slpcon proc~slpcon->proc~searsl

Source Code

    subroutine muller(me, Ioptn, Nparm, Numgr, Dvec, Fun, Ifun, Pttbl, Iptb, Indm, &
                      Zwork, Tolcon, Iphse, Iwork, Liwrk, Work, Lwrk, Parwrk, &
                      Err1, p1, f1, Procor, Emin)

        implicit none

        class(conmax_solver), intent(inout) :: me
        integer, intent(in) :: Ifun
        integer, intent(in) :: Indm
        integer, intent(in) :: Iptb
        integer, intent(in) :: Lwrk
        integer, intent(in) :: Nparm
        integer, intent(in) :: Numgr
        integer :: Ioptn
        integer :: Iphse
        integer :: Liwrk
        real(wp) :: Emin
        real(wp) :: f1
        real(wp) :: p1
        real(wp) :: Procor
        real(wp) :: Tolcon
        integer :: Iwork(Liwrk)
        real(wp) :: Dvec(Nparm)
        real(wp) :: Err1(Numgr + 3)
        real(wp) :: Fun(Ifun)
        real(wp) :: Parwrk(Nparm)
        real(wp) :: Pttbl(Iptb, Indm)
        real(wp) :: Work(Lwrk)
        real(wp) :: Zwork(Nparm)

        real(wp) :: acof, bcof, ccof, den, discr, f2, f3, &
                    f4, fval, p2, p3, p4, pval, temp
        integer ::  ilc08, ilc21, imain, ipmax, ismax, j, limmul, &
                   lll, nsrch

        real(wp), parameter :: tol1 = ten*ten*spcmn
        real(wp), parameter :: tol4 = tol1/four
        real(wp), parameter :: tolden = ten*spcmn

        ! SET MACHINE AND PRECISION DEPENDENT CONSTANTS.
        ilc08 = iloc(8, Nparm, Numgr)
        ilc21 = iloc(21, Nparm, Numgr)
        limmul = 5
        nsrch = 0
        imain = 0
        p3 = Procor
        f3 = Emin

        ! WE DO NOT ALLOW THE LENGTH OF THE INTERVAL (P1,P3) TO FALL BELOW
        ! TOL1.
100     if (p3 - p1 < tol1) then
            return
        else
            ! COMPUTE P2 = (P1+P3)/2.0 AND F(P2).
            p2 = (p1 + p3)/two
            pval = p2
            ! SET LLL AS THE THREAD THROUGH THE MINOTAURS CAVERN AND JUMP DOWN TO
            ! COMPUTE F(PVAL)=F(P2).  WE WILL JUMP BACK AFTER ALL SUCH JUMPS.
            lll = 1
            goto 1000
        end if

        ! HERE -TOLCON <= F2 <= TOLCON AND WE RETURN WITH PROCOR=P2 AND
        ! EMIN=F2.
200     Procor = p2
        Emin = f2
        return

        ! HERE WE HAVE NOT ACHIEVED SUCCESS YET AND WE SEE IF THE ITERATION
        ! LIMIT HAS BEEN REACHED.
300     if (nsrch < limmul) then

            ! HERE WE HAVE NOT REACHED THE ITERATION LIMIT SO WE TRY AGAIN.
            ! IF IMAIN=0 HERE WE WILL HAVE NO P4 TO SHUFFLE IN, AND WE WILL HAVE
            ! ALREADY CHECKED P3-P1 >= TOL1, SO WE RESET IMAIN TO 1 AND DO A FIT.
            if (imain <= 0) goto 900

            ! HERE WE HAVE POINTS P1, P2, P3, P4 WITH P1+TOL1/4.0 <= P2 <=
            ! P3-TOL1/4.0, P1+TOL1/4.0 <= P4 <= P3-TOL1/4.0, ABS(P4-P2) >=
            ! TOL1/4.0, F(P1) > TOLCON, F(P3) < -TOLCON, ABS(F(P2)) >
            ! TOLCON, AND ABS(F(P4)) > TOLCON.  WE WILL NOW DISCARD EITHER
            ! P1 OR P3 AND RELABEL TO GET NEW POINTS P1, P2, P3, EXCEPT IN ONE
            ! CASE WHERE TWO POINTS WILL BE DISCARDED AND WE WILL RELABEL TO GET
            ! NEW POINTS P1, P3.
            ! IF P2 > P4 HERE WE WILL, IN THE INTEREST OF A MORE READABLE
            ! PROGRAM, INTERCHANGE P2 AND P4 (AND F2 AND F4) SO WE WILL BE ABLE
            ! TO ASSUME P2 <= P4.
            if (p2 > p4) then
                temp = p2
                p2 = p4
                p4 = temp
                temp = f2
                f2 = f4
                f4 = temp
            end if
            if (f2 <= 0) then
                ! HERE F2 < 0.0.
                if (f4 <= 0) goto 700
                ! HERE F2 < 0.0 AND F4 > 0.0, AND IN THIS SAWTOOTH PATTERN WE
                ! DISCARD BOTH P4 AND P3, SET IMAIN=0, AND GO BACK TO THE BEGINNING
                ! (EXCEPT NSRCH CONTINUES TO INCREASE, INSURING EVENTUAL TERMINATION).
                imain = 0
                p3 = p2
                f3 = f2
                Procor = p3
                Emin = f3
                goto 100
            else
                ! HERE F2 > 0.0.
                if (f4 <= 0) then
                    ! HERE F2 > 0.0 AND F4 < 0.0.
                    if (p2 - p1 <= (p3 - p4)) goto 700
                end if
                ! HERE EITHER F2 > 0.0 AND F4 > 0.0, OR ELSE F2 > 0.0,
                ! F4 < 0.0, AND P2-P1 > P3-P4.  WE DISCARD P1, SINCE IN THE
                ! FORMER CASE THE FIRST THREE F VALUES ARE ALL POSITIVE, AND IN THE
                ! LATTER CASE ONLY THE FIRST TWO F VALUES ARE POSITIVE, BUT BY DROPPING
                ! P1 WE CAN GET MAXIMUM SHRINKAGE OF P3-P1.
                p1 = p2
                f1 = f2
                p2 = p4
                f2 = f4
                goto 800
            end if
        else

            ! HERE WE HAVE REACHED THE ITERATION LIMIT WITHOUT SUCCESS.  WE RETURN
            ! WITH PROCOR = THE LEFTMOST OF THE THREE POINTS P2, P4, AND P3 WHICH
            ! HAS NEGATIVE F VALUE (UNLESS IMAIN=0, IN WHICH CASE WE IGNORE P4).
            ! WRITE(NWRIT,'(A)') '***WARNING  TOO MANY ITERATIONS IN MULLER***'
            if (imain <= 0) goto 600
            if (p2 <= p4) then
                ! HERE P2 < P4.
                if (f2 < 0) goto 200
                if (f4 >= 0) goto 500
                ! HERE P4 < P2.
            else if (f4 >= 0) then
                goto 600
            end if
        end if
400     Procor = p4
        Emin = f4
        return

500     Procor = p3
        Emin = f3
        return

600     if (f2 >= 0) goto 500
        goto 200

        ! HERE EITHER F2 < 0.0 AND F4 < 0.0, OR ELSE F2 > 0.0,
        ! F4 < 0.0, AND P2-P1 <= P3-P4.  WE DISCARD P3, SINCE IN THE
        ! FORMER CASE THE LAST THREE F VALUES ARE NEGATIVE, AND IN THE LATTER
        ! CASE ONLY THE LAST TWO F VALUES ARE NEGATIVE, BUT BY DROPPING P3 WE
        ! GET MAXIMUM SHRINKAGE OF P3-P1.
700     p3 = p4
        f3 = f4

        ! HERE WE HAVE THREE POINTS.  IF P3-P1 < TOL1 WE WILL RETURN AFTER
        ! SETTING PROCOR AND EMIN.
800     if (p3 - p1 < tol1) goto 600

        ! HERE WE RESET IMAIN TO 1 AND COMPUTE P4, THE UNIQUE ZERO IN THE
        ! INTERVAL (P1,P3) OF THE QUADRATIC POLYNOMIAL WHICH PASSES THROUGH
        ! (P1,F1), (P2,F2), AND (P3,F3).  RECALL THAT F1 > 0.0,
        ! F3 < 0.0, AND P1+TOL1/4.0 <= P2 <= P3-TOL1/4.0.
900     imain = 1

        ! COMPUTE THE COEFFICIENTS ACOF, BCOF, AND CCOF OF OUR POLYNOMIAL
        ! ACOF*X**2 + BCOF*X + CCOF.
        acof = ((f3 - f2)*(p2 - p1) - (f2 - f1)*(p3 - p2))/((p2 - p1)*(p3 - p2)*(p3 - p1))
        bcof = (f3 - f1)/(p3 - p1) - acof*(p1 + p3)
        ccof = f2 - p2*(acof*p2 + bcof)
        discr = bcof**2 - four*acof*ccof
        ! IN THEORY THE DISCRIMINANT SHOULD BE POSITIVE HERE, BUT TO BE SAFE WE
        ! CHECK IT IN CASE ROUNDOFF ERROR HAS MADE IT NEGATIVE.
        if (discr < 0) goto 600
        if (bcof <= 0) then
            ! HERE BCOF <= 0.0 AND WE USE THE ALTERNATE FORM OF THE QUADRATIC
            ! FORMULA.  NOTE THAT THE DENOMINATOR CANNOT BE ZERO SINCE THAT
            ! WOULD IMPLY BOTH BCOF=0.0 AND SQRT(...)=0.0, SO ALSO EITHER
            ! ACOF=0.0 OR CCOF=0.0, BUT THIS CONTRADICTS THE FACT THAT F1  >
            ! 0.0 AND F3 < 0.0.
            ! STILL, TO BE SAFE, WE CHECK THE SIZE OF THE DENOMINATOR.
            den = -bcof + sqrt(discr)
            if (den < tolden) goto 600
            p4 = two*ccof/den
        else
            ! HERE BCOF > 0.0 AND WE USE THE USUAL FORM OF THE QUADRATIC
            ! FORMULA TO TRY TO REDUCE PROBLEMS WITH SUBTRACTION AND SMALL
            ! DENOMINATORS.  THE MINUS SIGN IS USED IN FRONT OF THE SQUARE ROOT
            ! BECAUSE IF ACOF > 0.0 THEN THE POLYNOMIAL IS CONCAVE UP, WHICH
            ! IMPLIES P1 MUST BE ON THE LEFT BRANCH (SINCE F1 > F3), WHICH
            ! IMPLIES WE WANT THE LEFT (I.E. SMALLER) ZERO, AGREEING WITH
            ! -SQRT(...)/ACOF <= 0.0.  IF ON THE OTHER HAND ACOF < 0.0 THEN
            ! THE POLYNOMIAL IS CONCAVE DOWN, WHICH IMPLIES P3 MUST BE ON THE
            ! RIGHT BRANCH (SINCE F1 > F3), WHICH IMPLIES WE WANT THE RIGHT
            ! (I.E. LARGER) ZERO, AGREEING WITH -SQRT(...)/ACOF >= 0.0.
            ! NOTE THAT ACOF=0.0 CANNOT OCCUR HERE SINCE IF IT DID THE POLYNOMIAL
            ! WOULD BE LINEAR, AND BCOF > 0.0 WOULD THEN CONTRADICT F1 > F3.
            ! STILL, TO BE SAFE, WE CHECK THE SIZE OF THE DENOMINATOR.
            den = two*acof
            if (abs(den) < tolden) goto 600
            p4 = (-bcof - sqrt(discr))/den
        end if

        ! THE NEXT SECTION (FROM HERE TO STATEMENT 3200) MODIFIES P4, IF
        ! NECESSARY, TO GET P1+TOL4 <= P2,P4 <= P3-TOL4 AND ABS(P4-P2) >=
        ! TOL4.

        ! IF ABS(P4-P2) < TOL1/4.0 WE REDEFINE P4 BY MOVING IT A DISTANCE
        ! TOL1/4.0 FROM P2 INTO THE LONGER SUBINTERVAL.  NOTE THAT THE LENGTH
        ! OF THIS SUBINTERVAL MUST BE AT LEAST TOL1/2.0 SINCE P3-P1 >= TOL1.
        if (abs(p4 - p2) < tol4) then
            if (p3 - p2 <= (p2 - p1)) then
                p4 = p2 - tol4
            else
                p4 = p2 + tol4
            end if
            ! HERE WE HAD ABS(P4-P2) >= TOL4 AND WE MAKE SURE THAT P1+TOL4
            ! <= P4 <= P3-TOL4.
        else if (p4 <= (p3 - tol4)) then
            if (p4 < (p1 + tol4)) then
                ! HERE P4 < P1+TOL4 AND WE SET P4=P1+TOL4 IF P2-P1 >= TOL1/2.0
                ! AND OTHERWISE WE SET P4=P2+TOL4.
                if (p2 - p1 < tol1/two) then
                    p4 = p2 + tol4
                else
                    p4 = p1 + tol4
                end if
            end if
            ! HERE P4 > P3-TOL4 AND WE SET P4=P3-TOL4 IF P3-P2 >= TOL1/2.0,
            ! AND OTHERWISE WE SET P4=P2-TOL4.
        else if (p3 - p2 < tol1/two) then
            p4 = p2 - tol4
        else
            p4 = p3 - tol4
        end if

        ! COMPUTE F4=F(P4).
        pval = p4
        lll = 2

        ! NOW INCREMENT NSRCH SINCE WE ARE ABOUT TO COMPUTE F.
1000    nsrch = nsrch + 1

        ! HERE IS WHERE WE MUST SUPPLY A ROUTINE TO COMPUTE FVAL = F(PVAL) =
        ! THE MAXIMUM OF THE LEFT SIDES OF THE TYPE -2 AND -1 CONSTRAINTS.

        ! PROJECT DVEC TO GET PARWRK FOR USE IN ERCMP1.
        do j = 1, Nparm
            Parwrk(j) = Zwork(j) + pval*Dvec(j)
        end do
        ! WE TAKE IPHSE=-3 AS A KLUDGE TO TELL ERCMP1 TO COMPUTE ONLY STANDARD
        ! ERRORS IF THE TEN THOUSANDS DIGIT OF IOPTN IS 1, THUS SAVING ERCMP1
        ! THE WORK OF SCANNING ICNTYP.
        call me%ercmp1(Ioptn, Nparm, Numgr, Fun, Ifun, Pttbl, Iptb, Indm, Parwrk, 1, &
                       -3, Iwork, Liwrk, Work(ilc08), Iwork(ilc21), ipmax, ismax, &
                       Err1)
        fval = Err1(Numgr + 3)

        ! CARRY THE COMPUTED F VALUE BACK TO THE APPROPRIATE PART OF THE PROGRAM.
        if (lll == 1) then
            f2 = fval
            if (f2 > Tolcon) goto 300
            if (f2 + Tolcon >= 0) goto 200
            goto 300
        else if (lll == 2) then
            f4 = fval
            ! IF -TOLCON <= F4 <= TOLCON WE RETURN WITH PROCOR=P4 AND EMIN
            ! =F4, AND OTHERWISE WE GO BACK UP TO SEE IF WE HAVE REACHED THE LIMIT
            ! ON THE NUMBER OF STEPS.
            if (f4 > Tolcon) goto 300
            if (f4 + Tolcon >= 0) goto 400
            goto 300
        end if

    end subroutine muller