Bierlaire, M. (2015). Optimization: Principles and Algorithms. EPFL Press.
The numbering of the algorithms, tables and page refer to the book.
import numpy as np
from scipy import linalg
# Define a function simple to call for the inner product
def scalarInner(a,b):
return(np.asscalar(a.T.dot(b)))
import optimizationExceptions
def nelderMead(obj,x0,eps=1.0e-5,maxiter=100):
n,m = x0.shape
x = x0
it = 0
if m != n+1:
raise OptimizationInputError("Incorrect size")
iters=list()
while True:
it = it + 1
f = [obj(x[:,k]) for k in range(m)]
## Worst value
worst = max(f)
worstindex = np.argmax(f)
xworst = x[:,[worstindex]]
## Best value
best = min(f)
bestindex = np.argmin(f)
tmp = f
tmp[worstindex] = -np.inf
secondworst = max(tmp)
secondworstindex = np.argmax(tmp)
xc = (np.sum(x,axis=1,keepdims=True) - xworst) / n
d = xc - x[:,[worstindex]]
xr = 2 * xc - xworst
fxr = obj(xr)
if fxr < best:
xe = 2 * xr - xc
fxe = obj(xe)
if fxe < fxr:
xnew = xe
else:
xnew = xr
elif secondworst > fxr:
xnew = xr
elif fxr >= worst:
xnew = 0.5 * (xworst + xc)
else:
xnew = 0.5 * (xr + xc)
fxnew = obj(xnew)
iters.append([x.copy(),xworst.copy(),xnew.copy(),xr])
x[:,[worstindex]] = xnew
if linalg.norm(d) < eps or it >= maxiter:
break
return x[:,bestindex],iters
Example 15.2, page 350
def f(x):
f = 0.5 * x.item(0) * x.item(0) + 4.5 * x.item(1) * x.item(1)
return f
x0 = np.array([[1, 2 , 1.1],[ 1, 1.1, 2]])
x0
(sol,iters) = nelderMead(f,x0)
sol
Table 15.1, page 352
for k in range(len(iters)):
print("{}\t{:+E}\t{:+E}\t{:+E}\t{:+E}\t{:+E}".format(k+1,iters[k][0][0,0],iters[k][0][0,1],iters[k][0][0,2],iters[k][3].item(0),iters[k][2].item(0)))
print("\t{:+E}\t{:+E}\t{:+E}\t{:+E}\t{:+E}".format(iters[k][0][1,0],iters[k][0][1,1],iters[k][0][1,2],iters[k][3].item(1),iters[k][2].item(1)))
print("_________________________________________________________________________________________")
print("\t{:+E}\t{:+E}\t{:+E}\t{:+E}\t{:+E}".format(f(iters[k][0][:,0]),f(iters[k][0][:,1]),f(iters[k][0][:,2]),f(iters[k][3]),f(iters[k][2])))
print("_________________________________________________________________________________________")
Figure 15.2 (a), page 350
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
return 0.5 * x * x + 4.5 * y * y
xmin = -0.1
xmax = 2.1
ymin = -0.1
ymax = 2.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
iter = 0
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
xarrow = [iters[iter][1].item(0),iters[iter][2].item(0)]
yarrow = [iters[iter][1].item(1),iters[iter][2].item(1)]
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.plot(xarrow,yarrow,linewidth=3,color='b')
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.show()
Figure 15.2 (b), page 350
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
return 0.5 * x * x + 4.5 * y * y
xmin = -0.1
xmax = 2.1
ymin = -0.1
ymax = 2.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
iter = 1
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
xarrow = [iters[iter][1].item(0),iters[iter][2].item(0)]
yarrow = [iters[iter][1].item(1),iters[iter][2].item(1)]
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.plot(xarrow,yarrow,linewidth=3,color='b')
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.show()
Figure 15.2 (c), page 350
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
return 0.5 * x * x + 4.5 * y * y
xmin = -0.1
xmax = 2.1
ymin = -0.1
ymax = 2.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
iter = 2
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
xarrow = [iters[iter][1].item(0),iters[iter][2].item(0)]
yarrow = [iters[iter][1].item(1),iters[iter][2].item(1)]
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.plot(xarrow,yarrow,linewidth=3,color='b')
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.show()
Figure 15.2 (d), page 350
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
return 0.5 * x * x + 4.5 * y * y
xmin = -0.1
xmax = 2.1
ymin = -0.1
ymax = 2.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
iter = 3
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
xarrow = [iters[iter][1].item(0),iters[iter][2].item(0)]
yarrow = [iters[iter][1].item(1),iters[iter][2].item(1)]
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.plot(xarrow,yarrow,linewidth=3,color='b')
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.show()
Figure 15.3 (a), page 351
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
return 0.5 * x * x + 4.5 * y * y
xmin = -0.5
xmax = 2.1
ymin = -0.2
ymax = 2.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
for iter in range(len(iters)):
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.show()
Figure 15.3 (b), page 351
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
return 0.5 * x * x + 4.5 * y * y
xmin = -0.2
xmax = 0.2
ymin = -0.1
ymax = 0.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
for iter in range(len(iters)):
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.show()
Example 15.3, page 352
def mckinnon(x):
x1 = x.item(0)
x2 = x.item(1)
return (x1 <= 0) * (360 * x1 * x1 + x2 + x2 * x2) + (x1 > 0) * (6 * x1 * x1 + x2 + x2 * x2)
x0 = np.array([[1, (1+np.sqrt(33))/8 , 0],[ 1, (1-np.sqrt(33))/8, 0]])
x0
(sol,iters) = nelderMead(mckinnon,x0)
sol
Figure 15.4, page 353
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
res = (x <= 0) * (360 * x * x + y + y * y) + (x > 0) * (6 * x * x + y + y * y)
return res
xmin = -0.2
xmax = 1.2
ymin = -0.7
ymax = 1.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
for iter in range(len(iters)):
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.show()
Figure 15.5 (a), page 354
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
res = (x <= 0) * (360 * x * x + y + y * y) + (x > 0) * (6 * x * x + y + y * y)
return res
xmin = -0.5
xmax = 1.5
ymin = -2
ymax = 2
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
for iter in range(4):
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.show()
Figure 15.5 (b), page 354
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
res = (x <= 0) * (360 * x * x + y + y * y) + (x > 0) * (6 * x * x + y + y * y)
return res
xmin = -0.1
xmax = 0.1
ymin = -0.1
ymax = 0.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
for iter in range(20,21):
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.show()
for k in range(len(iters)):
print("{}\t{:+E}\t{:+E}\t{:+E}\t{:+E}\t{:+E}".format(k+1,iters[k][0][0,0],iters[k][0][0,1],iters[k][0][0,2],iters[k][3].item(0),iters[k][2].item(0)))
print("\t{:+E}\t{:+E}\t{:+E}\t{:+E}\t{:+E}".format(iters[k][0][1,0],iters[k][0][1,1],iters[k][0][1,2],iters[k][3].item(1),iters[k][2].item(1)))
print("_________________________________________________________________________________________")
print("\t{:+E}\t{:+E}\t{:+E}\t{:+E}\t{:+E}".format(f(iters[k][0][:,0]),f(iters[k][0][:,1]),f(iters[k][0][:,2]),f(iters[k][3]),f(iters[k][2])))
print("_________________________________________________________________________________________")
def torczon(obj,x0,eps=1.0e-5,maxiter=100):
x = x0
n,m = x0.shape
x = x0
it = 0
if m != n+1:
raise OptimizationInputError("Incorrect size")
iters=list()
while True:
it = it + 1
f = [obj(x[:,k]) for k in range(m)]
## Worst value
worst = max(f)
worstindex = np.argmax(f)
xworst = x[:,[worstindex]]
## Best value
best = min(f)
bestindex = np.argmin(f)
xbest = x[:,[bestindex]]
d = xworst - xbest
iterOutput = [x.copy(),xbest.copy(),best]
## Reflexion
xr = np.empty(x.shape)
for k in range(m):
if k != bestindex:
xr[:,[k]] = 2 * xbest - x[:,[k]]
else:
xr[:,[k]] = xbest
fr = [obj(xr[:,k]) for k in range(m)]
## Best value
bestr = min(fr)
bestrindex = np.argmin(fr)
if bestr >= best:
## Contraction
for k in range(m):
if k != bestindex:
x[:,[k]] = 0.5 * (xbest + x[:,[k]])
status = "C"
else:
## Expansion
xe = np.empty(x.shape)
for k in range(m):
if k == bestindex:
xe[:,[k]] = xbest
else:
xe[:,[k]] = 3 * xbest - 2 * x[:,[k]]
fe = [obj(xe[:,k]) for k in range(m)]
## Best value
beste = min(fe)
besteindex = np.argmin(fe)
if beste >= bestr:
x = xr
status = "R"
else:
x = xe
status = "E"
iters.append(iterOutput + [status])
if linalg.norm(d) < eps or it >= maxiter:
break
return x[:,[bestindex]],iters
x0 = np.array([[1, (1+np.sqrt(33))/8 , 0],[ 1, (1-np.sqrt(33))/8, 0]])
print(x0)
(sol,iters) = torczon(mckinnon,x0)
sol
print("(x1)1\t\t(x1)2\t\tf(x1)\t\tStatus")
for k in range(len(iters)):
print("{:+E}\t{:+E}\t{:+E}\t{}".format(iters[k][1].item(0),iters[k][1].item(1),iters[k][2],iters[k][3]))
Figure 15.7, page 357
%matplotlib inline
import matplotlib.pyplot as plt
def theFunctionToPlot(x,y):
res = (x <= 0) * (360 * x * x + y + y * y) + (x > 0) * (6 * x * x + y + y * y)
return res
xmin = -0.5
xmax = 1.2
ymin = -1.1
ymax = 1.1
xlist = np.linspace(xmin,xmax,100)
ylist = np.linspace(ymin,ymax,100)
X,Y = np.meshgrid(xlist,ylist)
Z = theFunctionToPlot(X,Y)
plt.contour(X,Y,Z,50)
for iter in range(len(iters)):
xiter = [iters[iter][0][:,k].item(0) for k in range(3)]+[iters[iter][0][:,0].item(0)]
yiter = [iters[iter][0][:,k].item(1) for k in range(3)]+[iters[iter][0][:,0].item(1)]
plt.plot(xiter,yiter, linewidth=5, color='r',marker='o',mfc='blue')
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.show()