"""Python program for golden section search (straight-up copied from Wikipedia). This implementation reuses function evaluations, saving 1/2 of the evaluations per iteration, and returns a bounding interval.""" import logging import math logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) invphi = (math.sqrt(5) - 1) / 2 # 1 / phi invphi2 = (3 - math.sqrt(5)) / 2 # 1 / phi^2 def gss(f, a, b, tol=1e-4): """Golden-section search. Given a function f with a single local minimum in the interval [a,b], gss returns a subset interval [c,d] that contains the minimum with d-c <= tol. Example: >>> f = lambda x: (x-2)**2 >>> a = 1 >>> b = 5 >>> tol = 1e-5 >>> (c,d) = gss(f, a, b, tol) >>> print(c, d) 1.9999959837979107 2.0000050911830893 """ (a, b) = (min(a, b), max(a, b)) h = b - a if h <= tol: return a, b # Required steps to achieve tolerance n = int(math.ceil(math.log(tol / h) / math.log(invphi))) logger.info( "About to perform %d iterations of golden section search to find the best framerate", n, ) def f_wrapped(x, is_last_iter): try: return f(x, is_last_iter) except TypeError: return f(x) c = a + invphi2 * h d = a + invphi * h yc = f_wrapped(c, n == 1) yd = f_wrapped(d, n == 1) for k in range(n - 1): if yc < yd: b = d d = c yd = yc h = invphi * h c = a + invphi2 * h yc = f_wrapped(c, k == n - 2) else: a = c c = d yc = yd h = invphi * h d = a + invphi * h yd = f(d, k == n - 2) if yc < yd: return a, d else: return c, b