from numpy import * class NelderMead: """Implementation of Nelder Mead Algorithm""" def __init__(self, f): self.function = f def Run(self): function = self.function ndim = 2 # 2D problem npts = ndim + 1 # a simplex # Define the starting simplex and evaluate the function at its vertices x = zeros((npts, ndim)) x[0,:] = 2 # Starting point for i in range(1,npts,1): x[i,:] = x[i-1,:] + array([0.1,0.2])*i f = apply_along_axis(function,1,x) # Sort the simplex and the vector of function values index = argsort(f, axis = 0) # best - middle - worst x = x[index,:] f = f[index] # set up storage for simplex path plotting self.path = copy(x) fpath = copy(f) converged = False while (converged==False): # 1. Find the center of the face of the simplex (except the worst point) x_mean = mean(x[0:(npts-1),:], axis = 0) # 2. Reflect the worst point across the face xr = 2*x_mean-x[(npts-1),:] if function(xr) <= f[0]: # is the new point the new best? x2r = 3*x_mean-2*x[(npts-1),:] # grow further in that direction if function(x2r) < function(xr): # did the growing improve? x[(npts-1),:] = x2r # accept the grown point and go to the next iteration f[(npts-1)] = function(x2r) print 'accepted grown point' else: # the growing step did not help x[(npts-1),:] = xr # accept the original reflected point and go to the next iteration f[(npts-1)] = function(xr) print 'accepted reflected point (it was the best)' elif function(xr) >= f[(npts-2)]: # is the new point still the worst? xs = 1.5*x_mean - 0.5*x[(npts-1),:] # reflect + shrink if function(xs) < f[(npts-2)]: # better than the second worst? x[(npts-1),:] = xs # accept and move on f[(npts-1)] = function(xs) print 'accepted reflected & shrunk point' else: # not better than the second worst xs = 0.5*x_mean+0.5*x[(npts-1),:] # just shrink (no reflection) if function(xs) > f[(npts-2)]: x[1:npts,:] = 0.5*(x[1:npts,:] + x[0,:]) # shrink everything (except the best, 0) towards the best f = apply_along_axis(function, 1, x) print 'shrank everything towards the best' else: x[(npts-1),:] = xs # accept and move on f[(npts-1)] = function(xs) print 'accepted shrunk only point' else: # the new reflected point is neither the best nor the worst. keep it x[(npts-1),:] = xr f[(npts-1)] = function(xr) print 'accepted reflected point (though it was not a new best)' # Sort the simplex and the vector of function values - think of a better way that doesn't need sorting every time index = argsort(f, axis = 0) # best - middle - worst x = x[index,:] f = f[index] # Record the history of the simplex: self.path = concatenate((self.path,x),axis = 0) if fabs(f[0]- f[(npts-1)]) < 1e-14: converged = True print '\nconverged at: ' + str(x[0,:]) + ', with a function value of ' + str(f[0]) + '\n' def plot(self): path = self.path function = self.function #Plot the Rosenbrock function from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.mplot3d.art3d import Line3D from matplotlib import cm from matplotlib.colors import LogNorm import matplotlib.pyplot as plt import numpy as np fig = plt.figure() ax = Axes3D(fig, azim = -128, elev = 43) s = .1 X = np.arange(-2, 2.5+s, s) Y = np.arange(-1, 3.5+s, s) X, Y = np.meshgrid(X, Y) Z = (1.-X)**2 + 100.*(Y-X*X)**2 ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, norm = LogNorm(), cmap = cm.gray) plt.xlabel("x1") plt.ylabel("x2") ax.plot(ravel(path[:,0]), ravel(path[:,1]), ravel(apply_along_axis(function, 1, path[:,:])), color = 'g', marker = '^') # # Plot the simplex path # for i in range(0,path.shape[0],3): # x_path = path[i:i+3,0] # y_path = path[i:i+3,1] # f_path = apply_along_axis(function, 1, path[i:i+3,:]) # lstLines = [ [ ( x_path[j], y_path[j], f_path[j] ), ( x_path[k], y_path[k], f_path[k] )] for (j, k) in ((0,1),(0,2),(1,2))] # ax.plot_wireframe(ravel(x_path), ravel(y_path), ravel(f_path), rstride = 1, cstride = 1) plt.savefig("Rosenbrock function.svg") plt.show()