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 descendant. 00078 00079 The default behavior is as follows: Initially, the step sizes 00080 are chosen to be 10 and the temperature to be 1. Each iteration 00081 decreases the temperature by a factor of 1.5 for each step, and 00082 the minimizer is finished when the next decrease would bring the 00083 temperature below multi_min::tolx. If none of the 00084 multi_min::ntrial steps in a particular iteration changes the 00085 value of the minimum, and the step sizes are greater than 100 00086 times multi_min::tolx, then the step sizes are decreased by a 00087 factor of 1.5 for the next iteration. 00088 00089 If \ref multi_min::verbose is greater than zero, 00090 then \ref mmin() will print out information and/or 00091 request a keypress after the function iterations 00092 for each temperature. 00093 00094 An example demonstrating the usage of this class is given in 00095 <tt>examples/ex_anneal.cpp</tt> and in the \ref ex_anneal_sect . 00096 00097 See also a multi-threaded version of this class in \ref 00098 anneal_mt. 00099 00100 \future There's x0, old_x, new_x, best_x, and x? There's probably 00101 some duplication here which could be avoided. 00102 00103 \future 00104 - Implement a more general simulated annealing routine 00105 which would allow the solution of discrete problems like the 00106 Traveling Salesman problem. 00107 \comment 00108 This could probably be done just by creating a parent abstract 00109 base class which doesn't have any reference to step() and 00110 step_vec. 00111 \endcomment 00112 00113 */ 00114 template<class param_t, class func_t=multi_funct<param_t>, 00115 class vec_t=ovector_base, class alloc_vec_t=ovector, 00116 class alloc_t=ovector_alloc, class rng_t=gsl_rnga> class gsl_anneal : 00117 public sim_anneal<param_t,func_t,vec_t,rng_t> { 00118 public: 00119 00120 gsl_anneal() { 00121 boltz=1.0; 00122 step_vec.allocate(1); 00123 step_vec[0]=10.0; 00124 } 00125 00126 virtual ~gsl_anneal() { 00127 step_vec.free(); 00128 } 00129 00130 /** \brief Calculate the minimum \c fmin of \c func w.r.t the 00131 array \c x0 of size \c nvar. 00132 */ 00133 virtual int mmin(size_t nvar, vec_t &x0, double &fmin, param_t &pa, 00134 func_t &func) 00135 { 00136 00137 if (nvar==0) { 00138 O2SCL_ERR2_RET("Tried to minimize over zero variables ", 00139 " in gsl_anneal::mmin().",gsl_einval); 00140 } 00141 00142 fmin=0.0; 00143 00144 allocate(nvar); 00145 00146 double E, new_E, best_E, T, old_E; 00147 int i, iter=0; 00148 size_t j; 00149 00150 for(j=0;j<nvar;j++) { 00151 x[j]=x0[j]; 00152 best_x[j]=x0[j]; 00153 } 00154 00155 E=func(nvar,x,pa); 00156 best_E=E; 00157 00158 // Setup initial temperature and step sizes 00159 start(nvar,T); 00160 00161 bool done=false; 00162 00163 while (!done) { 00164 00165 // Copy old value of x for next() function 00166 for(j=0;j<nvar;j++) old_x[j]=x[j]; 00167 old_E=E; 00168 00169 size_t nmoves=0; 00170 00171 for (i=0;i<this->ntrial;++i) { 00172 for (j=0;j<nvar;j++) new_x[j]=x[j]; 00173 00174 step(new_x,nvar); 00175 new_E=func(nvar,new_x,pa); 00176 00177 // Store best value obtained so far 00178 if(new_E<=best_E){ 00179 for(j=0;j<nvar;j++) best_x[j]=new_x[j]; 00180 best_E=new_E; 00181 } 00182 00183 // Take the crucial step: see if the new point is accepted 00184 // or not, as determined by the boltzmann probability 00185 if (new_E<E) { 00186 for(j=0;j<nvar;j++) x[j]=new_x[j]; 00187 E=new_E; 00188 nmoves++; 00189 } else if (this->def_rng.random() < exp(-(new_E-E)/(boltz*T))) { 00190 for(j=0;j<nvar;j++) x[j]=new_x[j]; 00191 E=new_E; 00192 nmoves++; 00193 } 00194 } 00195 00196 if (this->verbose>0) { 00197 this->print_iter(nvar,best_x,best_E,iter,T,"gsl_anneal"); 00198 iter++; 00199 } 00200 00201 // See if we're finished and proceed to the next step 00202 next(nvar,old_x,old_E,x,E,T,nmoves,done); 00203 00204 } 00205 00206 for(j=0;j<nvar;j++) x0[j]=best_x[j]; 00207 fmin=best_E; 00208 00209 free(); 00210 00211 return 0; 00212 } 00213 00214 /// Return string denoting type ("gsl_anneal") 00215 virtual const char *type() { return "gsl_anneal"; } 00216 00217 /** \brief Boltzmann factor (default 1.0). 00218 */ 00219 double boltz; 00220 00221 /// Set the step sizes 00222 template<class vec2_t> int set_step(size_t nv, vec2_t &stepv) { 00223 if (nv>0) { 00224 step_vec.free(); 00225 step_vec.allocate(nv); 00226 for(size_t i=0;i<nv;i++) step_vec[i]=stepv[i]; 00227 } 00228 return 0; 00229 } 00230 00231 #ifndef DOXYGEN_INTERNAL 00232 00233 protected: 00234 00235 /// \name Storage for present, next, and best vectors 00236 //@{ 00237 alloc_vec_t x, new_x, best_x, old_x; 00238 //@} 00239 00240 /// Allocation object 00241 alloc_t ao; 00242 00243 /// Vector of step sizes 00244 ovector step_vec; 00245 00246 /// Determine how to change the minimization for the next iteration 00247 virtual int next(size_t nvar, vec_t &x_old, double min_old, vec_t &x_new, 00248 double min_new, double &T, size_t n_moves, 00249 bool &finished) { 00250 00251 if (T/2.0<this->tolx) { 00252 finished=true; 00253 return gsl_success; 00254 } 00255 if (n_moves==0) { 00256 for(size_t i=0;i<nvar;i++) { 00257 if (i<step_vec.size() && step_vec[i]>this->tolx*1.0e2) { 00258 step_vec[i]/=1.5; 00259 } 00260 } 00261 } 00262 T/=1.5; 00263 return gsl_success; 00264 } 00265 00266 /// Setup initial temperature and stepsize 00267 virtual int start(size_t nvar, double &T) { 00268 T=1.0; 00269 return gsl_success; 00270 } 00271 00272 /** \brief Allocate memory for a minimizer over \c n dimensions 00273 with stepsize \c step and Boltzmann factor \c boltz_factor 00274 */ 00275 virtual int allocate(size_t n, double boltz_factor=1.0) { 00276 ao.allocate(x,n); 00277 ao.allocate(old_x,n); 00278 ao.allocate(new_x,n); 00279 ao.allocate(best_x,n); 00280 boltz=boltz_factor; 00281 return 0; 00282 } 00283 00284 /// Free allocated memory 00285 virtual int free() { 00286 ao.free(x); 00287 ao.free(old_x); 00288 ao.free(new_x); 00289 ao.free(best_x); 00290 return 0; 00291 } 00292 00293 /// Make a step to a new attempted minimum 00294 virtual int step(vec_t &sx, int nvar) { 00295 size_t nstep=step_vec.size(); 00296 for(int i=0;i<nvar;i++) { 00297 double u=this->def_rng.random(); 00298 sx[i]=(2.0*u-1.0)*step_vec[i%nstep]+sx[i]; 00299 } 00300 return 0; 00301 } 00302 00303 #endif 00304 00305 }; 00306 00307 #ifndef DOXYGENP 00308 } 00309 #endif 00310 00311 #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