Nelder-Mead Method¶
Copyright (C) 2022 François Chollet, derived from this code
Copyright (C) 2022 Andreas Kloeckner
Licensed under the GNU General Public License Version 2
Resources:
- Nelder-Mead method (Wikipedia)
In [111]:
import numpy as np
import matplotlib.pyplot as plt
import copy
This is a challenge problem for optimization algorithms known as Rosenbrock's banana function.
In [112]:
def f(X):
x = X[0]
y = X[1]
val = 100.0 * (y - x**2)**2 + (1.0 - x)**2
return val
In [113]:
fig = plt.figure(figsize=(6, 6))
xmesh, ymesh = np.mgrid[-2:2:50j,-2:2:50j]
fmesh = f(np.array([xmesh, ymesh]))
plt.axis("equal")
plt.contour(xmesh, ymesh, fmesh, 150)
Out[113]:
<matplotlib.contour.QuadContourSet at 0x7f702f0b8b80>
Set the starting guess:
In [114]:
x_start = np.array([2, 2./5])
Set some parameters:
In [115]:
step = 0.1
alpha = 1.
gamma = 2.
rho = -0.5
sigma = 0.5
Some initialization:
In [116]:
dim = len(x_start)
prev_best = f(x_start)
no_improv = 0
res = [[x_start, prev_best]]
for i in range(dim):
x = copy.copy(x_start)
x[i] = x[i] + step
score = f(x)
res.append([x, score])
And the iteration:
In [117]:
def iteration(res):
res = res[:]
# order
res.sort(key=lambda x: x[1])
best = res[0][1]
# centroid
x0 = [0.] * dim
for tup in res[:-1]:
for i, c in enumerate(tup[0]):
x0[i] += c / (len(res)-1)
# reflection
xr = x0 + alpha*(x0 - res[-1][0])
rscore = f(xr)
if res[0][1] <= rscore < res[-2][1]:
del res[-1]
res.append([xr, rscore])
return res
# expansion
if rscore < res[0][1]:
xe = x0 + gamma*(x0 - res[-1][0])
escore = f(xe)
if escore < rscore:
del res[-1]
res.append([xe, escore])
return res
else:
del res[-1]
res.append([xr, rscore])
return res
# contraction
xc = x0 + rho*(x0 - res[-1][0])
cscore = f(xc)
if cscore < res[-1][1]:
del res[-1]
res.append([xc, cscore])
return res
# reduction
x1 = res[0][0]
nres = []
for tup in res:
redx = x1 + sigma*(tup[0] - x1)
score = f(redx)
nres.append([redx, score])
return nres
In [120]:
res = iteration(res)
fig = plt.figure(figsize=(9, 9))
xmesh, ymesh = np.mgrid[-2:2:50j,-2:2:50j]
fmesh = f(np.array([xmesh, ymesh]))
plt.axis("equal")
plt.contour(xmesh, ymesh, fmesh, 150)
pts = np.array([pt for pt, val in res]).T
plt.plot(pts[0], pts[1], "ko-")
Out[120]:
[<matplotlib.lines.Line2D at 0x7f702e80e2c0>]
In [ ]: