Use lemon::Timer for time measuring. Added the threshold() function and initial threshold and temperature calculation.
authorladanyi
Mon, 22 Nov 2004 14:39:40 +0000
changeset 101868beae6758a7
parent 1017 f588efc6d607
child 1019 ee01de62188d
Use lemon::Timer for time measuring. Added the threshold() function and initial threshold and temperature calculation.
src/work/akos/simann.h
     1.1 --- a/src/work/akos/simann.h	Mon Nov 22 09:12:33 2004 +0000
     1.2 +++ b/src/work/akos/simann.h	Mon Nov 22 14:39:40 2004 +0000
     1.3 @@ -3,7 +3,7 @@
     1.4  
     1.5  #include <cstdlib>
     1.6  #include <cmath>
     1.7 -#include <sys/time.h>
     1.8 +#include <lemon/time_measure.h>
     1.9  
    1.10  namespace lemon {
    1.11  
    1.12 @@ -30,12 +30,12 @@
    1.13        controller = &_controller;
    1.14        controller->setBase(this);
    1.15      }
    1.16 -    double getCurrCost() { return curr_cost; }
    1.17 -    double getPrevCost() { return prev_cost; }
    1.18 -    double getBestCost() { return best_cost; }
    1.19 +    double getCurrCost() const { return curr_cost; }
    1.20 +    double getPrevCost() const { return prev_cost; }
    1.21 +    double getBestCost() const { return best_cost; }
    1.22      void run() {
    1.23        controller->init();
    1.24 -      while (controller->next()) {
    1.25 +      do {
    1.26          mutate();
    1.27          if (controller->accept()) {
    1.28            controller->acceptEvent();
    1.29 @@ -48,7 +48,7 @@
    1.30            revert();
    1.31            controller->rejectEvent();
    1.32          }
    1.33 -      }
    1.34 +      } while (controller->next());
    1.35      }
    1.36  
    1.37      /*! \brief A base class for controllers. */
    1.38 @@ -72,6 +72,7 @@
    1.39      };
    1.40    };
    1.41  
    1.42 +  /*! \todo atgondolni mi is ez a prev_cost */
    1.43    template <typename E>
    1.44    class SimAnn : public SimAnnBase {
    1.45    private:
    1.46 @@ -85,10 +86,12 @@
    1.47      }
    1.48      E getBestEntity() { return *best_ent; }
    1.49      void mutate() {
    1.50 -      curr_ent->mutate();
    1.51 +      prev_cost = curr_cost;
    1.52 +      curr_cost = curr_ent->mutate();
    1.53      }
    1.54      void revert() {
    1.55        curr_ent->revert();
    1.56 +      curr_cost = prev_cost;
    1.57      }
    1.58      void saveAsBest() {
    1.59        *best_ent = *curr_ent;
    1.60 @@ -140,8 +143,13 @@
    1.61        return !quit;
    1.62      }
    1.63      bool accept() {
    1.64 -      return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
    1.65 -        temp));
    1.66 +      double cost_diff = base->getPrevCost() - base->getCurrCost();
    1.67 +      if (cost_diff < 0.0) {
    1.68 +        return (drand48() <= exp(cost_diff / temp));
    1.69 +      }
    1.70 +      else {
    1.71 +        return true;
    1.72 +      }
    1.73      }
    1.74    };
    1.75  
    1.76 @@ -151,51 +159,90 @@
    1.77     */
    1.78    class AdvancedController : public SimAnnBase::Controller {
    1.79    private:
    1.80 +    Timer timer;
    1.81      /*! \param time the elapsed time in seconds */
    1.82 -    double threshold(double time) { return 0.0; }
    1.83 +    virtual double threshold(double time) {
    1.84 +      // this is the function 1 / log(x) scaled and offset
    1.85 +      static double xm = 5.0 / end_time;
    1.86 +      static double ym = start_threshold / (1 / log(1.2) - 1 / log(5.0 + 1.2));
    1.87 +      return ym * (1 / log(xm * time + 1.2) - 1 / log(5.0 + 1.2));
    1.88 +    }
    1.89    public:
    1.90      double alpha, beta, gamma;
    1.91      double end_time, start_time;
    1.92 +    double start_threshold;
    1.93      double avg_cost;
    1.94      double temp, ann_fact;
    1.95 -    /*! \param _end_time running_time
    1.96 +    bool warmup;
    1.97 +    long iter;
    1.98 +    /*! \param _end_time running time in seconds
    1.99       *  \param _alpha parameter used to calculate the running average
   1.100       *  \param _beta parameter used to decrease the annealing factor
   1.101       *  \param _gamma parameter used to increase the temperature
   1.102       */
   1.103      AdvancedController(double _end_time, double _alpha = 0.2,
   1.104      double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta),
   1.105 -    gamma(_gamma), end_time(_end_time) {}
   1.106 +    gamma(_gamma), end_time(_end_time), ann_fact(0.9999), warmup(true),
   1.107 +    iter(0) {}
   1.108      void init() {
   1.109 -      timeval tv;
   1.110 -      gettimeofday(&tv, 0);
   1.111 -      start_time = tv.tv_sec + double(tv.tv_usec) / 1e6;
   1.112 +      avg_cost = base->getCurrCost();
   1.113      }
   1.114      void acceptEvent() {
   1.115        avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost;
   1.116 +      iter++;
   1.117      }
   1.118      void improveEvent() {
   1.119      }
   1.120      void rejectEvent() {
   1.121 +      iter++;
   1.122      }
   1.123      bool next() {
   1.124 -      timeval tv;
   1.125 -      gettimeofday(&tv, 0);
   1.126 -      double elapsed_time = tv.tv_sec + double(tv.tv_usec) / 1e6 - start_time;
   1.127 -      if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
   1.128 -	// decrease the annealing factor
   1.129 -        ann_fact *= beta;
   1.130 +      if (warmup) {
   1.131 +        static double max_cost_diff = 0.0;
   1.132 +        double cost_diff = base->getCurrCost() - base->getPrevCost();
   1.133 +        // jo ez igy egyaltalan? -> prev_cost
   1.134 +        if ((cost_diff > 0.0) && (cost_diff > max_cost_diff)) {
   1.135 +          max_cost_diff = cost_diff;
   1.136 +        }
   1.137 +        // How to set the starting temperature when all the 100 first
   1.138 +        // iterations improve the solution?
   1.139 +        if (iter > 100) {
   1.140 +          // calculate starting threshold and starting temperature
   1.141 +          start_threshold = fabs(base->getBestCost() - avg_cost);
   1.142 +          temp = exp(max_cost_diff) / 0.5;
   1.143 +          warmup = false;
   1.144 +          timer.reset();
   1.145 +        }
   1.146 +        return true;
   1.147        }
   1.148        else {
   1.149 -        // increase the temperature
   1.150 -        temp *= gamma;
   1.151 +        double elapsed_time = timer.getRealTime();
   1.152 +        if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
   1.153 +          // decrease the annealing factor
   1.154 +          ann_fact *= beta;
   1.155 +        }
   1.156 +        else {
   1.157 +          // increase the temperature
   1.158 +          temp *= gamma;
   1.159 +        }
   1.160 +        temp *= ann_fact;
   1.161 +        return elapsed_time < end_time;
   1.162        }
   1.163 -      temp *= ann_fact;
   1.164 -      return elapsed_time < end_time;
   1.165      }
   1.166      bool accept() {
   1.167 -      return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
   1.168 -        temp));
   1.169 +      if (warmup) {
   1.170 +        // we accept eveything during the "warm up" phase
   1.171 +        return true;
   1.172 +      }
   1.173 +      else {
   1.174 +        double cost_diff = base->getPrevCost() - base->getCurrCost();
   1.175 +        if (cost_diff < 0.0) {
   1.176 +          return (drand48() <= exp(cost_diff / temp));
   1.177 +        }
   1.178 +        else {
   1.179 +          return true;
   1.180 +        }
   1.181 +      }
   1.182      }
   1.183    };
   1.184