cern_minimize.h

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

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