Object-oriented Scientific Computing Library: Version 0.910
gsl_min_quad_golden.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 /*--------------------------------------------------------------------------*/
00024 /*                                                                          */
00025 /*  quad_golden.c                                                           */
00026 /*                                                                          */
00027 /*  Copyright (C) 2007 James Howse                                          */
00028 /*  Copyright (C) 2009 Brian Gough                                          */
00029 /*                                                                          */
00030 /* This program is free software; you can redistribute it and/or modify     */
00031 /* it under the terms of the GNU General Public License as published by     */
00032 /* the Free Software Foundation; either version 3 of the License, or (at    */
00033 /* your option) any later version.                                          */
00034 /*                                                                          */
00035 /* This program is distributed in the hope that it will be useful, but      */
00036 /* WITHOUT ANY WARRANTY; without even the implied warranty of               */
00037 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        */
00038 /* General Public License for more details.                                 */
00039 /*                                                                          */
00040 /* You should have received a copy of the GNU General Public License        */
00041 /*  along with this program; if not, write to the Free Software             */
00042 /*  Foundation, Inc., 51 Franklin Street, Fifth Floor,                      */
00043 /*  Boston, MA 02110-1301, USA.                                             */
00044 /*--------------------------------------------------------------------------*/
00045 #ifndef O2SCL_GSL_MIN_QUAD_GOLDEN_H
00046 #define O2SCL_GSL_MIN_QUAD_GOLDEN_H
00047 
00048 #include <gsl/gsl_min.h>
00049 #include <o2scl/minimize.h>
00050 
00051 #ifndef DOXYGENP
00052 namespace o2scl {
00053 #endif
00054    
00055   /** \brief Minimization of a function using the safeguarded step-length
00056       algorithm of Gill and Murray [GSL] 
00057 
00058       This class is unfinished. 
00059       
00060       Documentation from GSL:
00061       \verbatim
00062                                                                             
00063       This algorithm performs univariate minimization (i.e., line
00064       search). It requires only objective function values g(x) to
00065       compute the minimum. The algorithm maintains an interval of
00066       uncertainty [a,b] and a point x in the interval [a,b] such that
00067       a < x < b, and g(a) > g(x) and g(x) < g(b). The algorithm also
00068       maintains the three points with the smallest objective values x,
00069       v and w such that g(x) < g(v) < g(w). The algorithm terminates
00070       when max( x-a, b-x ) < 2(r |x| + t) where r and t are small
00071       positive reals. At a given iteration, the algorithm first fits a
00072       quadratic through the three points (x, g(x)), (v, g(v)) and (w,
00073       g(w)) and computes the location of the minimum u of the
00074       resulting quadratic. If u is in the interval [a,b] then g(u) is
00075       computed. If u is not in the interval [a,b], and either v < x
00076       and w < x, or v > x and w > x (i.e., the quadratic is
00077       extrapolating), then a point u' is computed using a safeguarding
00078       procedure and g(u') is computed. If u is not in the interval
00079       [a,b], and the quadratic is not extrapolating, then a point u''
00080       is computed using approximate golden section and g(u'') is
00081       computed. After evaluating g() at the appropriate new point, a,
00082       b, x, v, and w are updated and the next iteration is performed.
00083       The algorithm is based on work presented in the following
00084       references.
00085                                                                             
00086       Algorithms for Minimization without derivatives
00087       Richard Brent
00088       Prentice-Hall Inc., Englewood Cliffs, NJ, 1973
00089       
00090       Safeguarded Steplength Algorithms for Optimization using Descent Methods
00091       Philip E. Gill and Walter Murray
00092       Division of Numerical Analysis and Computing
00093       National Physical Laboratory, Teddington, United Kingdom
00094       NPL Report NAC 37, August 1974
00095       \endverbatim
00096 
00097       \future Take common elements of this and gsl_min_brent and
00098       move to a generic GSL minimizer type? 
00099   */
00100   template<class func_t=funct> class gsl_min_quad_golden : 
00101   public minimize_bkt<func_t> {
00102         
00103 #ifndef DOXYGEN_INTERNAL
00104         
00105     protected:
00106 
00107     /// The function
00108     func_t *uf;
00109       
00110     double x_prev_small;
00111     double f_prev_small;
00112     double x_small;
00113     double f_small;
00114     double step_size;
00115     double stored_step;
00116     double prev_stored_step;
00117     size_t num_iter;
00118 
00119     double rel_err_val;
00120     double abs_err_val;
00121     double golden_mean;
00122     double golden_ratio;
00123 
00124     /// Compute the function values at the various points
00125     int compute_f_values(func_t &func, double xminimum, double *fminimum, 
00126                          double xlower, double *flower, double xupper,
00127                          double *fupper) {
00128     
00129       *flower=func(xlower);
00130       *fupper=func(xupper);
00131       *fminimum=func(xminimum);
00132     
00133       return gsl_success;
00134     }
00135       
00136 #endif
00137       
00138     public:
00139  
00140     /// Location of minimum
00141     double x_minimum;
00142     /// Lower bound
00143     double x_lower;
00144     /// Upper bound
00145     double x_upper;
00146     /// Minimum value
00147     double f_minimum;
00148     /// Value at lower bound
00149     double f_lower;
00150     /// Value at upper bound
00151     double f_upper;
00152 
00153     gsl_min_quad_golden() {
00154       rel_err_val=1.0e-06;
00155       abs_err_val=1.0e-10;
00156       golden_mean=0.3819660112501052;
00157       golden_ratio=1.6180339887498950;
00158     }
00159       
00160     virtual ~gsl_min_quad_golden() {}
00161 
00162     /// Set the function and the initial bracketing interval
00163     int set(func_t &func, double xmin, double lower, double upper) {
00164       
00165       double fmin, fl, fu;
00166       int status=compute_f_values(func,lower,&fl,xmin,&fmin,upper,&fu);
00167     
00168       status=set_with_values(func,xmin,fmin,lower,fl,upper,fu);
00169 
00170       return status;
00171     }
00172 
00173     /** \brief Set the function, the initial bracketing interval,
00174         and the corresponding function values.
00175     */
00176     int set_with_values(func_t &func, double xmin, double fmin,
00177                         double lower, double fl, double upper,
00178                         double fu) {
00179 
00180       if (lower > upper) {
00181         std::string tmp=((std::string)"Invalid interval (lower > upper) ")+
00182         "in gsl_min_quad_golden::set_with_values().";
00183         O2SCL_ERR_RET(tmp.c_str(),gsl_einval);
00184       }
00185       if (xmin>=upper || xmin<=lower) {
00186         std::string tmp=((std::string)"'xmin' was not inside interval ")+
00187         "in gsl_min_quad_golden::set_with_values().";
00188         O2SCL_ERR_RET(tmp.c_str(),gsl_einval);
00189       }
00190       if (fmin>= fl || fmin>=fu) {
00191         std::string tmp=((std::string)"Endpoints don't enclose minimum ")+
00192         "in gsl_min_quad_golden::set_with_values().";
00193         O2SCL_ERR_RET(tmp.c_str(),gsl_einval);
00194       }
00195     
00196       x_lower=lower;
00197       x_minimum=xmin;
00198       x_upper=upper;
00199       f_lower=fl;
00200       f_minimum=fmin;
00201       f_upper=fu;
00202 
00203       uf=&func;
00204 
00205       x_prev_small=xmin;
00206       x_small=xmin;
00207       f_prev_small=fmin;
00208       f_small=fmin;
00209       
00210       step_size=0.0;
00211       stored_step=0.0;
00212       prev_stored_step=0.0;
00213       num_iter=0;
00214     
00215       return gsl_success;
00216     }
00217   
00218     /** \brief Perform an iteration
00219      */
00220     int iterate() {
00221 
00222       const double x_m=x_minimum;
00223       const double f_m=f_minimum;
00224 
00225       const double x_l=x_lower;
00226       const double x_u=x_upper;
00227   
00228       double quad_step_size=prev_stored_step;
00229   
00230       double x_trial;
00231       double x_eval, f_eval;
00232       
00233       double x_midpoint=0.5*(x_l+x_u);
00234       double tol=rel_err_val*fabs(x_m)+abs_err_val; 
00235 
00236       if (fabs(stored_step)-tol>-2.0*GSL_DBL_EPSILON) {
00237         
00238         // [GSL] Fit quadratic
00239         double c3=(x_m-x_small)*(f_m-f_prev_small);
00240         double c2=(x_m-x_prev_small)*(f_m-f_small);
00241         double c1=(x_m-x_prev_small)*c2-(x_m-x_small)*c3;
00242 
00243         c2=2.0*(c2-c3);
00244 
00245         // [GSL] if (c2!=0)
00246         if (fabs(c2)>GSL_DBL_EPSILON) {
00247           if (c2>0.0) {
00248             c1=-c1;
00249           }
00250           c2=fabs(c2);
00251           quad_step_size=c1/c2;
00252         } else {
00253           // [GSL] Handle case where c2 is nearly 0. Insure that the
00254           // line search will NOT take a quadratic interpolation step
00255           // in this iteration
00256           quad_step_size=stored_step;
00257         }
00258 
00259         prev_stored_step=stored_step;
00260         stored_step=step_size;
00261       }
00262 
00263       x_trial=x_m+quad_step_size;
00264 
00265       if (fabs(quad_step_size)<fabs(0.5*prev_stored_step) && 
00266           x_trial>x_l && x_trial<x_u) {
00267 
00268         // [GSL] Take quadratic interpolation step 
00269         step_size=quad_step_size;
00270 
00271         // [GSL] Do not evaluate function too close to x_l or x_u 
00272         if ((x_trial-x_l)<2.0*tol || (x_u-x_trial)<2.0*tol) {
00273           step_size=(x_midpoint >= x_m ? +1.0 : -1.0)*fabs(tol);
00274         }
00275         
00276       } else if ((x_small!=x_prev_small && x_small<x_m && 
00277                   x_prev_small<x_m) ||
00278                  (x_small!=x_prev_small && x_small>x_m && 
00279                   x_prev_small>x_m)) {
00280 
00281         // [GSL] Take safeguarded function comparison step
00282         double outside_interval, inside_interval;
00283 
00284         if (x_small<x_m) {
00285           outside_interval=x_l-x_m;
00286           inside_interval=x_u-x_m;
00287         } else {
00288           outside_interval=x_u-x_m;
00289           inside_interval=x_l-x_m;
00290         }
00291 
00292         if (fabs(inside_interval) <= tol) {
00293           // [GSL] Swap inside and outside intervals
00294           double tmp=outside_interval;
00295           outside_interval=inside_interval;
00296           inside_interval=tmp;
00297         }
00298 
00299         {
00300           double step=inside_interval;
00301           double scale_factor;
00302 
00303           if (fabs(outside_interval)<fabs(inside_interval)) {
00304             scale_factor=0.5*sqrt (-outside_interval/inside_interval);
00305           } else {
00306             scale_factor=(5.0/11.0)*
00307             (0.1-inside_interval/outside_interval);
00308           }
00309 
00310           stored_step=step;
00311           step_size=scale_factor*step;
00312         }
00313 
00314       } else {
00315 
00316         // [GSL] Take golden section step
00317         double step;
00318 
00319         if (x_m<x_midpoint) {
00320           step=x_u-x_m;
00321         } else {
00322           step=x_l-x_m;
00323         }
00324           
00325         stored_step=step;
00326         step_size=golden_mean*step;
00327 
00328       }
00329 
00330       // [GSL] Do not evaluate function too close to x_minimum 
00331       if (fabs(step_size)>tol) {
00332         x_eval=x_m+step_size;
00333       } else {
00334         x_eval=x_m+(step_size >= 0 ? +1.0 : -1.0)*fabs(tol);
00335       }
00336       
00337       
00338       // [GSL] Evaluate function at the new point x_eval
00339       f_eval=(*uf)(x_eval);
00340 
00341       // [GSL] Update {x,f}_lower, {x,f}_upper, {x,f}_prev_small, 
00342       // {x,f}_small, and {x,f}_minimum 
00343       if (f_eval <= f_m) {
00344         if (x_eval<x_m) {
00345           x_upper=x_m;
00346           f_upper=f_m;
00347         } else {
00348           x_lower=x_m;
00349           f_upper=f_m;
00350         }
00351 
00352         x_prev_small=x_small;
00353         f_prev_small=f_small;
00354 
00355         x_small=x_m;
00356         f_small=f_m;
00357 
00358         x_minimum=x_eval;
00359         f_minimum=f_eval;
00360       } else {
00361         if (x_eval<x_m) {
00362           x_lower=x_eval;
00363           f_lower=f_eval;
00364         } else {
00365           x_upper=x_eval;
00366           f_upper=f_eval;
00367         }
00368 
00369         if (f_eval <= f_small || fabs(x_small-x_m)<2.0*GSL_DBL_EPSILON) {
00370           x_prev_small=x_small;
00371           f_prev_small=f_small;
00372 
00373           x_small=x_eval;
00374           f_small=f_eval;
00375         } else if (f_eval <= f_prev_small ||
00376                    fabs(x_prev_small-x_m)<2.0*GSL_DBL_EPSILON ||
00377                    fabs(x_prev_small-x_small)<2.0*GSL_DBL_EPSILON) {
00378           x_prev_small=x_eval;
00379           f_prev_small=f_eval;
00380         }
00381       }
00382 
00383       // Update for next iteration
00384       num_iter++;
00385 
00386       return gsl_success;
00387     }
00388   
00389     /** \brief Calculate the minimum \c fmin of \c func 
00390         with \c x2 bracketed between \c x1 and \c x3.
00391 
00392         Note that this algorithm requires that the initial guess
00393         already brackets the minimum, i.e. \f$ x_1<x_2<x_3 \f$,
00394         \f$ f(x_1)>f(x_2) \f$ and \f$ f(x_3)>f(x_2) \f$. This is
00395         different from \ref cern_minimize, where the initial value
00396         of the first parameter to cern_minimize::min_bkt() is
00397         ignored.
00398     */
00399     virtual int min_bkt(double &x2, double x1, double x3, double &fmin,
00400                         func_t &func) {
00401     
00402       int status, iter=0;
00403     
00404       this->last_conv=0;
00405 
00406       int rx=set(func,x2,x1,x3);
00407       if (rx!=0) {
00408         O2SCL_ERR2_RET("Function set() failed in ",
00409                        "gsl_min_quad_golden::min_bkt().",rx);
00410       }
00411         
00412       do {
00413         iter++;
00414         status=iterate();
00415         x2=x_minimum;
00416         if (status) {
00417           // This should never actually happen in the current
00418           // version, but we retain it for now
00419           this->last_conv=gsl_efailed;
00420           O2SCL_CONV2_RET("Function iterate() failed in gsl_min_",
00421                           "quad_golden::min_bkt().",status,this->err_nonconv);
00422           break;
00423         }
00424           
00425         status=gsl_min_test_interval(x_lower,x_upper,this->tol_abs,
00426                                      this->tol_rel);
00427         if (status>0) {
00428           // The function gsl_min_test_interval() fails if the
00429           // tolerances are negative or if the lower bound is larger
00430           // than the upper bound
00431           std::string s="Function gsl_min_test_interval() failed in ";
00432           s+="gsl_min_quad_golden::min_bkt().";
00433           O2SCL_ERR(s.c_str(),status);
00434         }
00435           
00436         if (this->verbose>0) {
00437           if (x_lower*x_upper<0.0) {
00438             if (x_lower<x_upper) {
00439               print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)-
00440                          this->tol_rel*x_lower,this->tol_abs,
00441                          "gsl_min_quad_golden");
00442             } else {
00443               print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)-
00444                          this->tol_rel*x_upper,this->tol_abs,
00445                          "gsl_min_quad_golden");
00446             }
00447           } else {
00448             print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper),this->tol_abs,
00449                        "gsl_min_quad_golden");
00450           }
00451         }
00452         
00453       } while (status == gsl_continue && iter<this->ntrial);
00454       
00455       if (iter>=this->ntrial) {
00456         this->last_conv=gsl_emaxiter;
00457         O2SCL_CONV2_RET("Exceeded maximum number of ",
00458                         "iterations in gsl_min_quad_golden::min_bkt().",
00459                         o2scl::gsl_emaxiter,this->err_nonconv);
00460       }
00461 
00462       this->last_ntrial=iter;
00463       fmin=f_minimum;
00464         
00465       return status;
00466     }
00467   
00468     /// Return string denoting type ("gsl_min_quad_golden")
00469     virtual const char *type() { return "gsl_min_quad_golden"; }
00470       
00471   };
00472 
00473 #ifndef DOXYGENP
00474 }
00475 #endif
00476 
00477 #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.