This subroutine uses a modified quadratic fitting process to search for a projection factor procor for which the maximum of the left sides of the type -2 and -1 constraints evaluated at zwork + procor*dvec is <= tolcon. 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. if searcr is able to force this maximum <= tolcon it will return with isrcr=0, with the minimum value found for the maximum in emin, with the corresponding projection factor in procor, with the number of times the maximum was computed in nsrch, and with the closest point found to the left with the maximum > tolcon in (p1,f1). the subroutine will begin by computing the maxima for procor = 1.0, 0.5, and 2.0, and if none of these maxima is <= tolcon and it is not the case that the maximum at 1.0 is <= the other two maxima the subroutine will return with the warning isrcr=1. the subroutine will also return with isrcr=1 if it would need to compute f more than limscr times, or the search interval length drops below tol1, or the quadratic fit becomes too flat. even in the event of a return with isrcr=1, emin, procor, and nsrch will be as above.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(conmax_solver), | intent(inout) | :: | me | |||
| integer | :: | Ioptn | ||||
| integer, | intent(in) | :: | Nparm | |||
| integer | :: | 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, | intent(in) | :: | 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 | ||||
| integer | :: | Isrcr |
subroutine searcr(me, Ioptn, Nparm, Numgr, Dvec, Fun, Ifun, Pttbl, Iptb, Indm, & Zwork, Tolcon, Iphse, Iwork, Liwrk, Work, Lwrk, Parwrk, & Err1, p1, f1, Procor, Emin, Isrcr) implicit none class(conmax_solver), intent(inout) :: me integer, intent(in) :: Ifun integer, intent(in) :: Indm integer, intent(in) :: Iptb integer, intent(in) :: Liwrk integer, intent(in) :: Lwrk integer, intent(in) :: Nparm integer :: Ioptn integer :: Iphse integer :: Isrcr integer :: Numgr 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) :: f1kp, f2, f3, f4, fval, p2, p3, p4, & progr, pval, rlf, rrt, s1, s2 integer :: iaddl, iext, ilc08, ilc21, ilf, & ipmax, irt, ismax, j, limscr, lll, nsrch real(wp), parameter :: tolden = ten*spcmn real(wp), parameter :: tol1 = ten*ten*spcmn real(wp), parameter :: tol4 = tol1/four real(wp), parameter :: balfct = ten real(wp), parameter :: baladj = (ten - one)/ten ! SET MACHINE AND PRECISION DEPENDENT CONSTANTS. ilc08 = iloc(8, Nparm, Numgr) ilc21 = iloc(21, Nparm, Numgr) limscr = 6 Procor = one p1 = zero f1 = Err1(Numgr + 3) f1kp = f1 Isrcr = 0 nsrch = 0 ilf = 0 irt = 0 ! IF AFTER LIMSCR ITERATIONS HAVE BEEN DONE (WHERE LIMSCR >= 4) THE ! BEST VALUE FOUND IS <= PROGR WE WILL (ONCE ONLY) BUMP LIMSCR UP BY ! IADDL, SINCE THERE WOULD SEEM TO BE A GOOD CHANCE THAT THIS WILL ! PRODUCE SUCCESS. ! SETTING IEXT=1 HERE WILL DISABLE THE BUMPING PROCEDURE. iext = 0 iaddl = 6 progr = ten*ten*ten*Tolcon ! WE NOW TRY TO COMPUTE VALUES AT POINTS P2=PROCOR, P1=P2/2.0, AND ! P3=2.0*P2. p2 = Procor ! SET LLL=2 AS THE THREAD THROUGH THE MINOTAURS CAVERN AND JUMP ! DOWN TO PUT F(P2) IN F2. WE WILL JUMP BACK AFTER ALL SUCH JUMPS ! UNLESS LIMSCR WOULD BE EXCEEDED. lll = 2 pval = p2 goto 400 100 Emin = f3 Procor = two goto 800 ! IF THE SEARCH INTERVAL LENGTH IS LESS THAN TOL1 WE HAVE FAILED. 200 if (p3 - p1 >= tol1) then ! COMPUTE S1 = THE ABSOLUTE VALUE OF THE SLOPE OF THE LINE THROUGH ! (P1,F1) AND (P2,F2), AND S2 = THE (ABSOLUTE VALUE OF THE) SLOPE ! OF THE LINE THROUGH (P2,F2) AND (P3,F3). s1 = (f1 - f2)/(p2 - p1) s2 = (f3 - f2)/(p3 - p2) ! IF S1+S2 IS VERY SMALL WE HAVE FAILED. if (s1 + s2 >= tolden) then rlf = s2/(s1 + s2) rrt = one - rlf ! THE MINIMUM OF THE QUADRATIC POLYNOMIAL PASSING THROUGH ! (P1,F1), (P2,F2), AND (P3,F3) WILL OCCUR AT (RLF*P1+ ! RRT*P3+P2)/2.0. NOTE THAT THE THREE POINTS CANNOT BE ! COLLNEAR, ELSE WE WOULD HAVE TERMINATED ABOVE. SINCE THE ! MINIMUM OCCURS AT THE AVERAGE OF P2 AND A CONVEX COMBINATION ! OF P1 AND P3, IT WILL BE AT LEAST AS CLOSE TO P2 AS TO THE ! ENDPOINT ON THE SAME SIDE. if (ilf > 1) then ! HERE THE LEFT ENDPOINT WAS DROPPED AT THE LAST ILF > 1 ! ITERATIONS, SO TO PREVENT A LONG STRING OF SUCH OCCURRENCES ! WITH LITTLE REDUCTION OF P3-P1 WE WILL SHIFT THE NEW POINT ! TO THE RIGHT BY DECREASING RLF RELATIVE TO RRT. rlf = rlf/two**(ilf - 1) rrt = one - rlf else if (irt > 1) then ! HERE THE RIGHT ENDPOINT WAS DROPPED AT THE LAST IRT > 1 ! ITERATIONS, AND WE WILL SHIFT THE NEW POINT TO THE LEFT. rrt = rrt/two**(irt - 1) rlf = one - rrt ! HERE WE HAVE NOT JUST HAD A STRING OF TWO OR MORE MOVES IN ! THE SAME DIRECTION, BUT IF THE SUBINTERVALS ARE OUT OF ! BALANCE BY MORE THAN A FACTOR OF BALFCT, WE SHIFT THE NEW ! POINT SLIGHTLY IN THE DIRECTION OF THE LONGER INTERVAL. THE ! IDEA HERE IS THAT THE TWO CLOSE POINTS ARE PROBABLY NEAR THE ! SOLUTION, AND IF WE CAN BRACKET THE SOLUTION WE MAY BE ABLE TO ! CUT OFF THE MAJOR PORTION OF THE LONGER SUBINTERVAL. else if (p2 - p1 > balfct*(p3 - p2)) then ! HERE THE LEFT SUBINTERVAL IS MORE THAN BALFCT TIMES LONGER THAN ! THE RIGHT SUBINTERVAL, SO WE DECREASE RRT RRELATIVE TO RLF. rrt = baladj*rrt rlf = one - rrt else if (p3 - p2 > balfct*(p2 - p1)) then ! HERE THE RIGHT SUBINTERVAL IS MORE THAN BALFCT TIMES LONGER ! THAN THE LEFT SUBINTERVAL, SO WE DECREASE RLF RELATIVE TO RRT. rlf = baladj*rlf rrt = one - rlf end if ! COMPUTE THE (POSSIBLY MODIFIED) MINIMUM OF THE QUADRATIC FIT. p4 = (rlf*p1 + rrt*p3 + p2)/two ! THE NEXT SECTION (FROM HERE TO STATEMENT 2800) MODIFIES P4, IF ! NECESSARY, TO GET P1+TOL4 <= P2,P4 <= P3-TOL4 AND ABS(P4-P2) >= ! TOL4. THIS SECTION IS LESS COMPLICATED THAN THE CORRESPONDING SECTION ! IN SEARSL BECAUSE ALL PS LIE BETWEEN 0.5 AND 2.0, SO WEIRD ROUNDOFF ! EFFECTS ARE LESS LIKELY. ! IF ABS(P4-P2) < TOL4 WE REDEFINE P4 BY MOVING TOL4 FROM ! P2 INTO THE LONGER SUBINTERVAL. NOTE THAT THE LENGTH OF THIS ! SUBINTERVAL MUST BE AT LEAST TOL1/2.0 = 2.0*TOL4, ELSE WE ! WOULD HAVE TERMINATED EARLIER. if (abs(p4 - p2) < tol4) then if (p3 - p2 <= (p2 - p1)) then p4 = p2 - tol4 ! NOW JUMP DOWN TO PUT F(P4) IN F4. pval = p4 else p4 = p2 + tol4 pval = p4 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 pval = p4 ! HERE P4 < P1+TOL4 AND WE SET P4=P1+TOL4 IF P2-P1 >= TOL1/2.0 ! AND OTHERWISE WE SET P4=P2+TOL4. else if (p2 - p1 < tol1/two) then p4 = p2 + tol4 pval = p4 else p4 = p1 + tol4 pval = p4 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 pval = p4 else p4 = p3 - tol4 pval = p4 end if goto 400 end if end if 300 Emin = f2 Procor = p2 goto 800 ! WE INCREMENT NSRCH SINCE WE ARE ABOUT TO COMPUTE F. 400 nsrch = nsrch + 1 ! THIS IS WHERE WE COMPUTE THE MAXIMUM FVAL = F(PVAL) OF THE LEFT SIDES ! OF THE TYPE -2 AND TYPE -1 CONSTRAINTS. ! PROJECT DVEC TO GET PARWRK. 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) if (fval <= Tolcon) then ! HERE FVAL <= TOLCON AND WE RETURN AFTER SETTING PROCOR, EMIN, P1, ! AND F1. Procor = pval Emin = fval ! IF LLL=1 TAKE P1=0.0 AND F1=F1KP, IF LLL=2 LEAVE P1 AND F1 ALONE (THEY ! WILL BE 0.0 AND FIKP RESPECTIVELY), IF LLL=3 TAKE P1=P2 AND F1=F2, ! IF LLL=4 AND P2 < P4 TAKE P1=P2 AND F1=F2, AND IF LLL=4 AND ! P2 >= P4 LEAVE P1 AND F1 ALONE. IN ALL CASES (P1,F1) WILL BE THE ! POINT WITH P1 THE NEAREST VALUE LEFT OF PROCOR CONSIDERED AND WE WILL ! HAVE F1 > TOLCON. select case (lll) case (2) case (3) goto 500 case (4) if (p2 < p4) goto 500 case default p1 = zero f1 = f1kp end select return else ! HERE FVAL > TOLCON AND WE SEE IF LIMSCR ITERATIONS IN SEARCR HAVE ! BEEN DONE. IF SO WE SET THE FAILURE WARNING ISRCR=1 AND RETURN ! UNLESS WE CHOOSE TO INCREASE LIMSCR. if (nsrch < limscr) goto 900 ! HERE WE HAVE DONE LIMSCR ITERATIONS. if (iext > 0) goto 700 if (fval <= progr) goto 600 if (f2 > progr) goto 700 goto 600 end if 500 p1 = p2 f1 = f2 return ! HERE WE HAVE NOT BUMPED LIMSCR EARLIER, LIMSCR >= 4, AND ! MIN(FVAL,F2) <= PROGR, SO WE BUMP LIMSCR. 600 iext = 1 limscr = limscr + iaddl goto 900 ! WRITE(NWRIT,'(A)') '*****WARNING*****WARNING***** ! WRITE(NWRIT,'(A)') 'TOO MANY ITERATIONS IN SEARCR' ! HERE WE HAVE FAILED AND WE SET EMIN AND PROCOR FOR OUTPUT, SET ISRCR=1, ! AND RETURN. 700 if (fval > f2) goto 300 Emin = fval Procor = pval 800 Isrcr = 1 return ! HERE WE WILL CARRY THE COMPUTED F VALUE BACK TO THE APPROPRIATE PART ! OF THE PROGRAM. 900 select case (lll) case (1) f1 = fval p3 = two*p2 ! HERE SET LLL=3 AND PUT F(P3) IN F3. lll = 3 pval = p3 goto 400 case (2) f2 = fval p1 = p2/two ! SET LLL=1 AND PUT F(P1) IN F1. lll = 1 pval = p1 goto 400 case (3) f3 = fval ! WE NOW HAVE FOUND P1, P2, AND P3 WITH CORRESPONDING VALUES ! F1, F2, AND F3, AND WE CHECK WHETHER F2 <= MIN(F1,F3). if (f2 <= f1) then ! HERE F2 <= F1. IF F2 <= F3 WE ARE DONE INITIALIZING. if (f2 > f3) goto 100 ! END OF INITIALIZATION. ! ASSUMING THAT P3-P1 >= TOL1, WE NOW HAVE POINTS P1, P2, P3 WITH ! P1 <= P2-TOL4, P2 <= P3-TOL4, F1=F(P1) >= F2=F(P2), AND F3=F(P3) ! >= F2. THESE CONDITIONS WILL BE MAINTAINED THROUGHOUT THE PROGRAM. ! SET LLL=4, WHERE IT WILL REMAIN FROM NOW ON. lll = 4 goto 200 else if (f1 > f3) goto 100 Emin = f1 Procor = one/two goto 800 end if case (4) f4 = fval ! NOW WE DROP EITHER P1 OR P3 AND RELABEL THE REMAINING POINTS (IF ! NECESSARY) SO THAT F(P2) <= F(P1) AND F(P2) <= F(P3). ! IF NOW THE LEFTMOST OF THE TWO MIDDLE POINTS IS LOWER THAN THE ! RIGHTMOST OF THE TWO MIDDLE POINTS WE DROP P3, AND SET ILF=0 ! AND INCREMENT IRT TO INDICATE THE RIGHT END POINT HAS BEEN DROPPED. ! OTHERWISE WE DROP P1, SET IRT=0 AND INCREMENT ILF. IN ALL CASES ! WE THEN RESHUFFLE THE VALUES INTO P1, P2, P3, F1, F2, F3 AND TRY ! TO DO ANOTHER ITERATION. if (p4 < p2) then ! HERE P4 < P2. if (f4 < f2) then p3 = p2 f3 = f2 p2 = p4 f2 = f4 ilf = 0 irt = irt + 1 else p1 = p4 f1 = f4 ilf = ilf + 1 irt = 0 end if ! HERE P4 > P2. else if (f2 < f4) then p3 = p4 f3 = f4 ilf = 0 irt = irt + 1 else p1 = p2 f1 = f2 p2 = p4 f2 = f4 ilf = ilf + 1 irt = 0 end if goto 200 case default end select end subroutine searcr