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