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