Nelder-Mead (downhill simplex) optimization.
If the number of free parameters (not fixed) is one, then bracketing method is used instead of downhill simplex.
47 {
48 FILE *fp=stdout;
49 int verbose=0;
if(status!=NULL) {verbose=status->
verbose; fp=status->
fp;}
50 if(verbose>1) fprintf(fp, "%s(NLOPT, %d, status)\n", __func__, maxIter);
51 if(nlo==NULL) {
54 }
58 }
59
60
61 for(
unsigned int i=0; i<nlo->
totalNr; i++)
63 !isfinite(nlo->
xfull[i]) || !isfinite(nlo->
xlower[i]) || !isfinite(nlo->
xupper[i]))
64 {
65 if(verbose>2) {
66 fprintf(fp, "parameter %d failed: %e <= %e <= %e\n",
68 fflush(fp);
69 }
72 }
73
74
76 if(verbose>2) fprintf(fp, "going for one-dimensional method.\n");
77 return(
nlopt1D(nlo, maxIter, NULL));
78 }
79
80
81 if(verbose>10) fprintf(fp, "Simplex initialization\n");
82 unsigned int parNr=nlo->
totalNr;
83 unsigned int sn=parNr+1;
84 double simplexP[sn+2][parNr];
85 double simplexC[parNr];
86 double simplexR[sn+2];
87 for(unsigned int i=0; i<(sn+2); i++) simplexR[i]=nan("");
88 if(verbose>16) fprintf(fp, "simplexR[0..%d]\n", sn+2);
89 unsigned int newPnt=sn;
90 unsigned int newPnt2=newPnt+1;
91
92 if(maxIter<2) maxIter=500;
93
94
95 for(unsigned int j=0; j<sn; j++)
96 for(unsigned int i=0; i<parNr; i++)
97 simplexP[j][i]=nlo->
xfull[i];
98
99 for(unsigned int j=1; j<sn; j++) {
100 for(unsigned int i=0; i<parNr; i++) {
101 simplexP[j][i] = simplexP[j-1][i];
103 simplexP[j][i] += nlo->
xdelta[i];
104 if(simplexP[j][i]<nlo->
xlower[i] || simplexP[j][i]>nlo->
xupper[i]) {
105
106 simplexP[j][i] -= 2.0*nlo->
xdelta[i];
107
108 if(simplexP[j][i]<nlo->
xlower[i] || simplexP[j][i]>nlo->
xupper[i]) {
109
110 if(verbose>2) {
111 fprintf(fp,
"failed limits %e,%e or delta: %e\n", nlo->
xlower[i], nlo->
xupper[i], nlo->
xdelta[i]);
112 fflush(fp);
113 }
116 }
117 }
118 }
119 }
120 }
121
122 for(unsigned int j=0; j<sn; j++) {
123 if(verbose>13) {
124 fprintf(fp, "x[%d][]=", j);
125 for(unsigned int i=0; i<parNr; i++) fprintf(fp, "%g ", simplexP[j][i]);
126 fprintf(fp, "\n");
127 }
128 simplexR[j] = (*nlo->
_fun)(parNr, simplexP[j], nlo->
fundata);
130 if(verbose>12) fprintf(fp, " R[%d]=%g\n", j, simplexR[j]);
132 int ret=
nloptAddP(nlo, simplexP[j], simplexR[j]);
134 statusSet(status, __func__, __FILE__, __LINE__, ret);
135 return(ret);
136 }
137 }
138 }
139 double initialR=simplexR[0];
140
141
142 unsigned int best=0, nextBest=0, worst=0;
143 {
144 double max, min, min2;
145 max=min=simplexR[0]; best=worst=0;
146 for(unsigned int j=1; j<sn; j++) {
147 if(!isfinite(max) || simplexR[j] > max) {max=simplexR[j]; worst=j;}
148 if(!isfinite(min) || simplexR[j] < min) {min=simplexR[j]; best=j; }
149 }
150
151 min2=max; nextBest=worst;
152 for(unsigned int j=0; j<sn; j++)
153 if(j!=best && (simplexR[j] < min2)) {min2=simplexR[j]; nextBest=j;}
154 if(verbose>14) {
155 fprintf(fp, " best := %g (%d)\n", min, best);
156 fprintf(fp, " next best := %g (%d)\n", min2, nextBest);
157 fprintf(fp, " worst := %g (%d)\n", max, worst);
158 }
159 }
160
161
162 if(verbose>10) fprintf(fp, "Simplex iterations\n");
163 double prevBestR=simplexR[best];
164 unsigned int iterNr=0, stopTolerance=0, stopR=0;
165 do {
166 iterNr++;
167 if(verbose>13) {fprintf(fp, "\niteration := %d\n", iterNr); fflush(fp);}
168 if(verbose>16) {
169 for(unsigned int j=0; j<sn; j++) {
170 fprintf(fp, "simplexP[%d][]=", j);
171 for(unsigned int i=0; i<parNr; i++) fprintf(fp, "%g ", simplexP[j][i]);
172 fprintf(fp, " --> %g ", simplexR[j]);
173 if(j==best) fprintf(fp, " (best)\n");
174 else if(j==nextBest) fprintf(fp, " (next best)\n");
175 else if(j==worst) fprintf(fp, " (worst)\n");
176 else fprintf(fp, "\n");
177 fflush(fp);
178 }
179 }
180
181 for(unsigned int i=0; i<parNr; i++) {
182 simplexC[i]=0.0; unsigned int n=0;
183 for(unsigned int j=0; j<sn; j++)
184 if(j!=worst && isfinite(simplexP[j][i])) {simplexC[i]+=simplexP[j][i]; n++;}
185 simplexC[i]/=(double)(n);
186
187 }
188 if(verbose>15) {
189 fprintf(fp, "centroid x[]=");
190 for(unsigned int i=0; i<parNr; i++) fprintf(fp, "%g ", simplexC[i]);
191 fprintf(fp, "\n"); fflush(fp);
192 }
193
194
195
196 {
197 unsigned int k;
198 for(k=0; k<parNr; k++) {
199 if(fabs(simplexC[k]-simplexP[worst][k])>0.5*nlo->
xtol[k])
break;
200 if(fabs(simplexC[k]-simplexP[best][k])>0.5*nlo->
xtol[k])
break;
201 if(fabs(simplexC[k]-simplexP[nextBest][k])>0.5*nlo->
xtol[k])
break;
202 }
203 if(k==parNr) stopTolerance++; else stopTolerance=0;
204 }
205
206 if(stopTolerance>=parNr && stopR>=parNr) {
207 if(verbose>2) {fprintf(fp, " stopping because simplex is not improving.\n"); fflush(fp);}
208 break;
209 }
210
211 double f=1.0;
212 for(unsigned int i=0; i<parNr; i++)
213 simplexP[newPnt][i] = simplexC[i] + f*(simplexC[i]-simplexP[worst][i]);
215
216 simplexR[newPnt] = (*nlo->
_fun)(parNr, simplexP[newPnt], nlo->
fundata);
218 if(verbose>15) {
219 fprintf(fp, "new point x[%d][]=", newPnt);
220 for(unsigned int i=0; i<parNr; i++) fprintf(fp, "%g ", simplexP[newPnt][i]);
221 fprintf(fp, "\n -> R[%d]=%g\n", newPnt, simplexR[newPnt]);
222 }
224 int ret=
nloptAddP(nlo, simplexP[newPnt], simplexR[newPnt]);
226 }
227
228 if(simplexR[newPnt] < simplexR[best]) {
229 if(verbose>14) fprintf(fp, " new is better than best\n");
230
231 f=2.0;
232 for(unsigned int i=0; i<parNr; i++)
233 simplexP[newPnt2][i] = simplexC[i] + f*(simplexC[i]-simplexP[worst][i]);
235 simplexR[newPnt2] = (*nlo->
_fun)(parNr, simplexP[newPnt2], nlo->
fundata);
238 int ret=
nloptAddP(nlo, simplexP[newPnt2], simplexR[newPnt2]);
240 }
241 if(simplexR[newPnt2] < simplexR[newPnt]) {
242 if(verbose>14) fprintf(fp, " expanded (%g) is better than new\n", simplexR[newPnt2]);
243 for(unsigned int i=0; i<parNr; i++) simplexP[worst][i]=simplexP[newPnt2][i];
244 simplexR[worst]=simplexR[newPnt2];
245 } else {
246 if(verbose>14) fprintf(fp, " expanded (%g) is no better than new\n", simplexR[newPnt2]);
247 for(unsigned int i=0; i<parNr; i++) simplexP[worst][i]=simplexP[newPnt][i];
248 simplexR[worst]=simplexR[newPnt];
249 }
250 } else if(!isfinite(simplexR[newPnt]) || simplexR[newPnt] > simplexR[worst]) {
251 if(verbose>14) fprintf(fp, " new is worse than worst\n");
252
253
254 f=-0.5;
255 for(unsigned int i=0; i<parNr; i++)
256 simplexP[newPnt2][i] = simplexC[i] + f*(simplexC[i]-simplexP[worst][i]);
258 simplexR[newPnt2] = (*nlo->
_fun)(parNr, simplexP[newPnt2], nlo->
fundata);
261 int ret=
nloptAddP(nlo, simplexP[newPnt2], simplexR[newPnt2]);
263 }
264 if(simplexR[newPnt2] < simplexR[newPnt] && isfinite(simplexR[newPnt2])) {
265 if(verbose>14) fprintf(fp, " halfway (%g) is better than new\n", simplexR[newPnt2]);
266 for(unsigned int i=0; i<parNr; i++) simplexP[worst][i]=simplexP[newPnt2][i];
267 simplexR[worst]=simplexR[newPnt2];
268 } else if(isfinite(simplexR[newPnt])) {
269 if(verbose>14) fprintf(fp, " halfway (%g) is no better than new\n", simplexR[newPnt2]);
270 for(unsigned int i=0; i<parNr; i++) simplexP[worst][i]=simplexP[newPnt][i];
271 simplexR[worst]=simplexR[newPnt];
272 }
273 } else if(simplexR[newPnt] > simplexR[nextBest]) {
274 if(verbose>14) fprintf(fp, " new is worse than next best\n");
275
276
277 f=0.5;
278 for(unsigned int i=0; i<parNr; i++)
279 simplexP[newPnt2][i] = simplexC[i] + f*(simplexP[newPnt][i]-simplexC[i]);
281 simplexR[newPnt2] = (*nlo->
_fun)(parNr, simplexP[newPnt2], nlo->
fundata);
284 int ret=
nloptAddP(nlo, simplexP[newPnt2], simplexR[newPnt2]);
286 }
287 if(simplexR[newPnt2] < simplexR[newPnt]) {
288 if(verbose>14) fprintf(fp, " halfway (%g) is better than new\n", simplexR[newPnt2]);
289 for(unsigned int i=0; i<parNr; i++) simplexP[worst][i]=simplexP[newPnt2][i];
290 simplexR[worst]=simplexR[newPnt2];
291 } else if(isfinite(simplexR[newPnt])) {
292 if(verbose>14) fprintf(fp, " halfway (%g) is worse than new\n", simplexR[newPnt2]);
293 for(unsigned int i=0; i<parNr; i++) simplexP[worst][i]=simplexP[newPnt][i];
294 simplexR[worst]=simplexR[newPnt];
295 }
296 } else if(isfinite(simplexR[newPnt])) {
297 if(verbose>14) fprintf(fp, " new is worse than the best but better than the next best\n");
298
299 for(unsigned int i=0; i<parNr; i++) simplexP[worst][i]=simplexP[newPnt][i];
300 simplexR[worst]=simplexR[newPnt];
301 }
302
303
304 {
305 double max, min, min2;
306 max=min=simplexR[0]; best=worst=0;
307 for(unsigned int j=1; j<sn; j++) {
308 if(!isfinite(max) || simplexR[j] > max) {max=simplexR[j]; worst=j;}
309 if(!isfinite(min) || simplexR[j] < min) {min=simplexR[j]; best=j; }
310 }
311
312 min2=max; nextBest=worst;
313 for(unsigned int j=0; j<sn; j++)
314 if(j!=best && (simplexR[j] < min2)) {min2=simplexR[j]; nextBest=j;}
315 if(verbose>14) {
316 fprintf(fp, " best := %g (%d)\n", min, best);
317 fprintf(fp, " next best := %g (%d)\n", min2, nextBest);
318 fprintf(fp, " worst := %g (%d)\n", max, worst);
319 }
320 }
321
322
323 if(simplexR[best]<prevBestR) stopR=0; else stopR++;
324 prevBestR=simplexR[best];
325
326 } while(iterNr<maxIter);
327
328 if(verbose>2) {
329 if(iterNr>=maxIter) fprintf(fp, " stopped because max iterations reached.\n");
330 fprintf(fp, " %d iterations\n", iterNr);
331 fprintf(fp, " R[%d]=%g\n", best, simplexR[best]);
332 fflush(fp);
333 }
334
335#if(0)
336
337
338 simplexR[best] = (*nlo->
_fun)(parNr, simplexP[best], nlo->
fundata);
339#endif
340
341
342 if(!isfinite(simplexR[best])) {
345 }
346
347
348 if(simplexR[best]<=initialR) {
349 for(
unsigned int i=0; i<parNr; i++) nlo->
xfull[i]=simplexP[best][i];
350 nlo->
funval=simplexR[best];
351 } else {
352
353 if(1 || verbose>0) fprintf(fp, "nloptSimplex() gives worse R than initially!\n");
356 }
357
360}
unsigned int nloptForceLimits(unsigned int n, double *pLower, double *pUpper, double *p)
Enforce the model parameters within given limits.
int nlopt1D(NLOPT *nlo, unsigned int maxIter, TPCSTATUS *status)
unsigned int nloptFixedNr(NLOPT *d)
int nloptAddP(NLOPT *nlo, double *p, double funval)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
double(* _fun)(int, double *, void *)
int verbose
Verbose level, used by statusPrint() etc.
FILE * fp
File pointer for writing log information during development and testing.
@ TPCERROR_INVALID_VALUE
Invalid value.
@ TPCERROR_BAD_FIT
Fitting not successful.
@ TPCERROR_FAIL
General error.
@ TPCERROR_NO_DATA
File contains no data.