Line data Source code
1 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3 : !!!! !!!!
4 : !!!! ParaMonte: Parallel Monte Carlo and Machine Learning Library. !!!!
5 : !!!! !!!!
6 : !!!! Copyright (C) 2012-present, The Computational Data Science Lab !!!!
7 : !!!! !!!!
8 : !!!! This file is part of the ParaMonte library. !!!!
9 : !!!! !!!!
10 : !!!! LICENSE !!!!
11 : !!!! !!!!
12 : !!!! https://github.com/cdslaborg/paramonte/blob/main/LICENSE.md !!!!
13 : !!!! !!!!
14 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
15 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16 :
17 : !> \brief
18 : !> This include file contains the implementation of procedures in [pm_mathRoot](@ref pm_mathRoot).
19 : !>
20 : !> \finmain
21 : !>
22 : !> \author
23 : !> \AmirShahmoradi, Oct 16, 2009, 11:14 AM, Michigan
24 :
25 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26 :
27 : #define CHECK_LF(LF) \
28 : CHECK_ASSERTION(__LINE__, abs(LF - lf) < abstol, SK_"@setRoot(): The condition `abs(getFunc(lb), lf) < abstol` must hold. lb, getFunc(lb), lf, abstol = "//getStr([lb, LF, lf, abstol]))
29 : #define CHECK_UF(UF) \
30 : CHECK_ASSERTION(__LINE__, abs(UF - uf) < abstol, SK_"@setRoot(): The condition `abs(getFunc(ub), uf) < abstol` must hold. ub, getFunc(ub), uf, abstol = "//getStr([ub, UF, uf, abstol]))
31 : #define CHECK_BRACKET \
32 : CHECK_ASSERTION(__LINE__, sign(lf, 1._RKC) /= sign(uf, 1._RKC), \
33 : SK_"@setRoot(): The condition `sign(lf, 1.) /= sign(uf, 1.)` must hold. lf, uf = "//getStr([lf, uf])) ! fpp
34 : #define CHECK_LB_LT_UB \
35 : CHECK_ASSERTION(__LINE__, lb < ub, SK_"@setRoot(): The condition `lb < ub` must hold. lb, ub = "//getStr([lb, ub])) ! fpp
36 : #define CHECK_ZERO_LT_ABSTOL \
37 : CHECK_ASSERTION(__LINE__, 0._RKC < abstol, SK_"@setRoot(): The condition `0. < abstol` must hold. abstol = "//getStr(abstol)) ! fpp
38 : #define CHECK_ABSTOL_LT_LB_UB_DIFF \
39 : CHECK_ASSERTION(__LINE__, abstol < ub - lb, \
40 : SK_"@setRoot(): The condition `abstol < ub - lb` must hold. abstol, ub, lb = "//getStr([abstol, ub, lb])) ! fpp
41 : real(RKC), parameter :: EPS10 = 10 * epsilon(0._RKC)
42 : #if Fixed_ENABLED
43 : #define CHECK_ZERO_LT_NITER
44 : integer(IK), parameter :: NITER = ceiling(50 * precision(0._RKC) / log10(2._RKC))
45 : #elif Niter_ENABLED
46 : #define CHECK_ZERO_LT_NITER \
47 : CHECK_ASSERTION(__LINE__, 0_IK < niter, SK_"@setRoot(): The condition `0 < niter` must hold. niter = "//getStr(niter)) ! fpp
48 : #elif !getRoot_ENABLED
49 : #error "Unrecognized interface."
50 : #endif
51 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 : #if getRoot_ENABLED && Def_ENABLED
53 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
54 :
55 96006 : root = getRoot(brent, getFunc, lb, ub, abstol, neval, niter)
56 :
57 : !%%%%%%%%%%%%%%
58 : #elif getRoot_ENABLED
59 : !%%%%%%%%%%%%%%
60 :
61 : real(RKC) :: abstol_def, lf, uf
62 : integer(IK) :: neval_def
63 137633 : if (present(abstol)) then
64 68801 : abstol_def = abstol
65 : else
66 68832 : abstol_def = epsilon(0._RKC)**.8 * (abs(lb) + abs(ub))
67 : end if
68 : #if Newton_ENABLED || Halley_ENABLED || Schroder_ENABLED
69 19209 : lf = getFunc(lb, 0_IK)
70 19209 : uf = getFunc(ub, 0_IK)
71 19209 : if (present(init)) then
72 9600 : root = init
73 : else
74 9609 : root = 0.5_RKC * (lb + ub)
75 : end if
76 : #elif False_ENABLED || Bisection_ENABLED || Secant_ENABLED || Brent_ENABLED || Ridders_ENABLED || TOMS748_ENABLED
77 118424 : lf = getFunc(lb)
78 118424 : uf = getFunc(ub)
79 : #else
80 : #error "Unrecognized interface."
81 : #endif
82 137633 : if (present(niter)) then
83 100800 : call setRoot(method, getFunc, root, lb, ub, lf, uf, abstol_def, neval_def, niter)
84 : else
85 36833 : call setRoot(method, getFunc, root, lb, ub, lf, uf, abstol_def, neval_def)
86 : end if
87 137633 : if (present(neval)) then
88 100830 : neval = neval_def + 2_IK
89 36803 : elseif (neval_def < 0_IK) then
90 : error stop MODULE_NAME//SK_"@getRoot(): Failed to converge in search for the root of the specified function." ! LCOV_EXCL_LINE
91 : end if
92 :
93 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 : #elif setRoot_ENABLED && False_ENABLED
95 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 :
97 : real(RKC) :: diff, interval, func
98 4006 : if (abs(lf) <= EPS10) then
99 906 : neval = 0_IK
100 906 : root = lb
101 3100 : elseif (abs(uf) <= EPS10) then
102 982 : neval = 0_IK
103 982 : root = ub
104 2118 : elseif (abs(ub - lb) < abstol) then
105 0 : root = .5_RKC * (ub + lb)
106 0 : neval = 0_IK
107 : else
108 6354 : CHECK_BRACKET
109 6354 : CHECK_LB_LT_UB
110 2118 : CHECK_ZERO_LT_ABSTOL
111 10590 : CHECK_LF(getFunc(lb))
112 10590 : CHECK_UF(getFunc(ub))
113 8472 : CHECK_ABSTOL_LT_LB_UB_DIFF
114 2118 : if (0._RKC <= lf) then
115 1076 : diff = lb
116 1076 : lb = ub
117 1076 : ub = diff
118 : diff = lf
119 : lf = uf
120 : uf = diff
121 : end if
122 2118 : interval = ub - lb
123 56536 : do neval = 1_IK, niter
124 56536 : root = lb + interval * lf / (lf - uf)
125 56536 : func = getFunc(root)
126 56536 : if (func < 0._RKC) then
127 56468 : diff = lb - root
128 56468 : lb = root
129 : lf = func
130 : else
131 68 : diff = ub - root
132 68 : ub = root
133 : uf = func
134 : end if
135 56536 : interval = ub - lb
136 56536 : if (abs(diff) < abstol .or. func == 0._RKC) return
137 : end do
138 : ! Error occurred.
139 0 : root = .5_RKC * (lb + ub) ! for the sake of defining `root` on output (important for tests).
140 0 : neval = -neval
141 : end if
142 :
143 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144 : #elif setRoot_ENABLED && Bisection_ENABLED
145 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 :
147 : real(RKC) :: delta, center
148 4006 : if (abs(lf) <= EPS10) then
149 950 : neval = 0_IK
150 950 : root = lb
151 3056 : elseif (abs(uf) <= EPS10) then
152 1030 : neval = 0_IK
153 1030 : root = ub
154 2026 : elseif (abs(ub - lb) < abstol) then
155 0 : root = .5_RKC * (ub + lb)
156 0 : neval = 0_IK
157 : else
158 6078 : CHECK_BRACKET
159 6078 : CHECK_LB_LT_UB
160 1010 : CHECK_ZERO_LT_NITER
161 2026 : CHECK_ZERO_LT_ABSTOL
162 10130 : CHECK_LF(getFunc(lb))
163 10130 : CHECK_UF(getFunc(ub))
164 8104 : CHECK_ABSTOL_LT_LB_UB_DIFF
165 2026 : if (lf < 0._RKC) then
166 970 : root = lb
167 970 : delta = ub - lb
168 : else
169 1056 : root = ub
170 1056 : delta = lb - ub
171 : end if
172 78204 : do neval = 3_IK, NITER + 2_IK
173 78204 : delta = delta * 0.5_RKC
174 78204 : center = root + delta
175 78204 : uf = getFunc(center)
176 78204 : if (uf <= 0._RKC) root = center
177 78204 : if (abs(delta) < abstol .or. uf == 0._RKC) return
178 : end do
179 : ! Error occurred.
180 0 : root = .5_RKC * (lb + ub) ! for the sake of defining `root` on output (important for tests).
181 0 : neval = -neval
182 : end if
183 :
184 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 : #elif setRoot_ENABLED && Secant_ENABLED
186 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 :
188 : real(RKC) :: x, delta
189 4006 : if (abs(lf) <= EPS10) then
190 1056 : neval = 0_IK
191 1056 : root = lb
192 2950 : elseif (abs(uf) <= EPS10) then
193 968 : neval = 0_IK
194 968 : root = ub
195 1982 : elseif (abs(ub - lb) < abstol) then
196 0 : root = .5_RKC * (ub + lb)
197 0 : neval = 0_IK
198 : else
199 5946 : CHECK_BRACKET
200 5946 : CHECK_LB_LT_UB
201 988 : CHECK_ZERO_LT_NITER
202 1982 : CHECK_ZERO_LT_ABSTOL
203 9910 : CHECK_LF(getFunc(lb))
204 9910 : CHECK_UF(getFunc(ub))
205 7928 : CHECK_ABSTOL_LT_LB_UB_DIFF
206 1982 : if (abs(lf) < abs(uf)) then
207 836 : root = lb
208 836 : x = ub
209 : delta = lf
210 : lf = uf
211 : uf = delta
212 : else
213 1146 : x = lb
214 1146 : root = ub
215 : end if
216 17206 : do neval = 1_IK, niter
217 17206 : delta = (x - root) * uf / (uf - lf)
218 : x = root
219 : lf = uf
220 17206 : root = root + delta
221 17206 : uf = getFunc(root)
222 17206 : if (abs(delta) < abstol .or. uf == 0._RKC) return
223 : end do
224 : ! Error occurred.
225 0 : root = .5_RKC * (lb + ub) ! for the sake of defining `root` on output (important for tests).
226 0 : neval = -neval
227 : end if
228 :
229 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230 : #elif setRoot_ENABLED && Brent_ENABLED
231 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 :
233 : real(RKC) :: halfAbsTol
234 : real(RKC) :: middle, interval, funMid, tol1, halfint, rnew, p, q, r, ratio
235 : real(RKC) , parameter :: EPS = epsilon(lb)
236 103212 : if (abs(lf) <= EPS10) then
237 26170 : neval = 0_IK
238 26170 : root = lb
239 77042 : elseif (abs(uf) <= EPS10) then
240 25518 : neval = 0_IK
241 25518 : root = ub
242 51524 : elseif (abs(ub - lb) < abstol) then
243 0 : root = .5_RKC * (ub + lb)
244 0 : neval = 0_IK
245 : else
246 154572 : CHECK_BRACKET
247 154572 : CHECK_LB_LT_UB
248 41740 : CHECK_ZERO_LT_NITER
249 51524 : CHECK_ZERO_LT_ABSTOL
250 257620 : CHECK_LF(getFunc(lb))
251 257620 : CHECK_UF(getFunc(ub))
252 206096 : CHECK_ABSTOL_LT_LB_UB_DIFF
253 51524 : halfAbsTol = 0.5_RKC * abstol
254 51524 : root = ub
255 : middle = ub
256 : funMid = uf
257 267808 : do neval = 0, niter
258 : ! adjust the search interval, if needed.
259 235840 : if ((funMid < 0._RKC .and. uf < 0._RKC) .or. (0._RKC < uf .and. 0._RKC < funMid)) then ! same sign
260 156781 : middle = lb
261 : funMid = lf
262 156781 : interval = root - lb
263 : rnew = interval
264 : end if
265 235840 : if (abs(funMid) < abs(uf)) then
266 39534 : lb = root
267 39534 : root = middle
268 : middle = lb
269 : lf = uf
270 : uf = funMid
271 : funMid = lf
272 : end if
273 235840 : halfint = .5_RKC * (middle - root)
274 235840 : tol1 = 2._RKC * EPS * abs(root) + halfAbsTol
275 235840 : if (abs(halfint) < tol1 .or. uf == 0._RKC) return
276 : ! See if a bisection is needed.
277 216284 : if ((abs(rnew) >= tol1) .and. (abs(lf) > abs(uf))) then
278 216284 : ratio = uf / lf ! 50
279 216284 : if (lb /= middle) then ! Try inverse quadratic interpolation.
280 68720 : q = lf / funMid
281 68720 : r = uf / funMid
282 68720 : p = ratio * (2._RKC * halfint * q * (q - r) - (root - lb) * (r - 1._RKC))
283 68720 : q = (q - 1._RKC) * (r - 1._RKC) * (ratio - 1._RKC)
284 : else ! Try linear interpolation.
285 147564 : p = 2._RKC * halfint * ratio
286 147564 : q = 1._RKC - ratio
287 : end if
288 216284 : if (0._RKC < p) then ! Check inbounds.
289 109119 : q = -q
290 : else
291 107165 : p = -p
292 : end if
293 216284 : if (((2._RKC * p) >= (3._RKC * halfint * q - abs(tol1 * q))) .or. (p >= abs(0.5_RKC * rnew * q))) then ! Interpolation failed, use bisection.
294 : interval = halfint
295 : rnew = interval
296 : else ! Accept interpolation.
297 : rnew = interval
298 199032 : interval = p / q
299 : end if
300 : else ! Bounds decreasing too slowly, use bisection.
301 : interval = halfint
302 : rnew = interval
303 : end if
304 : ! Move last best guess to a.
305 216284 : lb = root ! 110
306 : lf = uf
307 : ! Evaluate new trial root.
308 216284 : if (tol1 < abs(interval)) then
309 207104 : root = root + interval
310 9180 : elseif (0._RKC < halfint) then
311 4346 : root = root + tol1
312 : else
313 4834 : root = root - tol1
314 : end if
315 248252 : uf = getFunc(root)
316 : end do
317 : ! Error occurred.
318 31968 : root = .5_RKC * (lb + root) ! for the sake of defining `root` on output (important for tests).
319 31968 : neval = -neval
320 : end if
321 :
322 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323 : #elif setRoot_ENABLED && Ridders_ENABLED
324 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 :
326 : real(RKC) :: halfint, rold, fold, func, multiplicity
327 4006 : neval = 0_IK
328 4006 : if (abs(lf) <= EPS10) then
329 1064 : root = lb
330 2942 : elseif (abs(uf) <= EPS10) then
331 1022 : root = ub
332 1920 : elseif (abs(ub - lb) < abstol) then
333 0 : root = .5_RKC * (ub + lb)
334 : else
335 5760 : CHECK_BRACKET
336 5760 : CHECK_LB_LT_UB
337 957 : CHECK_ZERO_LT_NITER
338 1920 : CHECK_ZERO_LT_ABSTOL
339 9600 : CHECK_LF(getFunc(lb))
340 9600 : CHECK_UF(getFunc(ub))
341 7680 : CHECK_ABSTOL_LT_LB_UB_DIFF
342 : !rnew = huge(rold)**.66
343 : do
344 12906 : halfint = 0.5_RKC * (ub - lb)
345 12906 : root = lb + halfint
346 12906 : func = getFunc(root)
347 12906 : neval = neval + 1_IK
348 12906 : if (niter < neval) exit
349 12906 : multiplicity = sqrt(func**2 - lf * uf)
350 : if (multiplicity == 0._RKC) return ! LCOV_EXCL_LINE ! This should rarely occur.
351 12906 : rold = root
352 : fold = func
353 12906 : root = rold + halfint * sign(fold, lf - uf) / multiplicity
354 12906 : if (abs(root - rold) < abstol) return ! This should never occur in the first iteration.
355 12582 : func = getFunc(root)
356 12582 : neval = neval + 1_IK
357 12582 : if (niter < neval) exit
358 : if (func == 0._RKC) return ! LCOV_EXCL_LINE
359 11112 : if (sign(fold, func) /= fold) then
360 7768 : lb = rold
361 : lf = fold
362 : uf = func
363 7768 : ub = root
364 3344 : elseif (sign(lf, func) /= lf) then
365 1644 : ub = root
366 : uf = func
367 1700 : elseif (sign(uf, func) /= uf) then
368 1700 : lb = root
369 : lf = func
370 : else
371 0 : error stop MODULE_NAME//SK_"@setRootRidders(): Internal library error detected. This condition should never occur."
372 : end if
373 11112 : if (abs(ub - lb) < abstol) exit
374 : end do
375 126 : if (niter < neval) then
376 0 : neval = -neval ! Error occurred.
377 : else
378 126 : root = .5_RKC * (lb + ub)
379 : end if
380 : end if
381 :
382 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 : #elif setRoot_ENABLED && TOMS748_ENABLED
384 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385 :
386 : real(RKC) , parameter :: EPS5 = 5 * epsilon(0._RKC), SMALL = tiny(0._RKC) / epsilon(0._RKC) !* 32
387 : real(RKC) :: rmid, rupp, fupp, rold, fold, rnew, fnew, interval
388 4006 : neval = 0_IK
389 4006 : if (abs(lf) <= EPS10) then
390 988 : root = lb
391 3018 : elseif (abs(uf) <= EPS10) then
392 1004 : root = ub
393 2014 : elseif (abs(ub - lb) < abstol) then
394 0 : root = .5_RKC * (ub + lb)
395 : else
396 6042 : CHECK_BRACKET
397 6042 : CHECK_LB_LT_UB
398 1004 : CHECK_ZERO_LT_NITER
399 2014 : CHECK_ZERO_LT_ABSTOL
400 10070 : CHECK_LF(getFunc(lb))
401 10070 : CHECK_UF(getFunc(ub))
402 8056 : CHECK_ABSTOL_LT_LB_UB_DIFF
403 : !fnew = 1.e5_RKC
404 : !rnew = 1.e5_RKC
405 : !fold = 1.e5_RKC
406 : blockConvergence: block
407 : ! On the first step we take lb secant step.
408 2014 : rmid = lb - lf * (ub - lb) / (uf - lf)
409 2014 : if (rmid <= lb + abs(lb) * EPS5 .or. ub - abs(ub) * EPS5 <= rmid) rmid = .5_RKC * (lb + ub)
410 2014 : call setBracket(getFunc, lb, ub, rmid, lf, uf, rold, fold)
411 2014 : neval = neval + 1_IK
412 : ! Take a quadratic interpolation on the second step.
413 2014 : call setPolIntQuad(rmid, lb, ub, rold, lf, uf, fold, nstep = 2_IK)
414 2014 : rnew = rold
415 2014 : fnew = fold
416 2014 : neval = neval + 1_IK
417 2014 : call setBracket(getFunc, lb, ub, rmid, lf, uf, rold, fold)
418 7958 : loopConvergence: do
419 3522 : interval = ub - lb
420 3522 : if (niter < neval .or. lf == 0._RKC .or. abs(ub - lb) < abstol) exit blockConvergence
421 : ! Starting with the third step taken use either quadratic or cubic interpolation.
422 : ! Cubic interpolation requires that all four function values lf, uf, fold, and fnew are distinct.
423 : ! Should that not be the case, take a quadratic step instead.
424 : if ((abs(lf - uf) < SMALL) .or. & ! LCOV_EXCL_LINE
425 : (abs(lf - fold) < SMALL) .or. & ! LCOV_EXCL_LINE
426 : (abs(lf - fnew) < SMALL) .or. & ! LCOV_EXCL_LINE
427 : (abs(uf - fold) < SMALL) .or. & ! LCOV_EXCL_LINE
428 : (abs(uf - fnew) < SMALL) .or. & ! LCOV_EXCL_LINE
429 : (abs(fold - fnew) < SMALL)) then
430 0 : call setPolIntQuad(rmid, lb, ub, rold, lf, uf, fold, nstep = 2_IK)
431 : else
432 3520 : call setPolIntCubic(rmid, lb, ub, rold, rnew, lf, uf, fold, fnew)
433 : end if
434 : ! Re-bracket and check for termination.
435 3520 : rnew = rold
436 3520 : fnew = fold
437 3520 : neval = neval + 1_IK
438 3520 : call setBracket(getFunc, lb, ub, rmid, lf, uf, rold, fold)
439 3520 : if (niter < neval .or. lf == 0._RKC .or. abs(ub - lb) < abstol) exit blockConvergence
440 : ! Next interpolated step.
441 : if ((abs(lf - uf) < SMALL) .or. & ! LCOV_EXCL_LINE
442 : (abs(lf - fold) < SMALL) .or. & ! LCOV_EXCL_LINE
443 : (abs(lf - fnew) < SMALL) .or. & ! LCOV_EXCL_LINE
444 : (abs(uf - fold) < SMALL) .or. & ! LCOV_EXCL_LINE
445 : (abs(uf - fnew) < SMALL) .or. & ! LCOV_EXCL_LINE
446 : (abs(fold - fnew) < SMALL)) then
447 0 : call setPolIntQuad(rmid, lb, ub, rold, lf, uf, fold, nstep = 3_IK)
448 : else
449 2636 : call setPolIntCubic(rmid, lb, ub, rold, rnew, lf, uf, fold, fnew)
450 : end if
451 : ! Bracket, check termination condition, and update rnew.
452 2636 : neval = neval + 1_IK
453 2636 : call setBracket(getFunc, lb, ub, rmid, lf, uf, rold, fold)
454 2636 : if (niter < neval .or. lf == 0._RKC .or. abs(ub - lb) < abstol) exit blockConvergence
455 : ! Take a double-length secant step.
456 1802 : if (abs(lf) < abs(uf)) then
457 : rupp = lb
458 : fupp = lf
459 : else
460 : rupp = ub
461 : fupp = uf
462 : end if
463 1802 : rmid = rupp - 2 * fupp * (ub - lb) / (uf - lf)
464 1802 : if (abs(rmid - rupp) > .5_RKC * (ub - lb)) rmid = lb + .5_RKC * (ub - lb)
465 : ! Bracket and check termination condition.
466 1802 : rnew = rold
467 1802 : fnew = fold
468 1802 : neval = neval + 1_IK
469 1802 : call setBracket(getFunc, lb, ub, rmid, lf, uf, rold, fold)
470 1802 : if (niter < neval .or. lf == 0._RKC .or. abs(ub - lb) < abstol) exit blockConvergence
471 1508 : if (2 * (ub - lb) < interval) cycle
472 : ! Take an additional bisection step due to slow convergence.
473 0 : rnew = rold
474 0 : fnew = fold
475 0 : neval = neval + 1_IK
476 0 : call setBracket(getFunc, lb, ub, lb + .5_RKC * (ub - lb), lf, uf, rold, fold)
477 2014 : if (niter < neval .or. lf == 0._RKC .or. abs(ub - lb) < abstol) exit blockConvergence
478 : end do loopConvergence
479 : end block blockConvergence
480 2014 : if (niter < neval) neval = -neval
481 2014 : if (abs(lf) < EPS10) ub = lb
482 2014 : if (abs(uf) < EPS10) lb = ub
483 2014 : root = .5_RKC * (ub + lb)
484 : end if
485 :
486 : contains
487 :
488 11986 : subroutine setBracket(getFunc, lb, ub, rmid, lf, uf, rold, fold)
489 : ! Given a point `rmid` inside the existing enclosing interval `[lb, ub]`:
490 : ! 1. set lb = rmid if `getFunc(rmid) == 0`, otherwise,
491 : ! 2. find the new enclosing interval, either `[lb, rmid]` or `[rmid, ub]`,
492 : ! and set `rold` and `fold` to the point that has just been removed from the interval.
493 : ! In other words `rold` is the third best guess to the root.
494 : real(RKC) , parameter :: EPS2 = 2 * epsilon(0._RKC)
495 : real(RKC), intent(inout) :: lb, ub, lf, uf
496 : real(RKC), intent(out) :: rold, fold
497 : procedure(real(RKC)) :: getFunc
498 : real(RKC), value :: rmid
499 : real(RKC) :: fmid
500 : ! Adjust the location of `rmid` accordingly if the `[lb, ub]` is small, or `rmid` is too close to one interval end.
501 11986 : if (ub - lb < 2 * EPS2 * lb) then
502 0 : rmid = lb + .5_RKC * (ub - lb)
503 11986 : elseif (rmid <= lb + abs(lb) * EPS2) then
504 96 : rmid = lb + abs(lb) * EPS2
505 11890 : elseif (ub - abs(ub) * EPS2 <= rmid) then
506 114 : rmid = ub - abs(ub) * EPS2
507 : end if
508 11986 : fmid = getFunc(rmid)
509 11986 : if (fmid == 0._RKC) then
510 1528 : rold = 0._RKC
511 1528 : fold = 0._RKC
512 1528 : lf = 0._RKC
513 1528 : lb = rmid
514 1528 : return
515 : end if
516 : ! Update the interval.
517 10458 : if ((lf < 0._RKC .and. 0._RKC < fmid) .or. (fmid < 0._RKC .and. 0._RKC < lf)) then
518 5246 : rold = ub
519 5246 : fold = uf
520 5246 : ub = rmid
521 5246 : uf = fmid
522 : else
523 5212 : rold = lb
524 5212 : fold = lf
525 5212 : lb = rmid
526 5212 : lf = fmid
527 : end if
528 : end subroutine
529 :
530 : ! Perform quadratic interpolation to determine the next point,
531 : ! by taking `niter - neval` Newton steps to find the location of the quadratic polynomial.
532 : ! `rold`, the third best approximation to the root, after `lb` and `ub`, must lie outside of the interval `[lb, ub]`.
533 : ! Fall back to a secant step should the result be out of range.
534 : ! Start by obtaining the coefficients of the quadratic polynomial.
535 : ! Compute division without undue over/under-flow.
536 2616 : pure subroutine setPolIntQuad(rmid, lb, ub, rold, lf, uf, fold, nstep)
537 : real(RKC), parameter :: HUGE_RKC = huge(0._RKC)
538 : real(RKC), intent(in) :: lb, ub, rold, lf, uf, fold
539 : integer(IK), intent(in) :: nstep
540 : real(RKC), intent(out) :: rmid
541 : integer(IK) :: istep
542 : real(RKC) :: ratio1, ratio2, numer, denom, divres
543 : #define SET_DIV(DIVRES,NUMER,DENOM,OFLOW) \
544 : if (abs(DENOM) < 1._RKC) then; if (abs((DENOM) * HUGE_RKC) <= abs(NUMER)) then; \
545 : DIVRES = OFLOW; else; DIVRES = (NUMER) / (DENOM); end if; else; DIVRES = (NUMER) / (DENOM); end if;
546 2616 : SET_DIV(ratio1,uf - lf,ub - lb,HUGE_RKC)
547 2616 : SET_DIV(ratio2,fold - uf,rold - ub,HUGE_RKC)
548 2616 : SET_DIV(ratio2,ratio2 - ratio1,rold - lb,0._RKC)
549 2616 : if (ratio2 == 0._RKC) then ! Failed to determine coefficients. Try a secant step.
550 : call setPolIntSecant(rmid, lb, ub, lf, uf)
551 2 : return
552 : end if
553 : ! Determine the starting point of the Newton steps.
554 2614 : if ((ratio2 < 0._RKC .and. lf < 0._RKC) .or. (0._RKC < ratio2 .and. 0._RKC < lf)) then
555 1364 : rmid = lb
556 : else
557 1250 : rmid = ub
558 : end if
559 : ! Take the Newton steps.
560 8444 : do istep = 1, nstep
561 5830 : numer = lf + (ratio1 + ratio2 * (rmid - ub)) * (rmid - lb)
562 5830 : denom = ratio1 + ratio2 * (2 * rmid - lb - ub)
563 5830 : SET_DIV(divres,numer,denom,1 + rmid - lb)
564 8444 : rmid = rmid - divres
565 : end do
566 2614 : if (rmid <= lb .or. ub <= rmid) call setPolIntSecant(rmid, lb, ub, lf, uf) ! Failed. Try a secant step.
567 : #undef SET_DIV
568 : end subroutine
569 :
570 : ! Perform standard secant interpolation of `[lb, ub]` given function evaluations `(lf, uf)`.
571 : ! Perform a bisection if secant interpolation is very close to either `lb` or `ub`.
572 : ! This interpolation is needed when at least one other form of interpolation has already failed,
573 : ! implying that the function is unlikely to be smooth with a root near `lb` or `ub`.
574 : pure subroutine setPolIntSecant(rmid, lb, ub, lf, uf)
575 : real(RKC), intent(in) :: lb, ub, lf, uf
576 : real(RKC), intent(out) :: rmid
577 2 : rmid = lb - lf * (ub - lb) / (uf - lf)
578 2 : if (rmid <= lb + abs(lb) * EPS5 .or. ub - abs(ub) * EPS5 <= rmid) rmid = .5_RKC * (lb + ub)
579 : end subroutine
580 :
581 : ! Use inverse cubic interpolation of getFunc(x) at points `[lb, ub, rold, rnew]` to obtain an approximate root of getFunc(x).
582 : ! `rold` and `rnew` lie out of `[lb, ub]` and are the third and forth best approximations to the root that we have found so far.
583 : ! Fall back to quadratic interpolation in case of an erroneous result out of `[lb, ub]`.
584 6156 : pure subroutine setPolIntCubic(rmid, lb, ub, rold, rnew, lf, uf, fold, fnew)
585 : real(RKC), intent(in) :: lb, ub, rold, rnew, lf, uf, fold, fnew
586 : real(RKC), intent(out) :: rmid
587 : real(RKC) :: q11, q21, q31, d21, d31, q22, q32, d32, q33
588 6156 : q11 = (rold - rnew) * fold / (fnew - fold)
589 6156 : q21 = (ub - rold) * uf / (fold - uf)
590 6156 : q31 = (lb - ub) * lf / (uf - lf)
591 6156 : d21 = (ub - rold) * fold / (fold - uf)
592 6156 : d31 = (lb - ub) * uf / (uf - lf)
593 :
594 6156 : q22 = (d21 - q11) * uf / (fnew - uf)
595 6156 : q32 = (d31 - q21) * lf / (fold - lf)
596 6156 : d32 = (d31 - q21) * fold / (fold - lf)
597 6156 : q33 = (d32 - q22) * lf / (fnew - lf)
598 6156 : rmid = q31 + q32 + q33 + lb
599 6156 : if (rmid <= lb .or. ub <= rmid) call setPolIntQuad(rmid, lb, ub, rold, lf, uf, fold, nstep = 3_IK) ! Out of bounds step. Us quadratic interpolation.
600 6156 : end subroutine
601 :
602 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603 : #elif setRoot_ENABLED && Newton_ENABLED
604 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
605 :
606 : integer(IK) :: iter
607 : real(RKC) :: func, grad, interval, func2grad, temp
608 7206 : neval = 0_IK
609 7206 : if (abs(lf) <= EPS10) then
610 2000 : root = lb
611 5206 : elseif (abs(uf) <= EPS10) then
612 1722 : root = ub
613 3484 : elseif (abs(ub - lb) < abstol) then
614 0 : root = .5_RKC * (ub + lb)
615 : else
616 10452 : CHECK_BRACKET
617 10452 : CHECK_LB_LT_UB
618 1739 : CHECK_ZERO_LT_NITER
619 3484 : CHECK_ZERO_LT_ABSTOL
620 17420 : CHECK_LF(getFunc(lb, 0_IK))
621 17420 : CHECK_UF(getFunc(ub, 0_IK))
622 13936 : CHECK_ABSTOL_LT_LB_UB_DIFF
623 3484 : if (root <= lb .or. ub <= root) root = .5_RKC * (lb + ub)
624 3484 : if (0._RKC <= lf) then
625 1464 : root = lb
626 1464 : lb = ub
627 1464 : ub = root
628 : end if
629 3484 : interval = abs(ub - lb)
630 : func2grad = interval
631 3484 : neval = neval + 1_IK
632 3484 : func = getFunc(root, 0_IK)
633 19016 : do iter = 1, niter
634 19016 : neval = neval + 1_IK
635 19016 : grad = getFunc(root, 1_IK)
636 19016 : if (0._RKC < ((root - ub) * grad - func) * ((root - lb) * grad - func) .or. abs(interval * grad) < abs(2._RKC * func)) then
637 : interval = func2grad
638 172 : func2grad = .5_RKC * (ub - lb)
639 172 : root = lb + func2grad
640 172 : if (lb == root) return
641 : else
642 : interval = func2grad
643 18844 : func2grad = func / grad
644 : temp = root
645 18844 : root = root - func2grad
646 18844 : if (temp == root) return
647 : end if
648 16680 : if (abs(func2grad) < abstol) return
649 15532 : neval = neval + 1_IK
650 15532 : func = getFunc(root, 0_IK)
651 15532 : if (func < 0._RKC) then
652 245 : lb = root
653 : else
654 15287 : ub = root
655 : end if
656 : end do
657 : ! Error occurred.
658 0 : root = .5_RKC * (lb + ub) ! for the sake of defining `root` on output (important for tests).
659 0 : neval = -neval
660 : end if
661 :
662 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663 : #elif setRoot_ENABLED && (Halley_ENABLED || Schroder_ENABLED)
664 : !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 :
666 : logical(LK) :: out_of_bounds_sentry, varset
667 : real(RKC) :: func, grad, hess, rold, fold, fmax, fmin, delta, delta1, delta2, temp, diff, ratio
668 14412 : neval = 0_IK
669 14412 : if (abs(lf) <= EPS10) then
670 3496 : root = lb
671 10916 : elseif (abs(uf) <= EPS10) then
672 3738 : root = ub
673 7178 : elseif (abs(ub - lb) < abstol) then
674 0 : root = .5_RKC * (ub + lb)
675 : else
676 21534 : CHECK_BRACKET
677 21534 : CHECK_LB_LT_UB
678 3583 : CHECK_ZERO_LT_NITER
679 7178 : CHECK_ZERO_LT_ABSTOL
680 35890 : CHECK_LF(getFunc(lb, 0_IK))
681 35890 : CHECK_UF(getFunc(ub, 0_IK))
682 28712 : CHECK_ABSTOL_LT_LB_UB_DIFF
683 : !print *, "lb, root, ub", lb, root, ub
684 7178 : if (root <= lb .or. ub <= root) root = .5_RKC * (lb + ub)
685 : out_of_bounds_sentry = .false._LK
686 7178 : delta = huge(delta)
687 : fmax = 0._RKC
688 : fmin = 0._RKC
689 7178 : rold = root
690 7178 : func = 0._RKC
691 : delta1 = delta
692 : delta2 = delta
693 7178 : neval = 0_IK
694 : do
695 26752 : fold = func
696 : delta2 = delta1
697 26752 : delta1 = delta
698 26752 : neval = neval + 3_IK
699 26752 : if (niter < neval) exit
700 26752 : func = getFunc(root, 0_IK)
701 26752 : grad = getFunc(root, 1_IK)
702 26752 : hess = getFunc(root, 2_IK)
703 29006 : if (func == 0._RKC) return
704 21828 : if (grad == 0._RKC) then ! Handle zero derivative and hessian.
705 0 : if (fold == 0._RKC) then
706 : ! First iteration: pretend that we had a previous one at either `lb` or `ub`.
707 0 : if (root == lb) then
708 0 : rold = ub
709 : else
710 0 : rold = lb
711 : end if
712 0 : neval = neval + 1_IK
713 0 : if (niter < neval) exit
714 0 : fold = getFunc(rold, 0_IK)
715 0 : delta = rold - root
716 : end if
717 0 : if ((fold < 0._RKC .and. 0._RKC < func) .or. (func < 0._RKC .and. 0._RKC < fold)) then
718 : ! Crossed over. Move in opposite direction to last step.
719 0 : if (delta < 0._RKC) then
720 0 : delta = .5_RKC * (root - lb)
721 : else
722 0 : delta = .5_RKC * (root - ub)
723 : end if
724 : else ! Move in same direction as last step.
725 0 : if (delta < 0._RKC) then
726 0 : delta = .5_RKC * (root - ub)
727 : else
728 0 : delta = .5_RKC * (root - lb)
729 : end if
730 : end if
731 21828 : elseif (hess /= 0._RKC) then
732 : #if Halley_ENABLED || Schroder_ENABLED
733 21828 : ratio = 2 * func
734 21828 : temp = 2 * grad - func * (hess / grad)
735 21828 : varset = abs(temp) < 1._RKC
736 21828 : if (varset) then
737 0 : varset = abs(temp) * huge(temp) <= abs(ratio)
738 0 : if (varset) delta = func / grad ! Possible overflow, use Newton step.
739 : end if
740 21828 : if (.not. varset) delta = ratio / temp ! Use Halley step.
741 : #elif Schroder_ENABLED
742 : ! The Schroder stepper appears unstable for certain class of test problems where the Halley method does.
743 : ! For now, Schroder is switched to Halley, but the origins of this instability must be explored.
744 : ratio = func / grad
745 : varset = root /= 0._RKC
746 : if (varset) then
747 : varset = abs(ratio / root) < 0.1_RKC
748 : if (varset) then
749 : delta = ratio + (hess / (2 * grad)) * ratio**2
750 : ! Fall back to Newton iteration if hess contribution is larger than grad.
751 : varset = 0._RKC <= delta * ratio
752 : end if
753 : end if
754 : ! Fall back to Newton iteration.
755 : if (.not. varset) delta = ratio
756 : #else
757 : #error "Unrecognized interface."
758 : #endif
759 21828 : if (delta * grad / func < 0._RKC) then
760 : ! The Newton and Halley steps disagree about which way we should move,
761 : ! likely due to cancelation error in the calculation of the Halley step,
762 : ! or else the derivatives are so small that their values are basically trash.
763 : ! Move in the direction indicated by a Newton step, but by no more than twice the
764 : ! current rold value, otherwise the search can jump out of bounds.
765 0 : delta = func / grad
766 0 : if (2 * abs(rold) < abs(delta)) delta = sign(2._RKC, delta) * abs(rold)
767 : end if
768 : else
769 0 : delta = func / grad
770 : end if
771 21828 : temp = abs(delta / delta2)
772 21828 : if (0.8_RKC < temp .and. temp < 2._RKC) then
773 : ! The last two steps did not converge.
774 92 : if (0._RKC < delta) then
775 42 : delta = .5_RKC * (root - lb)
776 : else
777 50 : delta = .5_RKC * (root - ub)
778 : end if
779 92 : if (root /= 0._RKC .and. root < abs(delta)) delta = sign(.9_RKC, delta) * abs(root) ! protect against huge jumps.
780 : ! reset delta2 so that this branch will *not* be taken on the next iteration.
781 92 : delta1 = delta * 3._RKC
782 : delta2 = delta1
783 : end if
784 21828 : rold = root
785 21828 : root = root - delta
786 : ! Check for out of bounds step.
787 21828 : if (root < lb) then
788 22 : varset = abs(lb) < 1._RKC .and. 1._RKC < abs(root)
789 : if (varset) then
790 0 : varset = huge(root) / abs(root) < abs(lb)
791 0 : if (varset) diff = 1000._RKC
792 : end if
793 22 : if (.not. varset) then
794 22 : varset = abs(lb) < 1._RKC
795 22 : if (varset) then
796 0 : varset = huge(lb) * abs(lb) < abs(root)
797 0 : if (varset) then
798 0 : if (lb < 0._RKC .neqv. root < 0._RKC) then
799 : diff = -huge(diff)
800 : else
801 : diff = +huge(diff)
802 : end if
803 : end if
804 : end if
805 22 : if (.not. varset) diff = root / lb
806 : end if
807 22 : if (abs(diff) < 1._RKC) diff = 1 / diff
808 22 : if (0._RKC < diff .and. diff < 3._RKC .and. .not. out_of_bounds_sentry) then
809 : ! Only a small out of bounds step, lets assume that the root is probably approximately at `lb`.
810 : out_of_bounds_sentry = .true. ! only take this branch once!
811 22 : delta = 0.99_RKC * (rold - lb)
812 22 : root = rold - delta
813 : else
814 0 : root = .5_RKC * (lb + ub)
815 0 : if (abs(lb - ub) < 2 * spacing(root)) return
816 0 : call setBracketTowardMin(delta, getFunc, rold, func, lb, ub, neval, niter)
817 0 : if (niter < neval) exit
818 0 : root = rold - delta
819 0 : rold = lb
820 0 : cycle
821 : end if
822 21806 : elseif (ub < root) then
823 4 : varset = abs(ub) < 1._RKC .and. 1._RKC < abs(root)
824 : if (varset) then
825 0 : varset = huge(root) / abs(root) < abs(ub)
826 0 : if (varset) diff = 1000._RKC
827 : end if
828 4 : if (.not. varset) diff = root / ub
829 4 : if (abs(diff) < 1._RKC) diff = 1._RKC / diff
830 4 : if (0._RKC < diff .and. diff < 3._RKC .and. .not. out_of_bounds_sentry) then
831 : ! Only a small out of bounds step, assume that the root is approximately at `lb`.
832 : out_of_bounds_sentry = .true. ! Take this branch only once.
833 0 : delta = 0.99_RKC * (rold - ub)
834 0 : root = rold - delta
835 : else
836 4 : root = .5_RKC * (lb + ub)
837 4 : if (abs(lb - ub) < 2 * spacing(root)) return
838 4 : call setBracketTowardMax(delta, getFunc, rold, func, lb, ub, neval, niter)
839 4 : if (niter < neval) exit
840 4 : root = rold - delta
841 4 : rold = lb
842 4 : cycle
843 : end if
844 : end if
845 : ! update brackets:
846 21824 : if (0._RKC < delta) then
847 10755 : ub = rold
848 : fmax = func
849 : else
850 11069 : lb = rold
851 : fmin = func
852 : end if
853 : ! Sanity check that we bracket the rold:
854 21824 : if (0._RKC < fmax * fmin) exit ! no root, possibly a minimum around root.
855 21824 : if (abs(delta) < abs(root * abstol)) return
856 : end do
857 : ! Error occurred.
858 0 : root = .5_RKC * (lb + ub) ! for the sake of defining `root` on output (important for tests).
859 0 : neval = -neval
860 : end if
861 :
862 : contains
863 :
864 4 : subroutine setBracketTowardMax(delta, getFunc, rold, func, lb, ub, neval, niter)
865 : ! Move rold towards ub until we bracket the root, updating `lb` and `ub` on the fly.
866 : real(RKC), intent(inout) :: rold, lb, ub
867 : integer(IK), intent(inout) :: neval
868 : integer(IK), intent(in) :: niter
869 : real(RKC), intent(out) :: delta
870 : procedure(real(RKC)) :: getFunc
871 : real(RKC), intent(in) :: func
872 : real(RKC) :: guess0, funcurrent
873 : integer(IK) :: multiplier
874 : multiplier = 2_IK
875 4 : funcurrent = func
876 4 : guess0 = rold
877 4 : if (abs(lb) < abs(ub)) then
878 0 : loopSearch1: do
879 0 : if (funcurrent < 0._RKC .neqv. func < 0._RKC) exit loopSearch1
880 0 : lb = rold
881 0 : rold = rold * multiplier
882 0 : if (ub < rold) then
883 0 : rold = ub
884 0 : funcurrent = -funcurrent ! There must be a change of sign.
885 0 : exit loopSearch1
886 : end if
887 0 : neval = neval + 1_IK
888 0 : if (niter < neval) return
889 0 : funcurrent = getFunc(rold, 0_IK)
890 0 : multiplier = multiplier * 2_IK
891 : end do loopSearch1
892 : else ! If `lb` and `ub` are negative, divide to head towards `ub`.
893 3 : loopSearch2: do
894 7 : if (funcurrent < 0._RKC .neqv. func < 0._RKC) exit loopSearch2
895 4 : lb = rold
896 4 : rold = rold / multiplier
897 4 : if (ub < rold) then
898 1 : rold = ub
899 1 : funcurrent = -funcurrent ! There must be a change of sign.
900 1 : exit loopSearch2
901 : end if
902 3 : neval = neval + 1_IK
903 3 : if (niter < neval) return
904 3 : funcurrent = getFunc(rold, 0_IK)
905 6 : multiplier = multiplier * 2_IK
906 : end do loopSearch2
907 : end if
908 4 : if (neval < niter) then
909 4 : ub = rold
910 4 : if (16_IK < multiplier) then
911 0 : call setBracketTowardMin(delta, getFunc, rold, funcurrent, lb, ub, neval, niter)
912 0 : delta = delta + (guess0 - rold)
913 0 : return
914 : end if
915 : end if
916 4 : delta = guess0 - .5_RKC * (lb + ub)
917 : end subroutine
918 :
919 0 : subroutine setBracketTowardMin(delta, getFunc, rold, func, lb, ub, neval, niter)
920 : ! Move rold towards lb until we bracket the root, updating `lb` and `ub` on the fly.
921 : real(RKC), intent(inout) :: rold, lb, ub
922 : integer(IK), intent(inout) :: neval
923 : integer(IK), intent(in) :: niter
924 : real(RKC), intent(out) :: delta
925 : procedure(real(RKC)) :: getFunc
926 : real(RKC), intent(in) :: func
927 : real(RKC) :: guess0, funcurrent
928 : integer(IK) :: multiplier
929 : multiplier = 2_IK
930 0 : funcurrent = func
931 0 : guess0 = rold
932 0 : if (abs(lb) < abs(ub)) then
933 0 : loopSearch1: do
934 0 : if (funcurrent < 0._RKC .neqv. func < 0._RKC) exit loopSearch1
935 0 : ub = rold
936 0 : rold = rold / multiplier
937 0 : if (rold < lb) then
938 0 : rold = lb
939 0 : funcurrent = -funcurrent ! There must be a change of sign.
940 0 : exit loopSearch1
941 : end if
942 0 : neval = neval + 1_IK
943 0 : if (niter < neval) return
944 0 : funcurrent = getFunc(rold, 0_IK)
945 0 : multiplier = multiplier * 2_IK
946 : end do loopSearch1
947 : else ! If `lb` and `ub` are negative, multiply to head towards `lb`.
948 0 : loopSearch2: do
949 0 : if (funcurrent < 0._RKC .neqv. func < 0._RKC) exit loopSearch2
950 0 : ub = rold
951 0 : rold = rold * multiplier
952 0 : if (rold < lb) then
953 0 : rold = lb
954 0 : funcurrent = -funcurrent ! There must be a change of sign.
955 0 : exit loopSearch2
956 : end if
957 0 : neval = neval + 1_IK
958 0 : if (niter < neval) return
959 0 : funcurrent = getFunc(rold, 0_IK)
960 0 : multiplier = multiplier * 2_IK
961 : end do loopSearch2
962 : end if
963 0 : if (neval < niter) then
964 0 : lb = rold
965 0 : if (16_IK < multiplier) then
966 0 : call setBracketTowardMax(delta, getFunc, rold, funcurrent, lb, ub, neval, niter)
967 0 : delta = delta + (guess0 - rold)
968 0 : return
969 : end if
970 : end if
971 0 : delta = guess0 - .5_RKC * (lb + ub)
972 : end subroutine
973 :
974 : #else
975 : !%%%%%%%%%%%%%%%%%%%%%%%%
976 : #error "Unrecognized interface."
977 : !%%%%%%%%%%%%%%%%%%%%%%%%
978 : #endif
979 : #undef CHECK_ABSTOL_LT_LB_UB_DIFF
980 : #undef CHECK_ZERO_LT_ABSTOL
981 : #undef CHECK_ZERO_LT_NITER
982 : #undef CHECK_LB_LT_UB
983 : #undef CHECK_BRACKET
984 : #undef CHECK_LF
985 : #undef CHECK_UF
|