gsl_min_brent.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 2008, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
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       \brief One-dimensional minimization (GSL)
00036 
00037       \todo Simplify temporary storage and document 
00038       stopping conditions.
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       /// The function
00049       func_t *uf;
00050       
00051       /// The parameters
00052       param_t *up;
00053       
00054       /// \name Temporary storage
00055       //@{
00056       double d, e, v, w, f_v, f_w;
00057       //@}
00058   
00059       /// Compute the function values at the various points
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       /// Location of minimum
00076       double x_minimum;
00077       /// Lower bound
00078       double x_lower;
00079       /// Upper mound
00080       double x_upper;
00081       /// Minimum value
00082       double f_minimum;
00083       /// Value at lower bound
00084       double f_lower;
00085       /// Value at upper bound
00086       double f_upper;
00087 
00088       /// Set the function to be minimized and the initial brackeing interval
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       /// Set the function to be minimized and the initial brackeing interval
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         /* golden=(3-sqrt(5))/2 */
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       /// Perform an iteration
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         /* golden=(3-sqrt(5))/2 */
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           /* fit parabola */
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       /** \brief Calculate the minimum \c min of \c func 
00267           with \c x2 bracketed between \c x1 and \c x3.
00268 
00269           Note that this algorithm requires that the initial guess
00270           already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$,
00271           \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is
00272           different from \ref cern_minimize, where the initial value
00273           of the first parameter to cern_minimize::min_bkt() is
00274           ignored.
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       /// Return string denoting type ("gsl_min_brent")
00320       virtual const char *type() { return "gsl_min_brent"; }
00321       
00322     };
00323 
00324 #ifndef DOXYGENP
00325 }
00326 #endif
00327 
00328 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page