lemon/simann.h
author ladanyi
Fri, 14 Apr 2006 22:01:02 +0000
changeset 2056 8acf212a5ed4
parent 1956 a055123339d5
child 2229 4dbb6dd2dd4b
permissions -rw-r--r--
downgrade to gettext 0.14.2
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #ifndef LEMON_SIMANN_H
    20 #define LEMON_SIMANN_H
    21 
    22 /// \ingroup experimental
    23 /// \file
    24 /// \brief Simulated annealing framework.
    25 ///
    26 /// \todo A test and some demo should be added
    27 /// \todo Doc should be improved
    28 /// \author Akos Ladanyi
    29 
    30 #include <cstdlib>
    31 #include <cmath>
    32 #include <limits>
    33 #include <lemon/time_measure.h>
    34 
    35 #ifdef WIN32
    36 #include <lemon/bits/mingw32_rand.h>
    37 #endif
    38 
    39 namespace lemon {
    40 
    41 /// \addtogroup experimental
    42 /// @{
    43 
    44   class SimAnnBase;
    45 
    46   /// \brief A base class for controllers.
    47   class ControllerBase {
    48   public:
    49     friend class SimAnnBase;
    50     /// \brief Pointer to the simulated annealing base class.
    51     SimAnnBase *simann;
    52     /// \brief Initializes the controller.
    53     virtual void init() {}
    54     /// \brief This is called by the simulated annealing class when a
    55     /// neighbouring state gets accepted.
    56     virtual void acceptEvent() {}
    57     /// \brief This is called by the simulated annealing class when the
    58     /// accepted neighbouring state's cost is less than the best found one's.
    59     virtual void improveEvent() {}
    60     /// \brief This is called by the simulated annealing class when a
    61     /// neighbouring state gets rejected.
    62     virtual void rejectEvent() {}
    63     /// \brief Decides whether to continue the annealing process or not.
    64     virtual bool next() = 0;
    65     /// \brief Decides whether to accept the current solution or not.
    66     virtual bool accept() = 0;
    67     /// \brief Destructor.
    68     virtual ~ControllerBase() {}
    69   };
    70 
    71   /// \brief Skeleton of an entity class.
    72   class EntityBase {
    73   public:
    74     /// \brief Makes a minor change to the entity.
    75     /// \return the new cost
    76     virtual double mutate() = 0;
    77     /// \brief Restores the entity to its previous state i.e. reverts the
    78     /// effects of the last mutate().
    79     virtual void revert() = 0;
    80     /// \brief Makes a copy of the entity.
    81     virtual EntityBase* clone() = 0;
    82     /// \brief Makes a major change to the entity.
    83     virtual void randomize() = 0;
    84     /// \brief Destructor.
    85     virtual ~EntityBase() {}
    86   };
    87 
    88   /// \brief Simulated annealing abstract base class.
    89   /// Can be used to derive a custom simulated annealing class if \ref SimAnn
    90   /// doesn't fit your needs.
    91   class SimAnnBase {
    92   private:
    93     /// \brief Pointer to the controller.
    94     ControllerBase *controller;
    95     /// \brief Cost of the current solution.
    96     double curr_cost;
    97     /// \brief Cost of the best solution.
    98     double best_cost;
    99     /// \brief Cost of the previous solution.
   100     double prev_cost;
   101     /// \brief Cost of the solution preceding the previous one.
   102     double prev_prev_cost;
   103     /// \brief Number of iterations.
   104     long iter;
   105     /// \brief Number of iterations which did not improve the solution since
   106     /// the last improvement.
   107     long last_impr;
   108   protected:
   109     /// \brief Step to a neighbouring state.
   110     virtual double mutate() = 0;
   111     /// \brief Reverts the last mutate().
   112     virtual void revert() = 0;
   113     /// \brief Saves the current solution as the best one.
   114     virtual void saveAsBest() = 0;
   115     /// \brief Does initializations before each run.
   116     virtual void init() {
   117       controller->init();
   118       curr_cost = prev_cost = prev_prev_cost = best_cost =
   119         std::numeric_limits<double>::infinity();
   120       iter = last_impr = 0;
   121     }
   122   public:
   123     /// \brief Sets the controller class to use.
   124     void setController(ControllerBase &_controller) {
   125       controller = &_controller;
   126       controller->simann = this;
   127     }
   128     /// \brief Returns the cost of the current solution.
   129     double getCurrCost() const { return curr_cost; }
   130     /// \brief Returns the cost of the previous solution.
   131     double getPrevCost() const { return prev_cost; }
   132     /// \brief Returns the cost of the best solution.
   133     double getBestCost() const { return best_cost; }
   134     /// \brief Returns the number of iterations done.
   135     long getIter() const { return iter; }
   136     /// \brief Returns the ordinal number of the last iteration when the
   137     /// solution was improved.
   138     long getLastImpr() const { return last_impr; }
   139     /// \brief Performs one iteration.
   140     bool step() {
   141       iter++;
   142       prev_prev_cost = prev_cost;
   143       prev_cost = curr_cost;
   144       curr_cost = mutate();
   145       if (controller->accept()) {
   146         controller->acceptEvent();
   147         last_impr = iter;
   148         if (curr_cost < best_cost) {
   149           best_cost = curr_cost;
   150           saveAsBest();
   151           controller->improveEvent();
   152         }
   153       }
   154       else {
   155         revert();
   156         curr_cost = prev_cost;
   157         prev_cost = prev_prev_cost;
   158         controller->rejectEvent();
   159       }
   160       return controller->next();
   161     }
   162     /// \brief Performs a given number of iterations.
   163     /// \param n the number of iterations
   164     bool step(int n) {
   165       for(; n > 0 && step(); --n) ;
   166       return !n;
   167     }
   168     /// \brief Starts the annealing process.
   169     void run() {
   170       init();
   171       do { } while (step());
   172     }
   173     /// \brief Destructor.
   174     virtual ~SimAnnBase() {}
   175   };
   176 
   177   /// \brief Simulated annealing class.
   178   class SimAnn : public SimAnnBase {
   179   private:
   180     /// \brief Pointer to the current entity.
   181     EntityBase *curr_ent;
   182     /// \brief Pointer to the best entity.
   183     EntityBase *best_ent;
   184     /// \brief Does initializations before each run.
   185     void init() {
   186       SimAnnBase::init();
   187       if (best_ent) delete best_ent;
   188       best_ent = NULL;
   189       curr_ent->randomize();
   190     }
   191   public:
   192     /// \brief Constructor.
   193     SimAnn() : curr_ent(NULL), best_ent(NULL) {}
   194     /// \brief Destructor.
   195     virtual ~SimAnn() {
   196       if (best_ent) delete best_ent;
   197     }
   198     /// \brief Step to a neighbouring state.
   199     double mutate() {
   200       return curr_ent->mutate();
   201     }
   202     /// \brief Reverts the last mutate().
   203     void revert() {
   204       curr_ent->revert();
   205     }
   206     /// \brief Saves the current solution as the best one.
   207     void saveAsBest() { 
   208       if (best_ent) delete best_ent;
   209       best_ent = curr_ent->clone();
   210     }
   211     /// \brief Sets the current entity.
   212     void setEntity(EntityBase &_ent) {
   213       curr_ent = &_ent;
   214     }
   215     /// \brief Returns a copy of the best found entity.
   216     EntityBase* getBestEntity() { return best_ent->clone(); }
   217   };
   218 
   219   /// \brief A simple controller for the simulated annealing class.
   220   /// This controller starts from a given initial temperature and evenly
   221   /// decreases it.
   222   class SimpleController : public ControllerBase {
   223   private:
   224     /// \brief Maximum number of iterations.
   225     long max_iter;
   226     /// \brief Maximum number of iterations which do not improve the
   227     /// solution.
   228     long max_no_impr;
   229     /// \brief Temperature.
   230     double temp;
   231     /// \brief Annealing factor.
   232     double ann_fact;
   233     /// \brief Constructor.
   234     /// \param _max_iter maximum number of iterations
   235     /// \param _max_no_impr maximum number of consecutive iterations which do
   236     ///        not yield a better solution
   237     /// \param _temp initial temperature
   238     /// \param _ann_fact annealing factor
   239   public:
   240     SimpleController(long _max_iter = 500000, long _max_no_impr = 20000,
   241     double _temp = 1000.0, double _ann_fact = 0.9999) : max_iter(_max_iter),
   242       max_no_impr(_max_no_impr), temp(_temp), ann_fact(_ann_fact)
   243     {
   244       srand48(time(0));
   245     }
   246     /// \brief This is called when a neighbouring state gets accepted.
   247     void acceptEvent() {}
   248     /// \brief This is called when the accepted neighbouring state's cost is
   249     /// less than the best found one's.
   250     void improveEvent() {}
   251     /// \brief This is called when a neighbouring state gets rejected.
   252     void rejectEvent() {}
   253     /// \brief Decides whether to continue the annealing process or not. Also
   254     /// decreases the temperature.
   255     bool next() {
   256       temp *= ann_fact;
   257       bool quit = (simann->getIter() > max_iter) ||
   258         (simann->getIter() - simann->getLastImpr() > max_no_impr);
   259       return !quit;
   260     }
   261     /// \brief Decides whether to accept the current solution or not.
   262     bool accept() {
   263       double cost_diff = simann->getCurrCost() - simann->getPrevCost();
   264       return (drand48() <= exp(-(cost_diff / temp)));
   265     }
   266     /// \brief Destructor.
   267     virtual ~SimpleController() {}
   268   };
   269 
   270   /// \brief A controller with preset running time for the simulated annealing
   271   /// class.
   272   /// With this controller you can set the running time of the annealing
   273   /// process in advance. It works the following way: the controller measures
   274   /// a kind of divergence. The divergence is the difference of the average
   275   /// cost of the recently found solutions the cost of the best found one. In
   276   /// case this divergence is greater than a given threshold, then we decrease
   277   /// the annealing factor, that is we cool the system faster. In case the
   278   /// divergence is lower than the threshold, then we increase the temperature.
   279   /// The threshold is a function of the elapsed time which reaches zero at the
   280   /// desired end time.
   281   class AdvancedController : public ControllerBase {
   282   private:
   283     /// \brief Timer class to measure the elapsed time.
   284     Timer timer;
   285     /// \brief Calculates the threshold value.
   286     /// \param time the elapsed time in seconds
   287     virtual double threshold(double time) {
   288       return (-1.0) * start_threshold / end_time * time + start_threshold;
   289     }
   290     /// \brief Parameter used to calculate the running average.
   291     double alpha;
   292     /// \brief Parameter used to decrease the annealing factor.
   293     double beta;
   294     /// \brief Parameter used to increase the temperature.
   295     double gamma;
   296     /// \brief The time at the end of the algorithm.
   297     double end_time;
   298     /// \brief The time at the start of the algorithm.
   299     double start_time;
   300     /// \brief Starting threshold.
   301     double start_threshold;
   302     /// \brief Average cost of recent solutions.
   303     double avg_cost;
   304     /// \brief Temperature.
   305     double temp;
   306     /// \brief Annealing factor.
   307     double ann_fact;
   308     /// \brief Initial annealing factor.
   309     double init_ann_fact;
   310     /// \brief True when the annealing process has been started.
   311     bool start;
   312   public:
   313     /// \brief Constructor.
   314     /// \param _end_time running time in seconds
   315     /// \param _alpha parameter used to calculate the running average
   316     /// \param _beta parameter used to decrease the annealing factor
   317     /// \param _gamma parameter used to increase the temperature
   318     /// \param _ann_fact initial annealing factor
   319     AdvancedController(double _end_time, double _alpha = 0.2,
   320     double _beta = 0.9, double _gamma = 1.6, double _ann_fact = 0.9999) :
   321     alpha(_alpha), beta(_beta), gamma(_gamma), end_time(_end_time),
   322     ann_fact(_ann_fact), init_ann_fact(_ann_fact), start(false)
   323     {
   324       srand48(time(0));
   325     }
   326     /// \brief Does initializations before each run.
   327     void init() {
   328       avg_cost = simann->getCurrCost();
   329     }
   330     /// \brief This is called when a neighbouring state gets accepted.
   331     void acceptEvent() {
   332       avg_cost = alpha * simann->getCurrCost() + (1.0 - alpha) * avg_cost;
   333       if (!start) {
   334         static int cnt = 0;
   335         cnt++;
   336         if (cnt >= 100) {
   337           // calculate starting threshold and starting temperature
   338           start_threshold = 5.0 * fabs(simann->getBestCost() - avg_cost);
   339           temp = 10000.0;
   340           start = true;
   341           timer.restart();
   342         }
   343       }
   344     }
   345     /// \brief Decides whether to continue the annealing process or not.
   346     bool next() {
   347       if (!start) {
   348         return true;
   349       }
   350       else {
   351         double elapsed_time = timer.realTime();
   352         if (fabs(avg_cost - simann->getBestCost()) > threshold(elapsed_time)) {
   353           // decrease the annealing factor
   354           ann_fact *= beta;
   355         }
   356         else {
   357           // increase the temperature
   358           temp *= gamma;
   359           // reset the annealing factor
   360           ann_fact = init_ann_fact;
   361         }
   362         temp *= ann_fact;
   363         return elapsed_time < end_time;
   364       }
   365     }
   366     /// \brief Decides whether to accept the current solution or not.
   367     bool accept() {
   368       if (!start) {
   369         return true;
   370       }
   371       else {
   372         double cost_diff = simann->getCurrCost() - simann->getPrevCost();
   373         return (drand48() <= exp(-(cost_diff / temp)));
   374       }
   375     }
   376     /// \brief Destructor.
   377     virtual ~AdvancedController() {}
   378   };
   379 
   380 /// @}
   381 
   382 }
   383 
   384 #endif