TPCCLIB
Loading...
Searching...
No Matches
nlopt1d.c File Reference

Nonlinear one-dimensional optimization. More...

#include "libtpcmodel.h"

Go to the source code of this file.

Functions

int nlopt1D (double(*_fun)(double, void *), void *_fundata, double x, double xl, double xu, double delta, double tol, const int maxeval, double *nx, double *nf, int verbose)
 

Detailed Description

Nonlinear one-dimensional optimization.

Author
Vesa Oikonen

Definition in file nlopt1d.c.

Function Documentation

◆ nlopt1D()

int nlopt1D ( double(* _fun )(double, void *),
void * _fundata,
double x,
double xl,
double xu,
double delta,
double tol,
const int maxeval,
double * nx,
double * nf,
int verbose )

Local one-dimensional minimization by bracketing.

Returns
0 in case of no errors.
See also
simplex, tgo, bobyqa, powell, pearson
Parameters
_funPointer to the function to be minimized. It must be defined in main program as: double func(double p, void *data); where p is the parameter, and data points to user-defined data structure needed by the function.
_fundataPointer to data that will be passed on to the _fun().
xParameter initial value.
xlParameter lower limit.
xuParameter upper limit.
deltaInitial parameter delta.
tolRequired tolerance.
maxevalMaximum number of function evaluations.
nxPointer for optimized parameter value.
nfPointer for function value at optimum; NULL if not needed.
verboseVerbose level

Definition at line 14 of file nlopt1d.c.

39 {
40 if(verbose>0) {
41 printf("%s(f, fdata, %g, %g, %g, %g, %g, %d, ...)\n", __func__, x, xl, xu, delta, tol, maxeval);
42 fflush(stdout);
43 }
44
45
46 /* Check the input */
47 if(_fun==NULL) return(1);
48 if(xl>xu || x<xl || x>xu) return(1);
49 if(!(delta>0.0) || !(tol>0.0)) return(1);
50 if(tol>=delta) return(1);
51 if(maxeval<5) return(1);
52 if(nx==NULL) return(1);
53
54 double begin=xl;
55 double end=xu;
56 int nevals=0;
57
58 double p1=0, p2=0, p3=0, f1=0, f2=0, f3=0;
59 /* Calculate function value with initial parameter value */
60 double minf=f2=_fun(x, _fundata); nevals++;
61 /* If parameter is fixed, then this was all that we can do */
62 if(xl>=xu) {
63 *nx=x; if(nf!=NULL) *nf=minf;
64 return(0);
65 }
66
67 /* Find three bracketing points such that f1 > f2 < f3.
68 Do this by generating a sequence of points expanding away from 0.
69 Also note that, in the following code, it is always the
70 case that p1 < p2 < p3. */
71 p2=x;
72
73 /* Start by setting a starting set of 3 points that are inside the bounds */
74 p1=p2-delta; if(p1>begin) p1=begin;
75 p3=p2+delta; if(p3<end) p3=end;
76 /* Compute their function values */
77 f1=_fun(p1, _fundata); nevals++;
78 f3=_fun(p3, _fundata); nevals++;
79 if(p2==p1 || p2==p3) {
80 p2=0.5*(p1+p3);
81 f2=minf=_fun(p2, _fundata); nevals++;
82 }
83
84 /* Now we have 3 points on the function.
85 Start looking for a bracketing set such that f1 > f2 < f3 is the case. */
86 double jump_size=delta;
87 while(!(f1>f2 && f2<f3)) {
88 /* check for hitting max_iter */
89 if(verbose>5) printf(" bracketing: nevals=%d\n", nevals);
90 if(nevals >= maxeval) {
91 *nx=p2; minf=f2; if(nf!=NULL) *nf=minf;
92 return(0);
93 }
94 /* check if required tolerance was reached */
95 if((p3-p1)<tol) { //if (p3-p1 < eps)
96 if(verbose>1) printf(" max tolerance was reached during bracketing\n");
97 if(f1<f2 && f1<f3) {
98 *nx=p1; minf=f1; if(nf!=NULL) *nf=minf;
99 return(0);
100 }
101 if(f2<f1 && f2<f3) {
102 *nx=p2; minf=f2; if(nf!=NULL) *nf=minf;
103 return(0);
104 }
105 *nx=p3; minf=f3; if(nf!=NULL) *nf=minf;
106 return(0);
107 }
108 if(verbose>6) printf(" jump_size=%g\n", jump_size);
109 /* if f1 is small then take a step to the left */
110 if(f1<f3) {
111 /* check if the minimum is colliding against the bounds. If so then pick
112 a point between p1 and p2 in the hopes that shrinking the interval will
113 be a good thing to do. Or if p1 and p2 aren't differentiated then try
114 and get them to obtain different values. */
115 if(p1==begin || (f1==f2 && (end-begin)<jump_size )) {
116 p3=p2; f3=f2; p2=0.5*(p1+p2);
117 f2=minf=_fun(p2, _fundata); nevals++;
118 } else {
119 /* pick a new point to the left of our current bracket */
120 p3=p2; f3=f2; p2=p1; f2=f1;
121 p1-=jump_size; if(p1<begin) p1=begin;
122 f1=_fun(p1, _fundata); nevals++;
123 jump_size*=2.0;
124 }
125 } else { // otherwise f3 is small and we should take a step to the right
126 /* check if the minimum is colliding against the bounds. If so then pick
127 a point between p2 and p3 in the hopes that shrinking the interval will
128 be a good thing to do. Or if p2 and p3 aren't differentiated then
129 try and get them to obtain different values. */
130 if(p3==end || (f2==f3 && (end-begin)<jump_size)) {
131 p1=p2; f1=f2; p2=0.5*(p3+p2);
132 f2=minf=_fun(p2, _fundata); nevals++;
133 } else {
134 /* pick a new point to the right of our current bracket */
135 p1=p2; f1=f2; p2=p3; f2=f3;
136 p3+=jump_size; if(p3>end) p3=end;
137 f3=minf=_fun(p3, _fundata); nevals++;
138 jump_size*=2.0;
139 }
140 }
141 }
142 if(verbose>4) printf(" brackets ready\n");
143
144 /* Loop until we have done the max allowable number of iterations or
145 the bracketing window is smaller than eps.
146 Within this loop we maintain the invariant that: f1 > f2 < f3 and
147 p1 < p2 < p3. */
148 double d, d2;
149 const double tau=0.1;
150 double p_min, f_min;
151 while((nevals<maxeval) && (p3-p1>tol)) {
152 if(verbose>5) printf(" main loop: nevals=%d\n", nevals);
153
154 //p_min = lagrange_poly_min_extrap(p1,p2,p3, f1,f2,f3);
155 d=f1*(p3*p3-p2*p2) + f2*(p1*p1-p3*p3) + f3*(p2*p2-p1*p1);
156 d2=2.0*(f1*(p3-p2) + f2*(p1-p3) + f3*(p2-p1));
157 if(d2==0.0 || !isfinite(d/=d2)) { // d=d/d2
158 p_min=p2;
159 } else {
160 if(p1<=d && d<=p3) {p_min=d;}
161 else {p_min=d; if(p1>p_min) p_min=p1; if(p3<p_min) p_min=p3;}
162 }
163
164 /* make sure p_min isn't too close to the three points we already have */
165 if(p_min<p2) {
166 d=(p2-p1)*tau;
167 if(fabs(p1-p_min)<d) p_min=p1+d;
168 else if(fabs(p2-p_min)<d) p_min=p2-d;
169 } else {
170 d=(p3-p2)*tau;
171 if(fabs(p2-p_min)<d) p_min=p2+d;
172 else if(fabs(p3-p_min)<d) p_min=p3-d;
173 }
174
175 /* make sure one side of the bracket isn't super huge compared to the other
176 side. If it is then contract it. */
177 double bracket_ratio=fabs(p1-p2)/fabs(p2-p3);
178 if(!(bracket_ratio<100.0 && bracket_ratio>0.01)) {
179 /* Force p_min to be on a reasonable side. */
180 if(bracket_ratio>1.0 && p_min>p2) p_min=0.5*(p1+p2);
181 else if(p_min<p2) p_min=0.5*(p2+p3);
182 }
183
184 /* Compute function value at p_min */
185 *nx=p_min;
186 f_min=minf=_fun(p_min, _fundata); nevals++;
187
188 /* Remove one of the endpoints of our bracket depending on where the new point falls */
189 if(p_min<p2) {
190 if(f1>f_min && f_min<f2) {p3=p2; f3=f2; p2=p_min; f2=f_min;}
191 else {p1=p_min; f1=f_min;}
192 } else {
193 if(f2>f_min && f_min<f3) {p1=p2; f1=f2; p2=p_min; f2=f_min;}
194 else {p3=p_min; f3=f_min;}
195 }
196 }
197 *nx=p2; minf=f2; if(nf!=NULL) *nf=minf;
198 return(0);
199}