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
,
O2scl Sourceforge Project Page