Object-oriented Scientific Computing Library: Version 0.910
gsl_anneal.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.