TPCCLIB
Loading...
Searching...
No Matches
powell.c
Go to the documentation of this file.
1
7/******************************************************************************/
8#include "libtpcmodel.h"
9/******************************************************************************/
12/******************************************************************************/
13/* Local variables */
15int _powell_ncom;
16double _powell_pcom[MAX_PARAMETERS], _powell_xicom[MAX_PARAMETERS];
17double (*_powellFunc)(int, double*, void*);
18void *_powellFuncData;
19int _powell_func_calls;
20/******************************************************************************/
21/* Local functions */
22void _powell_linmin(double *p, double *xi, int n, double *fret, int *itnr);
23double _powell_brent(double ax, double bx, double cx, double tol, double *xmin,
24 int *itnr, int dim);
25double _powell_f1dim(double x, int dim);
26void _powell_mnbrak(double *ax, double *bx, double *cx, double *fa, double *fb,
27 double *fc, int dim);
28/* Local "inline" functions */
29double _powell_sqr(double x) {return (x*x);}
30void _powell_shft(double *a, double *b, double *c, double *d) {*a=*b; *b=*c; *c=*d;}
31double _powell_fmax(double a, double b) {return((a>b) ? a:b);}
33/******************************************************************************/
34
35/******************************************************************************/
45 double *p,
47 double *delta,
49 int parNr,
51 double ftol,
53 int *iterNr,
55 double *fret,
57 double (*_fun)(int, double*, void*),
59 void *fundata,
61 int verbose
62) {
63 int pbIterNr;
64 int i, j, ibig, iterMax, fixed[MAX_PARAMETERS];
65 double xi[MAX_PARAMETERS][MAX_PARAMETERS]; /* Matrix for directions */
66 double pt[MAX_PARAMETERS], ptt[MAX_PARAMETERS], xit[MAX_PARAMETERS];
67 double del, fp, fptt, t;
68 double origp[MAX_PARAMETERS];
69 int ftol_reached=0;
70
71
72 if(verbose>0) printf("in powell(,,%d,%g,%d,,)\n", parNr, ftol, *iterNr);
73 if(verbose>1) {
74 printf("Initial parameter guesses and deltas:\n");
75 for(i=0; i<parNr; i++) printf(" %g %g\n", p[i], delta[i]);
76 }
77 *fret=nan("");
78 if(p==NULL) return(11);
79 if(delta==NULL) return(12);
80 if(parNr<1) return(21);
81 if(ftol<=0.0) return(22);
82 if(ftol>=1.0) return(23);
83 if((*iterNr)<1) return(24);
84
85 /* SetUp */
86 _powellFunc=_fun;
87 _powellFuncData=fundata;
88 iterMax=*iterNr; /* save the max nr of iterations */
89 _powell_ncom=parNr;
90 /* Function value at initial point */
91 _powell_func_calls=1;
92 *fret=(*_powellFunc)(parNr, p, _powellFuncData);
93 if(verbose>10) printf("initial point fret=%g\n", *fret);
94 if(!isfinite(*fret)) {
95 if(verbose>0) printf("in powell(): objf failed at initial point.\n");
96 *fret=nan(""); return(2);
97 }
98 /* Save the initial point (pt[] will be changed later) */
99 for(j=0; j<parNr; j++) origp[j]=pt[j]=p[j];
100 /* Check which parameters are fixed */
101 for(i=0; i<parNr; i++) if(fabs(delta[i])<1.0e-20) fixed[i]=1; else fixed[i]=0;
102
103 /* Initiate matrix for directions */
104 for(i=0; i<parNr; i++)
105 for(j=0; j<parNr; j++)
106 if(i==j) xi[i][j]=delta[i]; else xi[i][j]=0.0;
107
108 /* Iterate */
109 for(*iterNr=1; ; (*iterNr)++) {
110 if(verbose>2) printf(" iteration %d\n", *iterNr);
111 fp=*fret; ibig=0; del=0.0; /* largest function decrease */
112
113 /* In each iteration, loop over all directions in the set */
114 for(i=0; i<parNr; i++) {
115 if(fixed[i]) continue; /* do nothing with fixed parameters */
116 for(j=0; j<parNr; j++) if(fixed[j]) xit[j]=0.0; else xit[j]=xi[j][i];
117 fptt=*fret;
118 /* minimize along direction xit */
119 pbIterNr=POWELL_LINMIN_MAXIT;
120 _powell_linmin(p, xit, parNr, fret, &pbIterNr);
121 if(verbose>3) printf("iterNr in _powell_linmin() with p%d: %d\n",
122 i, pbIterNr);
123 if(fabs(fptt-(*fret))>del) {del=fabs(fptt-(*fret)); ibig=i;}
124 }
125 if(verbose>20) printf("fret=%g fp=%g\n", *fret, fp);
126
127 /* Check if done */
128#if(0)
129 if(2.0*fabs(fp-(*fret)) <= ftol*(fabs(fp)+fabs(*fret))) break;
130#else
131 if(2.0*fabs(fp-(*fret)) <= ftol*(fabs(fp)+fabs(*fret))) {
132 if(ftol_reached>0 || (*iterNr)>=iterMax) break; else ftol_reached++;
133 } else ftol_reached=0;
134#endif
135 if((*iterNr)>=iterMax) {
136 if(verbose>0) printf("max iterations nr exceeded in powell().\n");
137 break;
138 }
139 /* Construct the extrapolated point and the average direction moved */
140 for(j=0; j<parNr; j++) {
141 ptt[j]=2.0*p[j]-pt[j]; xit[j]=p[j]-pt[j];
142 pt[j]=p[j]; /* save the old starting point */
143 }
144 fptt=(*_powellFunc)(parNr, ptt, _powellFuncData); _powell_func_calls++;
145 if(fptt<fp) {
146 t=2.0*(fp-2.0*(*fret)+fptt)*_powell_sqr(fp-(*fret)-del)-del*_powell_sqr(fp-fptt);
147 if(t<0.0) {
148 pbIterNr=POWELL_LINMIN_MAXIT;
149 _powell_linmin(p, xit, parNr, fret, &pbIterNr);
150 if(verbose>3) printf("iterNr in _powell_linmin(): %d\n", pbIterNr);
151 for(j=0; j<parNr; j++) {
152 xi[j][ibig]=xi[j][parNr-1]; xi[j][parNr-1]=xit[j];}
153 }
154 }
155 } /* next iteration */
156 if(verbose>1) {
157 printf("iterNr := %d\n", *iterNr);
158 printf("nr of function calls := %d\n", _powell_func_calls);
159 }
160
161 if(isnan(*fret) || !isfinite(*fret)) {
162 if(verbose>10) printf("powell() fails and returns the initial point.\n");
163 if(verbose>11) {
164 if(isnan(*fret)) printf(" fret := NaN\n");
165 if(isfinite(*fret)) printf(" fret := overflow/underflow\n");
166 }
167 // if failed, then return initial guess
168 for(j=0; j<parNr; j++) p[j]=origp[j];
169 // and call function again so that any data saved there is correct
170 *fret=(*_powellFunc)(parNr, p, _powellFuncData);
171 return(3);
172 }
173 // and call function again so that any data saved there is correct
174 *fret=(*_powellFunc)(parNr, p, _powellFuncData);
175 if((*iterNr)>=iterMax) return(1);
176 if(verbose>0) printf("out of powell() in good order.\n");
177 return(0);
178}
179/******************************************************************************/
180
181/******************************************************************************/
183void _powell_linmin(double *p, double *xi, int n, double *fret, int *itnr)
184{
185 int i;
186 double xx, xmin, fx, fb, fa, bx, ax;
187
188 _powell_ncom=n;
189 for(i=0; i<n; i++) {_powell_pcom[i]=p[i]; _powell_xicom[i]=xi[i];}
190 ax=0.0; xx=1.0;
191 _powell_mnbrak(&ax, &xx, &bx, &fa, &fx, &fb, n);
192 *fret=_powell_brent(ax, xx, bx, 2.0e-4, &xmin, itnr, n);
193 for(i=0; i<n; i++) {xi[i]*=xmin; p[i]+=xi[i];}
194}
195/******************************************************************************/
196double _powell_brent(
197 double ax, double bx, double cx, double tol, double *xmin, int *itnr, int dim
198) {
199 //const int ITMAX = 100;
200 const double CGOLD = 0.3819660;
201 const double ZEPS = 1.0E-10;
202 int iterMax;
203 double a, b, d=0.0, etemp, fu, fv, fw, fx, p, q, r;
204 double e=0.0, tol1, tol2, u, v, w, x, xm;
205
206 a=(ax<cx ? ax:cx); b=(ax>cx ? ax:cx); x=w=v=bx;
207 fw=fv=fx=_powell_f1dim(x, dim);
208 iterMax=*itnr;
209 for(*itnr=0; *itnr<iterMax; (*itnr)++) {
210 xm=0.5*(a+b); tol2=2.0*(tol1=tol*fabs(x)+ZEPS);
211 if(fabs(x-xm)<=(tol2-0.5*(b-a))) {*xmin=x; return(fx);}
212 if(fabs(e)>tol1) {
213 r=(x-w)*(fx-fv); q=(x-v)*(fx-fw); p=(x-v)*q-(x-w)*r;
214 q=2.0*(q-r); if(q>0.0) p=-p; q=fabs(q);
215 etemp=e; e=d;
216 if(fabs(p)>=fabs(0.5*q*etemp) || p<=q*(a-x) || p>=q*(b-x))
217 d=CGOLD*(e=(x>=xm ? a-x:b-x));
218 else {
219 d=p/q; u=x+d;
220 if(u-a<tol2 || b-u<tol2) d=copysign(tol1, xm-x);
221 }
222 } else {d=CGOLD*(e=(x>=xm ? a-x:b-x));}
223 u=(fabs(d)>=tol1 ? x+d : x+copysign(tol1, d));
224 fu=_powell_f1dim(u, dim);
225 if(fu<=fx) {
226 if(u>=x) a=x; else b=x;
227 _powell_shft(&v, &w, &x, &u); _powell_shft(&fv, &fw, &fx, &fu);
228 } else {
229 if(u<x) a=u; else b=u;
230 if(fu<=fw || w==x) {v=w; w=u; fv=fw; fw=fu;}
231 else if(fu<=fv || v==x || v==w) {v=u; fv=fu;}
232 }
233 }
234 *xmin=x;
235 return(fx);
236}
237/******************************************************************************/
238double _powell_f1dim(double x, int dim)
239{
240 int i;
241 double f, xt[MAX_PARAMETERS];
242
243 for(i=0; i<_powell_ncom; i++) xt[i]=_powell_pcom[i]+x*_powell_xicom[i];
244 f=(*_powellFunc)(dim, xt, _powellFuncData); _powell_func_calls++;
245 return(f);
246}
247/******************************************************************************/
248void _powell_mnbrak(
249 double *ax, double *bx, double *cx, double *fa, double *fb,
250 double *fc, int dim
251) {
252 const double GOLD = 1.618034;
253 const double GLIMIT = 100.0;
254 const double TINY = 1.0e-20;
255 double ulim, u, r, q, fu, dum=0.0;
256
257 *fa=_powell_f1dim(*ax, dim); *fb=_powell_f1dim(*bx, dim);
258 if(*fb>*fa) {_powell_shft(&dum, ax, bx, &dum); _powell_shft(&dum, fb, fa, &dum);}
259 *cx=(*bx)+GOLD*(*bx-*ax); *fc=_powell_f1dim(*cx, dim);
260 while((*fb)>(*fc)) {
261 r=(*bx-*ax)*(*fb-*fc); q=(*bx-*cx)*(*fb-*fa);
262 u=(*bx)-((*bx-*cx)*q-(*bx-*ax)*r)/(2.0*copysign(_powell_fmax(fabs(q-r),TINY),q-r));
263 ulim=(*bx)+GLIMIT*(*cx-*bx);
264 if(((*bx)-u)*(u-(*cx)) > 0.0) {
265 fu=_powell_f1dim(u, dim);
266 if(fu < *fc) {*ax=(*bx); *bx=u; *fa=(*fb); *fb=fu; return;}
267 else if(fu > *fb) {*cx=u; *fc=fu; return;}
268 u=(*cx)+GOLD*(*cx-*bx);
269 fu=_powell_f1dim(u, dim);
270 } else if((*cx-u)*(u-ulim) > 0.0) {
271 fu=_powell_f1dim(u, dim);
272 if(fu < *fc) {
273 q=*cx+GOLD*(*cx-*bx); r=_powell_f1dim(u, dim);
274 _powell_shft(bx, cx, &u, &q); _powell_shft(fb, fc, &fu, &r);
275 }
276 } else if((u-ulim)*(ulim-*cx) >= 0.0) {
277 u=ulim; fu=_powell_f1dim(u, dim);
278 } else {
279 u=(*cx)+GOLD*(*cx-*bx);
280 fu=_powell_f1dim(u, dim);
281 }
282 _powell_shft(ax, bx, cx, &u); _powell_shft(fa, fb, fc, &fu);
283 }
284}
285/******************************************************************************/
287
288/******************************************************************************/
Header file for libtpcmodel.
#define MAX_PARAMETERS
Definition libtpcmodel.h:31
int POWELL_LINMIN_MAXIT
Definition powell.c:11
int powell(double *p, double *delta, int parNr, double ftol, int *iterNr, double *fret, double(*_fun)(int, double *, void *), void *fundata, int verbose)
Definition powell.c:43