-
Notifications
You must be signed in to change notification settings - Fork 192
/
nelder.m
195 lines (195 loc) · 5.58 KB
/
nelder.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
function [x,lhist,histout,simpdata]=nelder(x0,f,tol,maxit,budget)
%
% Nelder-Mead optimizer, No tie-breaking rule other than MATLAB's sort
%
% C. T. Kelley, December 12, 1996
%
%
% This code comes with no guarantee or warranty of any kind.
%
% function [x,lhist,histout,simpdata] = nelder(x0,f,tol,maxit,budget)
%
% inputs:
% vertices of initial simplex = x0 (n x n+1 matrix)
% The code will order the vertices for you and no benefit is
% accrued if you do it yourself.
%
% objective function = f
%
% termination tolerance = tol
% maximum number of iterations = maxit (default = 100)
% As of today, dist = | best value - worst value | < tol
% or when maxit iterations have been taken
% budget = max f evals (default=50*number of variables)
% The iteration will terminate after the iteration that
% exhausts the budget
%
%
% outputs:
% final simplex = x (n x n+1) matrix
%
% number of iterations before termination = itout (optional)
% iteration histor = histout itout x 5
% histout = iteration history, updated after each nonlinear iteration
% = lhist x 5 array, the rows are
% [fcount, fval, norm(grad), dist, diam]
% fcount = cumulative function evals
% fval = current best function value
% norm(grad) = current simplex grad norm
% dist = difference between worst and best values
% diam = max oriented length
% simpdata = data for simplex gradient restart
% = [norm(grad), cond(v), bar f]
%
% initialize counters
%
lhist=0; fcount=0;
%
% set debug=1 to print out iteration stats
%
debug=0;
%
% Set the N-M parameters
%
rho=1; chi=2; gamma=.5; sigma=.5;
dsize=size(x0); n=dsize(1);
if nargin < 4 maxit=100; end
if nargin < 5 budget=100*n; end
%
% set the paramters for stagnation detection/fixup
% setting oshrink=0 gives vanilla Nelder-Mead
%
oshrink=1; restartmax=3; restarts=0;
%
%
% Order the vertices for the first time
%
x=x0; [n,m]=size(x); histout=zeros(maxit*3,5); simpdata=zeros(maxit,3);
itout=0; orth=0;
xtmp=zeros(n,n+1); z=zeros(n,n); delf=zeros(n,1);
for j=1:n+1; fv(j)=feval(f,x(:,j)); end; fcount=fcount+n+1;
[fs,is]=sort(fv); xtmp=x(:,is); x=xtmp; fv=fs;
itc=0; dist=fv(n+1)-fv(1);
diam=zeros(n,1);
for j=2:n+1
v(:,j-1)=-x(:,1)+x(:,j);
delf(j-1)=fv(j)-fv(1);
diam(j-1)=norm(v(:,j-1));
end
sgrad=v'\delf; alpha=1.d-4*max(diam)/norm(sgrad);
lhist=lhist+1;
histout(lhist,:)=[fcount, fv(1), norm(sgrad,inf), 0, max(diam)];
%
% main N-M loop
%
while(itc < maxit & dist > tol & restarts < restartmax & fcount <= budget)
fbc=sum(fv)/(n+1);
xbc=sum(x')'/(n+1);
sgrad=v'\delf;
simpdata(itc+1,1)=norm(sgrad);
simpdata(itc+1,2)=cond(v);
simpdata(itc+1,3)=fbc;
if(det(v) == 0)
disp('simplex collapse')
break
end
happy=0; itc=itc+1; itout=itc;
%
% reflect
%
y=x(:,1:n);
xbart = sum(y')/n; % centriod of better vertices
xbar=xbart';
xr=(1 + rho)*xbar - rho*x(:,n+1);
fr=feval(f,xr); fcount=fcount+1;
if(fr >= fv(1) & fr < fv(n)) happy = 1; xn=xr; fn=fr; end;
% if(happy==1) disp(' reflect '); end
%
% expand
%
if(happy == 0 & fr < fv(1))
xe = (1 + rho*chi)*xbar - rho*chi*x(:,n+1);
fe=feval(f,xe); fcount=fcount+1;
if(fe < fr) xn=xe; fn=fe; happy=1; end
if(fe >=fr) xn=xr; fn=fr; happy=1; end
% if(happy==1) disp(' expand '); end
end
%
% contract
%
if(happy == 0 & fr >= fv(n) & fr < fv(n+1))
%
% outside contraction
%
xc=(1 + rho*gamma)*xbar - rho*gamma*x(:,n+1);
fc=feval(f,xc); fcount=fcount+1;
if(fc <= fr) xn=xc; fn=fc; happy=1; end;
% if(happy==1) disp(' outside '); end;
end
%
% inside contraction
%
if(happy == 0 & fr >= fv(n+1))
xc=(1 - gamma)*xbar+gamma*x(:,n+1);
fc=feval(f,xc); fcount=fcount+1;
if(fc < fv(n+1)) happy=1; xn=xc; fn=fc; end;
% if(happy==1) disp(' inside '); end;
end
%
% test for sufficient decrease,
% do an oriented shrink if necessary
%
if(happy==1 & oshrink==1)
xt=x; xt(:,n+1)=xn; ft=fv; ft(n+1)=fn;
% xt=x; xt(:,n+1)=xn; ft=fv; ft(n+1)=feval(f,xn); fcount=fcount+1;
fbt=sum(ft)/(n+1); delfb=fbt-fbc; armtst=alpha*norm(sgrad)^2;
if(delfb > -armtst/n)
restarts=restarts+1;
orth=1; diams=min(diam);
sx=.5+sign(sgrad); sx=sign(sx);
if debug==1
[itc, delfb, armtst]
end
happy=0;
for j=2:n+1; x(:,j)=x(:,1);
x(j-1,j)=x(j-1,j)-diams*sx(j-1); end;
end
end
%
% if you have accepted a new point, nuke the old point and
% resort
%
if(happy==1)
x(:,n+1)=xn; fv(n+1)=fn;
% x(:,n+1)=xn; fv(n+1)=feval(f,xn); fcount=fcount+1;
[fs,is]=sort(fv); xtmp=x(:,is); x=xtmp; fv=fs;
end
%
% You're in trouble now! Shrink or restart.
%
if(restarts >= restartmax) disp(' stagnation in Nelder-Mead'); end;
if(happy == 0 & restarts < restartmax)
if(orth ~=1) disp(' shrink '); end;
if(orth ==1)
if debug == 1 disp(' restart '); end
orth=0; end;
for j=2:n+1;
x(:,j)=x(:,1)+sigma*(x(:,j)-x(:,1));
fv(j)=feval(f,x(:,j));
end
fcount=fcount+n;
[fs,is]=sort(fv); xtmp=x(:,is); x=xtmp; fv=fs;
end
%
% compute the diameter of the new simplex and the iteration data
%
for j=2:n+1
v(:,j-1)=-x(:,1)+x(:,j);
delf(j-1)=fv(j)-fv(1);
diam(j-1)=norm(v(:,j-1));
end
dist=fv(n+1)-fv(1);
lhist=lhist+1;
sgrad=v'\delf;
histout(lhist,:)=[fcount, fv(1), norm(sgrad,inf), dist, max(diam)];
end