cern_minimize.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 #ifndef O2SCL_CERN_MINIMIZE_H
00024 #define O2SCL_CERN_MINIMIZE_H
00025 
00026 #include <o2scl/minimize.h>
00027 
00028 #ifndef DOXYGENP
00029 namespace o2scl {
00030 #endif
00031 
00032   /** 
00033       \brief One-dimensional minimization (CERNLIB)
00034 
00035       The golden section search is applied in the interval  \f$ (a,b) \f$ 
00036       using a fixed number \f$ n \f$ of function evaluations where 
00037       \f[
00038       n=\left[ 2.08 \ln(|a-b|/\mathrm{tolx})+\frac{1}{2}\right]+1 
00039       \f]
00040       
00041       The accuracy depends on the function. A choice of \f$
00042       \mathrm{tolx}>10^{-8} \f$ usually results in a relative error of
00043       $x$ which is smaller than or of the order of \f$ \mathrm{tolx}
00044       \f$ .
00045       
00046       This routine strictly searches the interval \f$ (a,b) \f$ . If
00047       the function is nowhere flat in this interval, then min_bkt()
00048       will return either \f$ a \f$ or \f$ b \f$ and \ref min_type
00049       is set to 1.
00050       
00051       \note The number of function evaluations can be quite large if
00052       multi_min::tolx is sufficiently small. If multi_min::tolx is
00053       exactly zero, then \f$ 10^{-8} \f$ will be used instead.
00054 
00055       Based on the CERNLIB routines RMINFC and DMINFC, which was 
00056       based on \ref Fletcher87, and \ref Krabs83 and is documented at
00057       http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/d503/top.html
00058   */
00059 #ifdef DOXYGENP
00060   template<class param_t, class func_t=funct<param_t> > class cern_minimize : 
00061   public minimize_bkt
00062 #else
00063   template<class param_t, class func_t=funct<param_t> > class cern_minimize : 
00064   public minimize_bkt<param_t,func_t> 
00065 #endif
00066     {
00067       
00068 #ifndef DOXGYEN_INTERNAL
00069 
00070       protected:
00071 
00072       /// C analog of Fortran's "Nearest integer" function 
00073       inline int nint(double x) {
00074         if (x<0.0) return ((int)(x-0.5));
00075         else return ((int)(x+0.5));
00076       }
00077     
00078 #endif      
00079 
00080     public:
00081       
00082       cern_minimize() {
00083         delta_set=false;
00084         min_type=0;
00085       }
00086     
00087       /** 
00088           \brief Calculate the minimum \c min of \c func between
00089           \c a and \c b
00090           
00091           The initial value of \c x is ignored.
00092           
00093           If there is no minimum in the given interval, then on exit
00094           \c x will be equal to either \c a or \c b and \ref min_type
00095           will be set to 1 instead of zero. The error handler is not
00096           called, as this need not be interpreted as an error.
00097       */
00098       virtual int min_bkt(double &x, double a, double b, double &y,
00099                           param_t &pa, func_t &func) {
00100       
00101         // The square root of 5
00102         static const double w5=2.23606797749979;
00103         static const double hv=(3.0-w5)/2.0, hw=(w5-1.0)/2.0;
00104         double c, d, v=0.0, fv, w=0.0, fw, h;
00105       
00106         if (!delta_set) delta=10.0*this->tolx;
00107         
00108         int n=-1;
00109         if (this->tolx==0.0) {
00110           n=nint(2.0*log(fabs((a-b)/1.0e-8)));
00111         } else {
00112           if (a!=b) n=nint(2.0*log(fabs((a-b)/this->tolx)));
00113         }
00114         this->last_ntrial=n;
00115         c=a;
00116         d=b;
00117         if (a>b) {
00118           c=b;
00119           d=a;
00120         }
00121         bool llt=true, lge=true;
00122       
00123         // This is never an infinite loop so long as 'n' is finite. We
00124         // should maybe check somehow that 'n' is not too large
00125         while (true) {
00126           h=d-c;
00127           if (this->verbose>0) {
00128             x=(c+d)/2.0;
00129             func(x,y,pa);
00130             this->print_iter(x,y,this->last_ntrial-n,0.0,this->tolx);
00131           }
00132           if (n<0) {
00133             x=(c+d)/2.0;
00134             func(x,y,pa);
00135             if ((fabs(x-a)>delta && fabs(x-b)>delta)) min_type=0;
00136             min_type=1;
00137             return 0;
00138           }
00139           if (llt) {
00140             v=c+hv*h;
00141             func(v,fv,pa);
00142           }
00143           if (lge) {
00144             w=c+hw*h;
00145             func(w,fw,pa);
00146           }
00147           if (fv<fw) {
00148             llt=true;
00149             lge=false;
00150             d=w;
00151             w=v;
00152             fw=fv;
00153           } else {
00154             llt=false;
00155             lge=true;
00156             c=v;
00157             v=w;
00158             fv=fw;
00159           }
00160           n--;
00161         }
00162 
00163         O2SCL_ERR("Failed sanity check in cern_minimize::min_bkt().",
00164                   gsl_esanity);
00165         return gsl_esanity;
00166       }
00167     
00168       /** 
00169           \brief Set the value of  \f$ \delta \f$ 
00170           
00171           If this is not called before min_bkt() is used, then the
00172           suggested value \f$ \delta=10 \mathrm{tolx} \f$ is used.
00173       */
00174       int set_delta(double d) {
00175         if (d>0.0) {
00176           delta=d;
00177           delta_set=true;
00178         }
00179         return 0;
00180       }
00181     
00182       /// Return string denoting type ("cern_minimize")
00183       virtual const char *type() { return "cern_minimize"; }
00184 
00185       /// Type of minimum found
00186       int min_type;
00187 
00188     protected:
00189 
00190 #ifndef DOXYGEN_INTERNAL
00191 
00192       /// The value of delta as specified by the user
00193       double delta;
00194 
00195       /// True if the value of delta has been set
00196       bool delta_set;
00197 
00198 #endif
00199 
00200     };
00201 
00202 #ifndef DOXYGENP
00203 }
00204 #endif
00205 
00206 #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