00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef O2SCL_GSL_MIN_BRENT_H
00025 #define O2SCL_GSL_MIN_BRENT_H
00026
00027 #include <gsl/gsl_min.h>
00028 #include <o2scl/minimize.h>
00029
00030 #ifndef DOXYGENP
00031 namespace o2scl {
00032 #endif
00033
00034
00035
00036
00037
00038
00039
00040 template<class param_t, class func_t=funct<param_t> > class gsl_min_brent :
00041 public minimize<param_t,func_t>
00042 {
00043
00044 #ifndef DOXYGEN_INTERNAL
00045
00046 protected:
00047
00048
00049 func_t *uf;
00050
00051
00052 param_t *up;
00053
00054
00055
00056 double d, e, v, w, f_v, f_w;
00057
00058
00059
00060 int compute_f_values(func_t &func, double xminimum, double *fminimum,
00061 double xlower, double *flower, double xupper,
00062 double *fupper, param_t &pa) {
00063
00064 func(xlower,*flower,pa);
00065 func(xupper,*fupper,pa);
00066 func(xminimum,*fminimum,pa);
00067
00068 return gsl_success;
00069 }
00070
00071 #endif
00072
00073 public:
00074
00075
00076 double x_minimum;
00077
00078 double x_lower;
00079
00080 double x_upper;
00081
00082 double f_minimum;
00083
00084 double f_lower;
00085
00086 double f_upper;
00087
00088
00089 int set(func_t &func, double xmin, double lower, double upper,
00090 param_t &pa) {
00091
00092 double fmin, fl, fu;
00093 int status=compute_f_values(func,lower,&fl,xmin,&fmin,upper,&fu,pa);
00094
00095 status=set_with_values(func,xmin,fmin,lower,fl,upper,fu,pa);
00096
00097 return status;
00098 }
00099
00100
00101 int set_with_values(func_t &func, double xmin, double fmin,
00102 double lower, double fl, double upper,
00103 double fu, param_t &pa) {
00104
00105 if (lower > upper) {
00106 set_err_ret("Invalid interval in set_with_values().",gsl_einval);
00107 }
00108 if (xmin>=upper || xmin<=lower) {
00109 set_err_ret
00110 ("'xmin' was not inside interval set_with_values().",gsl_einval);
00111 }
00112 if (fmin >= fl || fmin>=fu) {
00113 set_err_ret
00114 ("Endpoints don't enclose minimum in set_with_values().",
00115 gsl_einval);
00116 }
00117
00118 x_lower=lower;
00119 x_minimum=xmin;
00120 x_upper=upper;
00121 f_lower=fl;
00122 f_minimum=fmin;
00123 f_upper=fu;
00124
00125 uf=&func;
00126 up=&pa;
00127
00128
00129 const double golden=0.3819660;
00130
00131 v=x_lower+golden*(x_upper-x_lower);
00132 w=v;
00133 d=0;
00134 e=0;
00135 func(v,f_v,pa);
00136 f_w=f_v;
00137
00138 return gsl_success;
00139 }
00140
00141
00142 int iterate() {
00143
00144 const double x_left= x_lower;
00145 const double x_right= x_upper;
00146
00147 const double z=x_minimum;
00148 double u, f_u;
00149 const double f_z=f_minimum;
00150
00151
00152 const double golden=0.3819660;
00153
00154 const double w_lower=(z-x_left);
00155 const double w_upper=(x_right-z);
00156
00157 const double tolerance= GSL_SQRT_DBL_EPSILON*fabs (z);
00158
00159 double p=0, q=0, r=0;
00160
00161 const double midpoint=0.5*(x_left+x_right);
00162
00163 if (fabs (e) > tolerance) {
00164
00165
00166 r=(z-w)*(f_z-f_v);
00167 q=(z-v)*(f_z-f_w);
00168 p=(z-v)*q-(z-w)*r;
00169 q=2*(q-r);
00170
00171 if (q > 0) {
00172 p=-p;
00173 } else {
00174 q=-q;
00175 }
00176
00177 r=e;
00178 e=d;
00179 }
00180
00181 if (fabs (p) < fabs (0.5*q*r) && p < q*w_lower &&
00182 p < q*w_upper) {
00183
00184 double t2=2*tolerance;
00185
00186 d=p / q;
00187 u=z+d;
00188
00189 if ((u-x_left) < t2 || (x_right-u) < t2)
00190 {
00191 d=(z < midpoint) ? tolerance : -tolerance ;
00192 }
00193 } else {
00194 e=(z < midpoint) ? x_right-z : -(z-x_left) ;
00195 d=golden*e;
00196 }
00197
00198
00199 if (fabs (d) >= tolerance) {
00200 u=z+d;
00201 } else {
00202 u=z+((d > 0) ? tolerance : -tolerance) ;
00203 }
00204
00205 (*uf)(u,f_u,*up);
00206
00207 if (f_u > f_z) {
00208
00209 if (u < z) {
00210 x_lower=u;
00211 f_lower=f_u;
00212 return gsl_success;
00213 } else {
00214 x_upper=u;
00215 f_upper=f_u;
00216 return gsl_success;
00217 }
00218
00219 } else if (f_u < f_z) {
00220
00221 if (u < z) {
00222 x_upper=z;
00223 f_upper=f_z;
00224 } else {
00225 x_lower=z;
00226 f_lower=f_z;
00227 }
00228
00229 v=w;
00230 w=z;
00231 f_v=f_w;
00232 f_w=f_z;
00233 x_minimum=u;
00234 f_minimum=f_u;
00235
00236 return gsl_success;
00237
00238 } else if (f_u <= f_w || w == z) {
00239
00240 v=w;
00241 f_v=f_w;
00242 w=u;
00243 f_w=f_u;
00244 return gsl_success;
00245
00246 } else if (f_u <= f_v || v == z || v == w) {
00247
00248 v=u;
00249 f_v=f_u;
00250 return gsl_success;
00251
00252 } else {
00253
00254 set_err_ret("Iteration failed in gsl_min_brent::iterate().",
00255 gsl_failure);
00256
00257 }
00258
00259 set_err("Sanity check failed in gsl_min_brent::iterate().",
00260 gsl_esanity);
00261 return gsl_esanity;
00262 }
00263
00264 virtual ~gsl_min_brent() {}
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 virtual int min_bkt(double &x2, double x1, double x3, double &fmin,
00277 param_t &pa, func_t &func) {
00278
00279 int status, iter=0;
00280 double a,b;
00281 double ytmp;
00282
00283 set(func,x2,x1,x3,pa);
00284
00285 do {
00286 iter++;
00287 status=iterate();
00288 if (status) break;
00289
00290 a=x_lower;
00291 b=x_upper;
00292 x2=x_minimum;
00293
00294 status=gsl_min_test_interval(a,b,this->tolx,this->tolf);
00295
00296 if (this->verbose>0) {
00297 func(x2,ytmp,pa);
00298 if (a*b<0.0) {
00299 if (a<b) {
00300 print_iter(x2,ytmp,iter,fabs(a-b)-this->tolf*a,this->tolx);
00301 } else {
00302 print_iter(x2,ytmp,iter,fabs(a-b)-this->tolf*b,this->tolx);
00303 }
00304 } else {
00305 print_iter(x2,ytmp,iter,fabs(a-b),this->tolx);
00306 }
00307 }
00308
00309 } while (status == gsl_continue && iter<this->ntrial);
00310
00311 this->last_ntrial=iter;
00312 func(x2,fmin,pa);
00313
00314 if (status==gsl_success) return 0;
00315
00316 return status;
00317 }
00318
00319
00320 virtual const char *type() { return "gsl_min_brent"; }
00321
00322 };
00323
00324 #ifndef DOXYGENP
00325 }
00326 #endif
00327
00328 #endif