Object-oriented Scientific Computing Library: Version 0.910
gsl_min_brent.h
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006-2012, 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 /* min/brent.c
00024  * 
00025  * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough
00026  * 
00027  * This program is free software; you can redistribute it and/or modify
00028  * it under the terms of the GNU General Public License as published by
00029  * the Free Software Foundation; either version 3 of the License, or (at
00030  * your option) any later version.
00031  * 
00032  * This program is distributed in the hope that it will be useful, but
00033  * WITHOUT ANY WARRANTY; without even the implied warranty of
00034  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00035  * General Public License for more details.
00036  * 
00037  * You should have received a copy of the GNU General Public License
00038  * along with this program; if not, write to the Free Software
00039  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
00040  * 02110-1301, USA.
00041  */
00042 #ifndef O2SCL_GSL_MIN_BRENT_H
00043 #define O2SCL_GSL_MIN_BRENT_H
00044 
00045 #include <gsl/gsl_min.h>
00046 #include <o2scl/minimize.h>
00047 
00048 #ifndef DOXYGENP
00049 namespace o2scl {
00050 #endif
00051    
00052   /** \brief One-dimensional minimization using Brent's method (GSL)
00053 
00054       The minimization in the function min_bkt() is complete when the
00055       bracketed interval is smaller than 
00056       \f$ \mathrm{tol} = \mathrm{tol\_abs} + \mathrm{tol\_rel} \cdot
00057       \mathrm{min} \f$, where \f$ \mathrm{min} = 
00058       \mathrm{min}(|\mathrm{lower}|,|\mathrm{upper}|) \f$.
00059 
00060       Note that this algorithm requires that the initial guess
00061       already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$,
00062       \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is
00063       different from \ref cern_minimize, where the initial value
00064       of the first parameter to cern_minimize::min_bkt() is
00065       ignored.
00066 
00067       The set functions throw an error if the initial bracket is not
00068       correctly specified. The function \ref iterate() never calls the
00069       error handler. The function min_bkt() calls the error handler if
00070       the tolerances are negative or if the number of iterations is
00071       insufficient to give the specified tolerance.
00072 
00073       Setting \ref minimize::err_nonconv to false will force
00074       min_bkt() not to call the error handler when the number of
00075       iterations is insufficient.
00076 
00077       Note that if there are more than 1 local minima in the specified
00078       interval, there is no guarantee that this method will find the
00079       global minimum.
00080 
00081       See also \ref gsl_root_brent for a similar algorithm
00082       applied as a solver rather than a minimizer.
00083 
00084       \note There was a bug in this minimizer which was fixed for
00085       GSL-1.11 which has also been fixed here. 
00086   */
00087   template<class func_t=funct> class gsl_min_brent : 
00088   public minimize_bkt<func_t> {
00089     
00090 #ifndef DOXYGEN_INTERNAL
00091     
00092     protected:
00093 
00094     /// The function
00095     func_t *uf;
00096       
00097     /// \name Temporary storage
00098     //@{
00099     double d, e, v, w, f_v, f_w;
00100     //@}
00101   
00102     /// Compute the function values at the various points
00103     int compute_f_values(func_t &func, double xminimum, double *fminimum, 
00104                          double xlower, double *flower, double xupper,
00105                          double *fupper) {
00106     
00107       *flower=func(xlower);
00108       *fupper=func(xupper);
00109       *fminimum=func(xminimum);
00110     
00111       return gsl_success;
00112     }
00113       
00114 #endif
00115       
00116     public:
00117  
00118     /// Location of minimum
00119     double x_minimum;
00120     /// Lower bound
00121     double x_lower;
00122     /// Upper bound
00123     double x_upper;
00124     /// Minimum value
00125     double f_minimum;
00126     /// Value at lower bound
00127     double f_lower;
00128     /// Value at upper bound
00129     double f_upper;
00130 
00131     gsl_min_brent() {
00132     }
00133       
00134     virtual ~gsl_min_brent() {}
00135 
00136     /// Set the function and the initial bracketing interval
00137     int set(func_t &func, double xmin, double lower, double upper) {
00138       
00139       double fmin, fl, fu;
00140       int status=compute_f_values(func,lower,&fl,xmin,&fmin,upper,&fu);
00141     
00142       status=set_with_values(func,xmin,fmin,lower,fl,upper,fu);
00143 
00144       return status;
00145     }
00146 
00147     /** \brief Set the function, the initial bracketing interval,
00148         and the corresponding function values.
00149     */
00150     int set_with_values(func_t &func, double xmin, double fmin,
00151                         double lower, double fl, double upper,
00152                         double fu) {
00153 
00154       if (lower > upper) {
00155         std::string tmp=((std::string)"Invalid interval (lower > upper) ")+
00156         "in gsl_min_brent::set_with_values().";
00157         O2SCL_ERR_RET(tmp.c_str(),gsl_einval);
00158       }
00159       if (xmin>=upper || xmin<=lower) {
00160         std::string tmp=((std::string)"'xmin' was not inside interval ")+
00161         "in gsl_min_brent::set_with_values().";
00162         O2SCL_ERR_RET(tmp.c_str(),gsl_einval);
00163       }
00164       if (fmin>=fl || fmin>=fu) {
00165         std::string tmp=((std::string)"Endpoints don't enclose minimum ")+
00166         "in gsl_min_brent::set_with_values().";
00167         O2SCL_ERR_RET(tmp.c_str(),gsl_einval);
00168       }
00169     
00170       x_lower=lower;
00171       x_minimum=xmin;
00172       x_upper=upper;
00173       f_lower=fl;
00174       f_minimum=fmin;
00175       f_upper=fu;
00176 
00177       uf=&func;
00178 
00179       /* golden=(3-sqrt(5))/2 */
00180       const double golden=0.3819660;      
00181     
00182       v=x_lower+golden*(x_upper-x_lower);
00183       w=v;
00184       d=0;
00185       e=0;
00186       f_v=func(v);
00187       f_w=f_v;
00188     
00189       return gsl_success;
00190     }
00191   
00192     /** \brief Perform an iteration
00193         
00194         \future It looks like x_left and x_right can be removed. Also,
00195         it would be great to replace the one-letter variable names
00196         with something more meaningful.
00197      */
00198     int iterate() {
00199     
00200       const double x_left=x_lower;
00201       const double x_right=x_upper;
00202         
00203       const double z=x_minimum;
00204       double u, f_u;
00205       const double f_z=f_minimum;
00206         
00207       /* golden=(3-sqrt(5))/2 */
00208       const double golden=0.3819660;      
00209     
00210       const double w_lower=(z-x_left);
00211       const double w_upper=(x_right-z);
00212     
00213       const double tolerance=GSL_SQRT_DBL_EPSILON*fabs(z);
00214     
00215       double p=0, q=0, r=0;
00216     
00217       const double midpoint=0.5*(x_left+x_right);
00218     
00219       if (fabs (e) > tolerance) {
00220         /* fit parabola */
00221           
00222         r=(z-w)*(f_z-f_v);
00223         q=(z-v)*(f_z-f_w);
00224         p=(z-v)*q-(z-w)*r;
00225         q=2*(q-r);
00226           
00227         if (q > 0) {
00228           p=-p;
00229         } else {
00230           q=-q;
00231         }
00232           
00233         r=e;
00234         e=d;
00235       }
00236 
00237       if (fabs (p) < fabs (0.5*q*r) && p < q*w_lower && 
00238           p < q*w_upper) {
00239 
00240         double t2=2*tolerance;
00241           
00242         d=p / q;
00243         u=z+d;
00244           
00245         if ((u-x_left) < t2 || (x_right-u) < t2) {
00246           d=(z < midpoint) ? tolerance : -tolerance ;
00247         }
00248 
00249       } else {
00250 
00251         e=(z < midpoint) ? x_right-z : -(z-x_left) ;
00252         d=golden*e;
00253 
00254       }
00255     
00256     
00257       if (fabs (d) >= tolerance) {
00258         u=z+d;
00259       } else {
00260         u=z+((d > 0) ? tolerance : -tolerance);
00261       }
00262         
00263       f_u=(*uf)(u);
00264       
00265       if (f_u<=f_z) {
00266 
00267         if (u<z) {
00268 
00269           x_upper=z;
00270           f_upper=f_z;
00271 
00272         } else {
00273 
00274           x_lower=z;
00275           f_lower=f_z;
00276 
00277         }
00278 
00279         v=w;
00280         f_v=f_w;
00281         w=z;
00282         f_w=f_z;
00283         x_minimum=u;
00284         f_minimum=f_u;
00285 
00286         return gsl_success;
00287 
00288       } else {
00289 
00290         if (u<z) {
00291 
00292           x_lower=u;
00293           f_lower=f_u;
00294 
00295         } else {
00296 
00297           x_upper=u;
00298           f_upper=f_u;
00299 
00300         }
00301 
00302         if (f_u<=f_w || w==z) {
00303 
00304           v=w;
00305           f_v=f_w;
00306           w=u;
00307           f_w=f_u;
00308           return gsl_success;
00309 
00310         } else if (f_u<=f_v || v==z || v==w) {
00311 
00312           v=u;
00313           f_v=f_u;
00314           return gsl_success;
00315         }
00316 
00317       }
00318 
00319       return gsl_success;
00320     }
00321   
00322     /** \brief Calculate the minimum \c fmin of \c func 
00323         with \c x2 bracketed between \c x1 and \c x3.
00324 
00325         Note that this algorithm requires that the initial guess
00326         already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$,
00327         \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is
00328         different from \ref cern_minimize, where the initial value
00329         of the first parameter to cern_minimize::min_bkt() is
00330         ignored.
00331     */
00332     virtual int min_bkt(double &x2, double x1, double x3, double &fmin,
00333                         func_t &func) {
00334     
00335       int status, iter=0;
00336     
00337       this->last_conv=0;
00338 
00339       int rx=set(func,x2,x1,x3);
00340       if (rx!=0) {
00341         O2SCL_ERR2_RET("Function set() failed in ",
00342                        "gsl_min_brent::min_bkt().",rx);
00343       }
00344         
00345       do {
00346         iter++;
00347         status=iterate();
00348         x2=x_minimum;
00349         if (status) {
00350           // This should never actually happen in the current
00351           // version, but we retain it for now
00352           this->last_conv=gsl_efailed;
00353           O2SCL_CONV2_RET("Function iterate() failed in gsl_min_",
00354                           "brent::min_bkt().",status,this->err_nonconv);
00355           break;
00356         }
00357           
00358         status=gsl_min_test_interval(x_lower,x_upper,this->tol_abs,
00359                                      this->tol_rel);
00360         if (status>0) {
00361           // The function gsl_min_test_interval() fails if the
00362           // tolerances are negative or if the lower bound is larger
00363           // than the upper bound
00364           std::string s="Function gsl_min_test_interval() failed in ";
00365           s+="gsl_min_brent::min_bkt().";
00366           O2SCL_ERR(s.c_str(),status);
00367         }
00368           
00369         if (this->verbose>0) {
00370           if (x_lower*x_upper<0.0) {
00371             if (x_lower<x_upper) {
00372               print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)-
00373                          this->tol_rel*x_lower,this->tol_abs,"gsl_min_brent");
00374             } else {
00375               print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)-
00376                          this->tol_rel*x_upper,this->tol_abs,"gsl_min_brent");
00377             }
00378           } else {
00379             print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper),this->tol_abs,
00380                        "gsl_min_brent");
00381           }
00382         }
00383       
00384       } while (status == gsl_continue && iter<this->ntrial);
00385       
00386       if (iter>=this->ntrial) {
00387         this->last_conv=gsl_emaxiter;
00388         O2SCL_CONV2_RET("Exceeded maximum number of ",
00389                         "iterations in gsl_min_brent::min_bkt().",
00390                         o2scl::gsl_emaxiter,this->err_nonconv);
00391       }
00392 
00393       this->last_ntrial=iter;
00394       fmin=f_minimum;
00395         
00396       return status;
00397     }
00398   
00399     /// Return string denoting type ("gsl_min_brent")
00400     virtual const char *type() { return "gsl_min_brent"; }
00401       
00402     };
00403 
00404 #ifndef DOXYGENP
00405 }
00406 #endif
00407 
00408 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.