(defn bracket-min
"Generates an interval `[lo, hi]` that is guaranteed to contain a minimum of the
function `f`, along with a candidate point `[mid, (f mid)]` that the user can
use to start a minimum search.
Returns a dictionary of the form:
{:lo `lower end of the bracket`
:mid `candidate point`
:hi `upper end of the bracket`
:fncalls `# of fn evaluations so far`
:iterations `total iterations`}
`:lo`, `:mid` and `:hi` are each pairs of the form `[x, (f x)]`.
The implementation works by growing the bounds using either:
- a step outside the bounds that places one bound at the golden-ratio cut
point between the new bounds, or
- a parabola with a minimum interpolated outside the current bounds, bounded b
a max.
This implementation was ported from `scipy.optimize.optimize.bracket`:
https://github.com/scipy/scipy/blob/v1.5.2/scipy/optimize/optimize.py#L2450
`bracket-min` supports the following optional keyword arguments:
`:xa` the initial guess for the lower end of the bracket. Defaults to 0.0.
`:xb` the initial guess for the upper end of the bracket. Defaults to 1.0. (If
these points aren't supplied in sorted order they'll be switched.)
`:grow-limit` The maximum factor that the parabolic interpolation can jump the
function. Defaults to 110.0.
`:maxiter` Maximum number of iterations allowed for the minimizer. Defaults to
1000.
`:maxfun` Maximum number of times the function can be evaluated before exiting.
Defaults to 1000.
"
([f] (bracket-min f {}))
([f {:keys [xa xb maxiter maxfun]
:or {xa 0.0
xb 1.0
maxiter 1000
maxfun 1000}
:as opts}]
(let [[f-counter f] (u/counted f)
step (bracket-step-fn f opts)
stop-fn (fn [_ [_ fb] [_ fc] iteration]
(or (> iteration maxiter)
(> @f-counter maxfun)
(<= fb fc)))
complete (fn [[xa :as a] b [xc :as c] iterations]
(let [m {:lo a
:mid b
:hi c
:fncalls @f-counter
:iterations iterations}]
(if (< xc xa)
(assoc m :lo c :hi a)
m)))
[[xb :as b] [xa :as a]] (ascending-by f xa xb)
xc (ug/extend-pt xb xa)
fc (f xc)]
(loop [[a b c] [a b [xc fc]]
iteration 0]
(if (stop-fn a b c iteration)
(complete a b c iteration)
(recur (step a b c)
(inc iteration)))))))