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