00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 2009, 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 /* siman/siman.c 00024 * 00025 * Copyright (C) 2007 Brian Gough 00026 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Mark Galassi 00027 * 00028 * This program is free software; you can redistribute it and/or modify 00029 * it under the terms of the GNU General Public License as published by 00030 * the Free Software Foundation; either version 3 of the License, or (at 00031 * your option) any later version. 00032 * 00033 * This program is distributed in the hope that it will be useful, but 00034 * WITHOUT ANY WARRANTY; without even the implied warranty of 00035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00036 * General Public License for more details. 00037 * 00038 * You should have received a copy of the GNU General Public License 00039 * along with this program; if not, write to the Free Software 00040 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00041 * 02110-1301, USA. 00042 */ 00043 #ifndef O2SCL_GSL_ANNEAL_H 00044 #define O2SCL_GSL_ANNEAL_H 00045 00046 #include <gsl/gsl_rng.h> 00047 #include <gsl/gsl_siman.h> 00048 #include <o2scl/sim_anneal.h> 00049 00050 #ifndef DOXYGENP 00051 namespace o2scl { 00052 #endif 00053 00054 /** 00055 \brief Multidimensional minimization by simulated annealing (GSL) 00056 00057 This class is a modification of simulated annealing as 00058 implemented in GSL in the function \c gsl_siman_solve(). It acts 00059 as a generic multidimensional minimizer for any function given a 00060 generic temperature schedule specified by the user. 00061 00062 The simulated annealing algorithm proposes a displacement of one 00063 coordinate of the previous point by 00064 \f[ 00065 x_{i,\mathrm{new}} = \mathrm{step\_size}_i 00066 (2 u_i - 1) + x_{i,\mathrm{old}} 00067 \f] 00068 where the \f$u_i\f$ are random numbers between 0 and 1. The 00069 displacement is accepted or rejected based on the Metropolis 00070 method. The random number generator is set in the parent, 00071 sim_anneal. 00072 00073 There are a large variety of strategies for choosing the 00074 temperature evolution. To offer the user the largest possible 00075 flexibility, the temperature evolution is controlled by a 00076 the virtual functions start() and next() which can be freely 00077 changed by creating a child class which overwrites these 00078 functions. 00079 00080 The default behavior is as follows: Initially, the step sizes 00081 are chosen to be 1.0 (or whatever was recently specified in \ref 00082 set_step() ) and the temperature to be \ref T_start (default 00083 1.0). Each iteration decreases the temperature by a factor of 00084 \ref T_dec (default 1.5) for each step, and the minimizer is 00085 finished when the next decrease would bring the temperature 00086 below multi_min::tolx. If none of the multi_min::ntrial steps in 00087 a particular iteration changes the value of the minimum, and the 00088 step sizes are greater than \ref min_step_ratio (default 100) 00089 times multi_min::tolx, then the step sizes are decreased by a 00090 factor of \ref step_dec (default 1.5) for the next iteration. 00091 00092 If \ref multi_min::verbose is greater than zero, then \ref 00093 mmin() will print out information and/or request a keypress 00094 after the function iterations for each temperature. 00095 00096 An example demonstrating the usage of this class is given in 00097 <tt>examples/ex_anneal.cpp</tt> and in the \ref ex_anneal_sect . 00098 00099 The form of the user-specified function is as in \ref 00100 multi_funct has a "function value" which is the value of the 00101 function (given in the third argument as a number of type \c 00102 double), and a "return value" (the integer return value). The 00103 initial function evaluation which is performed at the 00104 user-specified initial guess must give 0 as the return value. 00105 If subsequent function evaluations have a non-zero return value, 00106 then the resulting function value of ignored. 00107 00108 This class thus can sometimes handle constrained minimization 00109 problems. If the user ensures that the function's return 00110 value is non-zero when the function is evaluated outside 00111 the allowed region, the minimizer will not accept any 00112 steps which take the minimizer outside the allowed region. 00113 Note that this should be done with care, however, as this 00114 approach may cause convergence problems with sufficiently 00115 difficult functions or constraints. 00116 00117 See also a multi-threaded version of this class in \ref 00118 anneal_mt. 00119 00120 \future There's x0, old_x, new_x, best_x, and x? There's probably 00121 some duplication here which could be avoided. 00122 00123 \future 00124 - Implement a more general simulated annealing routine 00125 which would allow the solution of discrete problems like the 00126 Traveling Salesman problem. 00127 \comment 00128 This could probably be done just by creating a parent abstract 00129 base class which doesn't have any reference to step() and 00130 step_vec. 00131 \endcomment 00132 00133 */ 00134 template<class param_t, class func_t=multi_funct<param_t>, 00135 class vec_t=ovector_base, class alloc_vec_t=ovector, 00136 class alloc_t=ovector_alloc, class rng_t=gsl_rnga> class gsl_anneal : 00137 public sim_anneal<param_t,func_t,vec_t,rng_t> { 00138 public: 00139 00140 gsl_anneal() { 00141 boltz=1.0; 00142 step_vec.allocate(1); 00143 step_vec[0]=1.0; 00144 T_start=1.0; 00145 T_dec=1.5; 00146 step_dec=1.5; 00147 min_step_ratio=100.0; 00148 } 00149 00150 virtual ~gsl_anneal() { 00151 step_vec.free(); 00152 } 00153 00154 /** \brief Calculate the minimum \c fmin of \c func w.r.t the 00155 array \c x0 of size \c nvar. 00156 */ 00157 virtual int mmin(size_t nvar, vec_t &x0, double &fmin, param_t &pa, 00158 func_t &func) 00159 { 00160 00161 if (nvar==0) { 00162 O2SCL_ERR2_RET("Tried to minimize over zero variables ", 00163 " in gsl_anneal::mmin().",gsl_einval); 00164 } 00165 00166 fmin=0.0; 00167 00168 allocate(nvar); 00169 00170 double E, new_E, best_E, T, old_E; 00171 int i, iter=0; 00172 size_t j; 00173 00174 for(j=0;j<nvar;j++) { 00175 x[j]=x0[j]; 00176 best_x[j]=x0[j]; 00177 } 00178 00179 int ret=func(nvar,x,E,pa); 00180 if (ret!=0) { 00181 O2SCL_ERR_RET("Initial point failed in gsl_anneal::mmin().", 00182 gsl_ebadfunc); 00183 } 00184 best_E=E; 00185 00186 // Setup initial temperature and step sizes 00187 start(nvar,T); 00188 00189 bool done=false; 00190 00191 while (!done) { 00192 00193 // Copy old value of x for next() function 00194 for(j=0;j<nvar;j++) old_x[j]=x[j]; 00195 old_E=E; 00196 00197 size_t nmoves=0; 00198 00199 for (i=0;i<this->ntrial;++i) { 00200 for (j=0;j<nvar;j++) new_x[j]=x[j]; 00201 00202 step(new_x,nvar); 00203 ret=func(nvar,new_x,new_E,pa); 00204 00205 // If the function evaluation failed, then 00206 // simply ignore the new value and proceed 00207 // to the next step 00208 if (ret==0) { 00209 00210 // Store best value obtained so far 00211 if(new_E<=best_E){ 00212 for(j=0;j<nvar;j++) best_x[j]=new_x[j]; 00213 best_E=new_E; 00214 } 00215 00216 // Take the crucial step: see if the new point is accepted 00217 // or not, as determined by the boltzmann probability 00218 if (new_E<E) { 00219 for(j=0;j<nvar;j++) x[j]=new_x[j]; 00220 E=new_E; 00221 nmoves++; 00222 } else if (this->def_rng.random() < exp(-(new_E-E)/(boltz*T))) { 00223 for(j=0;j<nvar;j++) x[j]=new_x[j]; 00224 E=new_E; 00225 nmoves++; 00226 } 00227 00228 } 00229 } 00230 00231 if (this->verbose>0) { 00232 this->print_iter(nvar,best_x,best_E,iter,T,"gsl_anneal"); 00233 iter++; 00234 } 00235 00236 // See if we're finished and proceed to the next step 00237 next(nvar,old_x,old_E,x,E,T,nmoves,done); 00238 00239 } 00240 00241 for(j=0;j<nvar;j++) x0[j]=best_x[j]; 00242 fmin=best_E; 00243 00244 free(); 00245 00246 return 0; 00247 } 00248 00249 /// Return string denoting type ("gsl_anneal") 00250 virtual const char *type() { return "gsl_anneal"; } 00251 00252 /** \brief Boltzmann factor (default 1.0). 00253 */ 00254 double boltz; 00255 00256 /// Set the step sizes 00257 template<class vec2_t> int set_step(size_t nv, vec2_t &stepv) { 00258 if (nv>0) { 00259 step_vec.free(); 00260 step_vec.allocate(nv); 00261 for(size_t i=0;i<nv;i++) step_vec[i]=stepv[i]; 00262 } 00263 return 0; 00264 } 00265 00266 /// Initial temperature (default 1.0) 00267 double T_start; 00268 00269 /// Factor to decrease temperature by (default 1.5) 00270 double T_dec; 00271 00272 /// Factor to decrease step size by (default 1.5) 00273 double step_dec; 00274 00275 /// Ratio between minimum step size and \ref tolx (default 100.0) 00276 double min_step_ratio; 00277 00278 #ifndef DOXYGEN_INTERNAL 00279 00280 protected: 00281 00282 /// \name Storage for present, next, and best vectors 00283 //@{ 00284 alloc_vec_t x, new_x, best_x, old_x; 00285 //@} 00286 00287 /// Allocation object 00288 alloc_t ao; 00289 00290 /// Vector of step sizes 00291 ovector step_vec; 00292 00293 /// Determine how to change the minimization for the next iteration 00294 virtual int next(size_t nvar, vec_t &x_old, double min_old, 00295 vec_t &x_new, double min_new, double &T, 00296 size_t n_moves, bool &finished) { 00297 00298 if (T/T_dec<this->tolx) { 00299 finished=true; 00300 return gsl_success; 00301 } 00302 if (n_moves==0) { 00303 for(size_t i=0;i<nvar;i++) { 00304 if (i<step_vec.size() && step_vec[i]>this->tolx*min_step_ratio) { 00305 step_vec[i]/=step_dec; 00306 } 00307 } 00308 } 00309 T/=T_dec; 00310 return gsl_success; 00311 } 00312 00313 /// Setup initial temperature and stepsize 00314 virtual int start(size_t nvar, double &T) { 00315 T=T_start; 00316 return gsl_success; 00317 } 00318 00319 /** \brief Allocate memory for a minimizer over \c n dimensions 00320 with stepsize \c step and Boltzmann factor \c boltz_factor 00321 */ 00322 virtual int allocate(size_t n, double boltz_factor=1.0) { 00323 ao.allocate(x,n); 00324 ao.allocate(old_x,n); 00325 ao.allocate(new_x,n); 00326 ao.allocate(best_x,n); 00327 boltz=boltz_factor; 00328 return 0; 00329 } 00330 00331 /// Free allocated memory 00332 virtual int free() { 00333 ao.free(x); 00334 ao.free(old_x); 00335 ao.free(new_x); 00336 ao.free(best_x); 00337 return 0; 00338 } 00339 00340 /// Make a step to a new attempted minimum 00341 virtual int step(vec_t &sx, int nvar) { 00342 size_t nstep=step_vec.size(); 00343 for(int i=0;i<nvar;i++) { 00344 double u=this->def_rng.random(); 00345 sx[i]=(2.0*u-1.0)*step_vec[i%nstep]+sx[i]; 00346 } 00347 return 0; 00348 } 00349 00350 #endif 00351 00352 }; 00353 00354 #ifndef DOXYGENP 00355 } 00356 #endif 00357 00358 #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