# Golden-section search

Diagram of a golden-section search

The golden-section search is a technique for finding the extremum (minimum or maximum) of a strictly unimodal function by successively narrowing the range of values inside which the extremum is known to exist. The technique derives its name from the fact that the algorithm maintains the function values for triples of points whose distances form a golden ratio. The algorithm is the limit of Fibonacci search (also described below) for a large number of function evaluations. Fibonacci search and golden-section search were discovered by Kiefer (1953) (see also Avriel and Wilde (1966)).

## Basic idea

The discussion here is posed in terms of searching for a minimum (searching for a maximum is similar) of a unimodal function. Unlike finding a zero, where two function evaluations with opposite sign are sufficient to bracket a root, when searching for a minimum, three values are necessary. The golden-section search is an efficient way to progressively reduce the interval locating the minimum. The key is to observe that regardless of how many points have been evaluated, the minimum lies within the interval defined by the two points adjacent to the point with the least value so far evaluated.

The diagram above illustrates a single step in the technique for finding a minimum. The functional values of ${\displaystyle f(x)}$ are on the vertical axis, and the horizontal axis is the x parameter. The value of ${\displaystyle f(x)}$ has already been evaluated at the three points: ${\displaystyle x_{1}}$, ${\displaystyle x_{2}}$, and ${\displaystyle x_{3}}$. Since ${\displaystyle f_{2}}$ is smaller than either ${\displaystyle f_{1}}$ or ${\displaystyle f_{3}}$, it is clear that a minimum lies inside the interval from ${\displaystyle x_{1}}$ to ${\displaystyle x_{3}}$.

The next step in the minimization process is to "probe" the function by evaluating it at a new value of x, namely ${\displaystyle x_{4}}$. It is most efficient to choose ${\displaystyle x_{4}}$ somewhere inside the largest interval, i.e. between ${\displaystyle x_{2}}$ and ${\displaystyle x_{3}}$. From the diagram, it is clear that if the function yields ${\displaystyle f_{4a}}$, then a minimum lies between ${\displaystyle x_{1}}$ and ${\displaystyle x_{4}}$, and the new triplet of points will be ${\displaystyle x_{1}}$, ${\displaystyle x_{2}}$, and ${\displaystyle x_{4}}$. However, if the function yields the value ${\displaystyle f_{4b}}$, then a minimum lies between ${\displaystyle x_{2}}$ and ${\displaystyle x_{3}}$, and the new triplet of points will be ${\displaystyle x_{2}}$, ${\displaystyle x_{4}}$, and ${\displaystyle x_{3}}$. Thus, in either case, we can construct a new narrower search interval that is guaranteed to contain the function's minimum.

## Probe point selection

From the diagram above, it is seen that the new search interval will be either between ${\displaystyle x_{1}}$ and ${\displaystyle x_{4}}$ with a length of a + c, or between ${\displaystyle x_{2}}$ and ${\displaystyle x_{3}}$ with a length of b. The golden-section search requires that these intervals be equal. If they are not, a run of "bad luck" could lead to the wider interval being used many times, thus slowing down the rate of convergence. To ensure that b = a + c, the algorithm should choose ${\displaystyle x_{4}=x_{1}+(x_{3}-x_{2})}$.

However, there still remains the question of where ${\displaystyle x_{2}}$ should be placed in relation to ${\displaystyle x_{1}}$ and ${\displaystyle x_{3}}$. The golden-section search chooses the spacing between these points in such a way that these points have the same proportion of spacing as the subsequent triple ${\displaystyle x_{1},x_{2},x_{4}}$ or ${\displaystyle x_{2},x_{4},x_{3}}$. By maintaining the same proportion of spacing throughout the algorithm, we avoid a situation in which ${\displaystyle x_{2}}$ is very close to ${\displaystyle x_{1}}$ or ${\displaystyle x_{3}}$ and guarantee that the interval width shrinks by the same constant proportion in each step.

Mathematically, to ensure that the spacing after evaluating ${\displaystyle f(x_{4})}$ is proportional to the spacing prior to that evaluation, if ${\displaystyle f(x_{4})}$ is ${\displaystyle f_{4a}}$ and our new triplet of points is ${\displaystyle x_{1}}$, ${\displaystyle x_{2}}$, and ${\displaystyle x_{4}}$, then we want

${\displaystyle {\frac {c}{a}}={\frac {a}{b}}.}$

However, if ${\displaystyle f(x_{4})}$ is ${\displaystyle f_{4b}}$ and our new triplet of points is ${\displaystyle x_{2}}$, ${\displaystyle x_{4}}$, and ${\displaystyle x_{3}}$, then we want

${\displaystyle {\frac {c}{b-c}}={\frac {a}{b}}.}$

Eliminating c from these two simultaneous equations yields

${\displaystyle \left({\frac {b}{a}}\right)^{2}-{\frac {b}{a}}=1,}$

or

${\displaystyle {\frac {b}{a}}=\varphi ,}$

where φ is the golden ratio:

${\displaystyle \varphi ={\frac {1+{\sqrt {5}}}{2}}=1.618033988\ldots }$

The appearance of the golden ratio in the proportional spacing of the evaluation points is how this search algorithm gets its name.

## Termination condition

Because smooth functions are flat (their first derivative is close to zero) near a minimum, attention must be paid not to expect too great an accuracy in locating the minimum. The termination condition provided in the book Numerical Recipes in C is based on testing the gaps among ${\displaystyle x_{1}}$, ${\displaystyle x_{2}}$, ${\displaystyle x_{3}}$ and ${\displaystyle x_{4}}$, terminating when within the relative accuracy bounds

${\displaystyle |x_{3}-x_{1}|<\tau (|x_{2}|+|x_{4}|),}$

where ${\displaystyle \tau }$ is a tolerance parameter of the algorithm, and ${\displaystyle |x|}$ is the absolute value of ${\displaystyle x}$. The check is based on the bracket size relative to its central value, because that relative error in ${\displaystyle x}$ is approximately proportional to the squared absolute error in ${\displaystyle f(x)}$ in typical cases. For that same reason, the Numerical Recipes text recommends that ${\displaystyle \tau ={\sqrt {\varepsilon }}}$, where ${\displaystyle \varepsilon }$ is the required absolute precision of ${\displaystyle f(x)}$.

## Algorithm

### Iterative algorithm

• Let [a, b] be interval of current bracket. f(a), f(b) would already have been computed earlier. ${\displaystyle \varphi =(1+{\sqrt {5}})/2}$.
• Let c = b - (ba)/φ , d = a + (ba)/φ. If f(c), f(d) not available, compute them.
• If f(c) < f(d) (this is to find min, to find max, just reverse it) then move the data: (b, f(b)) ← (d, f(d)), (d, f(d)) ← (c, f(c)) and update c = b - (b - a)/φ and f(c);
• otherwise, move the data: (a, f(a)) ← (c, f(c)), (c, f(c)) ← (d, f(d)) and update d = a + (ba)/φ and f(d).
• At the end of the iteration, [a, c, d, b] bracket the minimum point.
'''python program for golden section search.  This implementation
does not reuse function evaluations.'''
gr = (math.sqrt(5) + 1) / 2

def gss(f, a, b, tol=1e-5):
'''
golden section search
to find the minimum of f on [a,b]
f: a strictly unimodal function on [a,b]

example:
>>> f = lambda x: (x-2)**2
>>> x = gss(f, 1, 5)
>>> x
2.000009644875678

'''
c = b - (b - a) / gr
d = a + (b - a) / gr
while abs(c - d) > tol:
if f(c) < f(d):
b = d
else:
a = c

# we recompute both c and d here to avoid loss of precision which may lead to incorrect results or infinite loop
c = b - (b - a) / gr
d = a + (b - a) / gr

return (b + a) / 2

'''Python program for golden section search.  This implementation
reuses function evaluations, saving 1/2 of the evaluations per
iteration, and returns a bounding interval.'''

invphi = (math.sqrt(5) - 1) / 2 # 1/phi
invphi2 = (3 - math.sqrt(5)) / 2 # 1/phi^2

def gss(f,a,b,tol=1e-5):
'''
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)))

c = a + invphi2 * h
d = a + invphi * h
yc = f(c)
yd = f(d)

for k in xrange(n-1):
if yc < yd:
b = d
d = c
yd = yc
h = invphi*h
c = a + invphi2 * h
yc = f(c)
else:
a = c
c = d
yc = yd
h = invphi*h
d = a + invphi * h
yd = f(d)

if yc < yd:
return (a,d)
else:
return (c,b)


### Recursive algorithm

public class GoldenSectionSearch {
public static final double invphi = (Math.sqrt(5.0)-1)/2.0;
public static final double invphi2 = (3-Math.sqrt(5.0))/2.0;

public interface Function {
double of(double x);
}

// returns subinterval of [a,b] containing minimum of f
public static double[] gss(Function f, double a, double b, double tol) {
return gss(f,a,b,tol,b-a,true,0,0,true,0,0);
}
private static double[] gss(Function f, double a, double b, double tol,
double h, boolean noC, double c, double fc,
boolean noD, double d, double fd) {
if (Math.abs(h) <= tol) {
return new double[] { a, b };
}
if (noC) {
c = a + invphi2*h;
fc = f.of(c);
}
if (noD) {
d = a + invphi*h;
fd = f.of(d);
}
if (fc < fd) {
return gss(f,a,d,tol,h*invphi,true,0,0,false,c,fc);
} else {
return gss(f,c,b,tol,h*invphi,false,d,fd,true,0,0);
}
}

public static void main(String[] args) {
Function f = (x)->Math.pow(x-2,2);
double a = 1;
double b = 5;
double tol = 1e-5;
double [] ans = gss(f,a,b,tol);
System.out.println("[" + ans[0] + "," + ans[1] + "]");
// [1.9999959837979107,2.0000050911830893]
}
}

invphi = (math.sqrt(5) - 1) / 2 # 1/phi
invphi2 = (3 - math.sqrt(5)) / 2 # 1/phi^2

def gssrec(f,a,b,tol=1e-5,h=None,c=None,d=None,fc=None,fd=None):
'''
Golden section search, recursive.

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) = gssrec(f, a, b, tol)
>>> print (c,d)
(1.9999959837979107, 2.0000050911830893)
'''

(a,b)=(min(a,b),max(a,b))
if h == None: h=b-a
if h <= tol: return (a,b)
if c == None: c = a + invphi2*h
if d == None: d = a + invphi*h
if fc == None: fc = f(c)
if fd == None: fd = f(d)
if fc < fd:
return gssrec(f,a,d,tol,h*invphi,c=None,fc=None,d=c,fd=fc)
else:
return gssrec(f,c,b,tol,h*invphi,c=d,fc=fd,d=None,fd=None)


## Fibonacci search

A very similar algorithm can also be used to find the extremum (minimum or maximum) of a sequence of values that has a single local minimum or local maximum. In order to approximate the probe positions of golden section search while probing only integer sequence indices, the variant of the algorithm for this case typically maintains a bracketing of the solution in which the length of the bracketed interval is a Fibonacci number. For this reason, the sequence variant of golden section search is often called Fibonacci search.

Fibonacci search was first devised by Kiefer (1953) as a minimax search for the maximum (minimum) of a unimodal function in an interval.