Go to the documentation of this file.00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007 #include "vnl_brent_minimizer.h"
00008
00009 #include <vcl_cmath.h>
00010 #include <vcl_iostream.h>
00011 #include <vcl_algorithm.h>
00012 #include <vcl_cassert.h>
00013
00014 #include <vnl/vnl_vector.h>
00015 #include <vnl/algo/vnl_bracket_minimum.h>
00016
00017 static const double GOLDEN_RATIO = 1.618033988749894848;
00018 static const double COMPL_GOLD = 0.381966011250105152;
00019 static const double EPS = 1e-8;
00020
00021
00022 class vnl_brent_minimizer_func
00023 {
00024 vnl_vector<double> v;
00025 vnl_cost_function* f;
00026 public:
00027 vnl_brent_minimizer_func(vnl_cost_function& fn)
00028 { f=&fn; v.set_size(1); }
00029
00030 double operator()(double x) { v[0]=x; return f->f(v); }
00031 };
00032
00033 vnl_brent_minimizer::vnl_brent_minimizer(vnl_cost_function& functor)
00034 {
00035 f_=&functor;
00036 set_x_tolerance(1e-6);
00037 }
00038
00039 vnl_brent_minimizer::~vnl_brent_minimizer()
00040 {
00041 }
00042
00043
00044
00045
00046
00047
00048 double vnl_brent_minimizer::minimize_golden(double a, double b, double c,
00049 double fa, double fb, double fc)
00050 {
00051
00052
00053 vnl_brent_minimizer_func f(*f_);
00054
00055 double m = 0.5*(a+c);
00056 double tol = EPS*vcl_fabs(b)+xtol;
00057 double tol2 = 2*tol;
00058
00059 double u,fu;
00060
00061
00062 while (vcl_fabs(b-m)>(tol2-0.5*(c-a)))
00063 {
00064 double e = (b<m?c:a) - b;
00065 double d = COMPL_GOLD * e;
00066
00067
00068 if (vcl_fabs(d)>=tol)
00069 u = b+d;
00070 else
00071 {
00072 if (d>0) u=b+tol;
00073 else u=b-tol;
00074 }
00075
00076 if (u<a) vcl_cout<<"u<a!"<<vcl_endl;
00077 if (u>c) vcl_cout<<"u>c!"<<vcl_endl;
00078
00079
00080 fu = f(u);
00081
00082
00083 if (fu<fb)
00084 {
00085
00086 if (u<b)
00087 {
00088
00089 c=b; fc=fb;
00090 b=u; fb=fu;
00091 }
00092 else
00093 {
00094
00095 a=b; fa=fb;
00096 b=u; fb=fu;
00097 }
00098 }
00099 else
00100 {
00101
00102 if (u<b)
00103 {
00104
00105 a=u; fa=fu;
00106 }
00107 else
00108 {
00109
00110 c=u; fc=fu;
00111 }
00112 }
00113
00114
00115 m = 0.5*(a+c);
00116 tol = EPS*vcl_fabs(b)+xtol;
00117 tol2 = 2*tol;
00118
00119 vcl_cout<<"Bracket: ("<<a<<','<<b<<','<<c<<") width: "<<c-a<<vcl_endl;
00120 }
00121
00122 f_at_last_minimum_ = fb;
00123 return b;
00124 }
00125
00126
00127
00128
00129
00130
00131 double vnl_brent_minimizer::minimize_given_bounds(double ax, double bx, double cx)
00132 {
00133 vnl_brent_minimizer_func f(*f_);
00134 double fb = f(bx);
00135
00136 return minimize_given_bounds_and_one_f(ax,bx,cx,fb);
00137 }
00138
00139
00140
00141
00142
00143
00144
00145 double vnl_brent_minimizer::minimize_given_bounds_and_one_f(double ax, double bx, double cx,
00146 double fb)
00147 {
00148
00149 assert(ax<bx);
00150 assert(bx<cx);
00151
00152
00153
00154 vnl_brent_minimizer_func f(*f_);
00155
00156 double x=bx;
00157 double w=x;
00158 double v=w;
00159 double u;
00160
00161
00162 double fx = fb;
00163 double fw = fx;
00164 double fv = fw;
00165 double fu;
00166
00167 double m = 0.5*(ax+cx);
00168 double tol = EPS*vcl_fabs(x)+xtol;
00169 double tol2 = 2*tol;
00170
00171 double d=0.0;
00172 double e=0.0;
00173
00174
00175 while (vcl_fabs(x-m)>(tol2-0.5*(cx-ax)))
00176 {
00177
00178 double p=0.0,q=0.0,r=0.0;
00179 if (vcl_fabs(e)>tol)
00180 {
00181
00182 r = (x-w)*(fx-fv);
00183 q = (x-v)*(fx-fw);
00184 p = (x-v)*q - (x-w)*r;
00185 q = 2*(q-r);
00186 if (q>0) p*=-1.0; else q*=-1.0;
00187 r = e; e = d;
00188 }
00189
00190 if (vcl_fabs(p)<vcl_fabs(0.5*q*r) &&
00191 p>(q*(ax-x)) && p<(q*(cx-x)) )
00192 {
00193
00194 d = p/q;
00195 u = x + d;
00196
00197
00198 if (u-ax<tol2 || cx-u<tol2) d = (x<m?tol:-tol);
00199 }
00200 else
00201 {
00202
00203 e = (x<m?cx:ax) - x;
00204 d = COMPL_GOLD * e;
00205 }
00206
00207
00208 if (vcl_fabs(d)>=tol)
00209 u = x+d;
00210 else
00211 {
00212 if (d>0) u=x+tol;
00213 else u=x-tol;
00214 }
00215
00216
00217 fu = f(u);
00218
00219
00220 if (fu<=fx)
00221 {
00222 if (u<x) cx=x; else ax=x;
00223 v=w; fv=fw;
00224 w=x; fw=fx;
00225 x=u; fx=fu;
00226 }
00227 else
00228 {
00229 if (u<x) ax=u; else cx=u;
00230 if (fu<=fw || w==x)
00231 {
00232 v=w; fv=fw;
00233 w=u; fw=fu;
00234 }
00235 else if (fu<=fv || v==x || v==w) { v=u; fv=fu; }
00236 }
00237
00238
00239 m = 0.5*(ax+cx);
00240 tol = EPS*vcl_fabs(x)+xtol;
00241 tol2 = 2*tol;
00242 }
00243
00244 f_at_last_minimum_ = fx;
00245 return x;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255 double vnl_brent_minimizer::minimize_given_bounds_and_all_f(double ax, double bx, double cx,
00256 double fa, double fb, double fc)
00257 {
00258
00259 assert(ax<bx);
00260 assert(bx<cx);
00261 assert(fb<fa);
00262 assert(fb<fc);
00263
00264
00265
00266 vnl_brent_minimizer_func f(*f_);
00267
00268 double x=bx;
00269 double fx = fb;
00270 double w, fw;
00271 double v, fv;
00272
00273 if (fa<fc) { w=ax; fw=fa; v=cx; fv=fc; }
00274 else { w=cx; fw=fc; v=ax; fv=fa; }
00275
00276 double u, fu;
00277
00278 double m = 0.5*(ax+cx);
00279 double tol = EPS*vcl_fabs(x)+xtol;
00280 double tol2 = 2*tol;
00281
00282 double d=vcl_min(bx-ax,cx-bx);
00283 double e=vcl_max(bx-ax,cx-bx);
00284
00285
00286 while (vcl_fabs(x-m)>(tol2-0.5*(cx-ax)))
00287 {
00288
00289 double p=0.0,q=0.0,r=0.0;
00290 if (vcl_fabs(e)>tol)
00291 {
00292
00293 r = (x-w)*(fx-fv);
00294 q = (x-v)*(fx-fw);
00295 p = (x-v)*q - (x-w)*r;
00296 q = 2*(q-r);
00297 if (q>0) p*=-1.0; else q*=-1.0;
00298 r = e; e = d;
00299 }
00300
00301 if (vcl_fabs(p)<vcl_fabs(0.5*q*r) &&
00302 p>(q*(ax-x)) && p<(q*(cx-x)) )
00303 {
00304
00305 d = p/q;
00306 u = x + d;
00307
00308
00309 if (u-ax<tol2 || cx-u<tol2) d = (x<m?tol:-tol);
00310 }
00311 else
00312 {
00313
00314 e = (x<m?cx:ax) - x;
00315 d = COMPL_GOLD * e;
00316 }
00317
00318
00319 if (vcl_fabs(d)>=tol)
00320 u = x+d;
00321 else
00322 {
00323 if (d>0) u=x+tol;
00324 else u=x-tol;
00325 }
00326
00327
00328 fu = f(u);
00329
00330
00331 if (fu<=fx)
00332 {
00333 if (u<x) cx=x; else ax=x;
00334 v=w; fv=fw;
00335 w=x; fw=fx;
00336 x=u; fx=fu;
00337 }
00338 else
00339 {
00340 if (u<x) ax=u; else cx=u;
00341 if (fu<=fw || w==x)
00342 {
00343 v=w; fv=fw;
00344 w=u; fw=fu;
00345 }
00346 else if (fu<=fv || v==x || v==w) { v=u; fv=fu; }
00347 }
00348
00349
00350 m = 0.5*(ax+cx);
00351 tol = EPS*vcl_fabs(x)+xtol;
00352 tol2 = 2*tol;
00353 }
00354
00355 f_at_last_minimum_ = fx;
00356 return x;
00357 }
00358
00359 double vnl_brent_minimizer::minimize(double x)
00360 {
00361 double ax=x-1.0;
00362 double cx=x+1.0;
00363 double fa,fx,fc;
00364 vnl_bracket_minimum(*f_, ax,x,cx, fa,fx,fc);
00365
00366 return minimize_given_bounds_and_all_f(ax,x,cx, fa,fx,fc);
00367 }