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 template<class param_t, class func_t=funct<param_t> > class cern_minimize : 00060 public minimize<param_t,func_t> 00061 { 00062 00063 #ifndef DOXGYEN_INTERNAL 00064 00065 protected: 00066 00067 /// C analog of Fortran's "Nearest integer" function 00068 inline int nint(double x) { 00069 if (x<0.0) return ((int)(x-0.5)); 00070 else return ((int)(x+0.5)); 00071 } 00072 00073 #endif 00074 00075 public: 00076 00077 cern_minimize() { 00078 this->over_bkt=true; 00079 delta_set=false; 00080 min_type=0; 00081 } 00082 00083 /** 00084 \brief Calculate the minimum \c min of \c func between 00085 \c a and \c b 00086 00087 The initial value of \c x is ignored. 00088 00089 If there is no minimum in the given interval, then on exit 00090 \c x will be equal to either \c a or \c b and \ref min_type 00091 will be set to 1 instead of zero. The error handler is not 00092 called, as this need not be interpreted as an error. 00093 */ 00094 virtual int min_bkt(double &x, double a, double b, double &y, 00095 param_t &pa, func_t &func) { 00096 00097 // The square root of 5 00098 static const double w5=2.23606797749979; 00099 static const double hv=(3.0-w5)/2.0, hw=(w5-1.0)/2.0; 00100 double c, d, v=0.0, fv, w=0.0, fw, h; 00101 00102 if (!delta_set) delta=10.0*this->tolx; 00103 00104 int n=-1; 00105 if (this->tolx==0.0) { 00106 n=nint(2.0*log(fabs((a-b)/1.0e-8))); 00107 } else { 00108 if (a!=b) n=nint(2.0*log(fabs((a-b)/this->tolx))); 00109 } 00110 this->last_ntrial=n; 00111 c=a; 00112 d=b; 00113 if (a>b) { 00114 c=b; 00115 d=a; 00116 } 00117 bool llt=true, lge=true; 00118 00119 // This is never an infinite loop so long as 'n' is finite. We 00120 // should maybe check somehow that 'n' is not too large 00121 while (true) { 00122 h=d-c; 00123 if (this->verbose>0) { 00124 x=(c+d)/2.0; 00125 func(x,y,pa); 00126 this->print_iter(x,y,this->last_ntrial-n,0.0,this->tolx); 00127 } 00128 if (n<0) { 00129 x=(c+d)/2.0; 00130 func(x,y,pa); 00131 if ((fabs(x-a)>delta && fabs(x-b)>delta)) min_type=0; 00132 min_type=1; 00133 return 0; 00134 } 00135 if (llt) { 00136 v=c+hv*h; 00137 func(v,fv,pa); 00138 } 00139 if (lge) { 00140 w=c+hw*h; 00141 func(w,fw,pa); 00142 } 00143 if (fv<fw) { 00144 llt=true; 00145 lge=false; 00146 d=w; 00147 w=v; 00148 fw=fv; 00149 } else { 00150 llt=false; 00151 lge=true; 00152 c=v; 00153 v=w; 00154 fv=fw; 00155 } 00156 n--; 00157 } 00158 00159 set_err("Failed sanity check in cern_minimize::min_bkt().", 00160 gsl_esanity); 00161 return gsl_esanity; 00162 } 00163 00164 /** 00165 \brief Set the value of \f$ \delta \f$ 00166 00167 If this is not called before min_bkt() is used, then the 00168 suggested value \f$ \delta=10 \mathrm{tolx} \f$ is used. 00169 */ 00170 int set_delta(double d) { 00171 if (d>0.0) { 00172 delta=d; 00173 delta_set=true; 00174 } 00175 return 0; 00176 } 00177 00178 /// Return string denoting type ("cern_minimize") 00179 virtual const char *type() { return "cern_minimize"; } 00180 00181 /// Type of minimum found 00182 int min_type; 00183 00184 protected: 00185 00186 #ifndef DOXYGEN_INTERNAL 00187 00188 /// The value of delta as specified by the user 00189 double delta; 00190 00191 /// True if the value of delta has been set 00192 bool delta_set; 00193 00194 #endif 00195 00196 }; 00197 00198 #ifndef DOXYGENP 00199 } 00200 #endif 00201 00202 #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