# HG changeset patch
# User ladanyi
# Date 1101134380 0
# Node ID 68beae6758a75f68c1f386bc511a05fbf70ec8f3
# Parent  f588efc6d607c51c4dea58528b15ecca4ef40f49
Use lemon::Timer for time measuring. Added the threshold() function and initial threshold and temperature calculation.

diff -r f588efc6d607 -r 68beae6758a7 src/work/akos/simann.h
--- a/src/work/akos/simann.h	Mon Nov 22 09:12:33 2004 +0000
+++ b/src/work/akos/simann.h	Mon Nov 22 14:39:40 2004 +0000
@@ -3,7 +3,7 @@
 
 #include <cstdlib>
 #include <cmath>
-#include <sys/time.h>
+#include <lemon/time_measure.h>
 
 namespace lemon {
 
@@ -30,12 +30,12 @@
       controller = &_controller;
       controller->setBase(this);
     }
-    double getCurrCost() { return curr_cost; }
-    double getPrevCost() { return prev_cost; }
-    double getBestCost() { return best_cost; }
+    double getCurrCost() const { return curr_cost; }
+    double getPrevCost() const { return prev_cost; }
+    double getBestCost() const { return best_cost; }
     void run() {
       controller->init();
-      while (controller->next()) {
+      do {
         mutate();
         if (controller->accept()) {
           controller->acceptEvent();
@@ -48,7 +48,7 @@
           revert();
           controller->rejectEvent();
         }
-      }
+      } while (controller->next());
     }
 
     /*! \brief A base class for controllers. */
@@ -72,6 +72,7 @@
     };
   };
 
+  /*! \todo atgondolni mi is ez a prev_cost */
   template <typename E>
   class SimAnn : public SimAnnBase {
   private:
@@ -85,10 +86,12 @@
     }
     E getBestEntity() { return *best_ent; }
     void mutate() {
-      curr_ent->mutate();
+      prev_cost = curr_cost;
+      curr_cost = curr_ent->mutate();
     }
     void revert() {
       curr_ent->revert();
+      curr_cost = prev_cost;
     }
     void saveAsBest() {
       *best_ent = *curr_ent;
@@ -140,8 +143,13 @@
       return !quit;
     }
     bool accept() {
-      return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
-        temp));
+      double cost_diff = base->getPrevCost() - base->getCurrCost();
+      if (cost_diff < 0.0) {
+        return (drand48() <= exp(cost_diff / temp));
+      }
+      else {
+        return true;
+      }
     }
   };
 
@@ -151,51 +159,90 @@
    */
   class AdvancedController : public SimAnnBase::Controller {
   private:
+    Timer timer;
     /*! \param time the elapsed time in seconds */
-    double threshold(double time) { return 0.0; }
+    virtual double threshold(double time) {
+      // this is the function 1 / log(x) scaled and offset
+      static double xm = 5.0 / end_time;
+      static double ym = start_threshold / (1 / log(1.2) - 1 / log(5.0 + 1.2));
+      return ym * (1 / log(xm * time + 1.2) - 1 / log(5.0 + 1.2));
+    }
   public:
     double alpha, beta, gamma;
     double end_time, start_time;
+    double start_threshold;
     double avg_cost;
     double temp, ann_fact;
-    /*! \param _end_time running_time
+    bool warmup;
+    long iter;
+    /*! \param _end_time running time in seconds
      *  \param _alpha parameter used to calculate the running average
      *  \param _beta parameter used to decrease the annealing factor
      *  \param _gamma parameter used to increase the temperature
      */
     AdvancedController(double _end_time, double _alpha = 0.2,
     double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta),
-    gamma(_gamma), end_time(_end_time) {}
+    gamma(_gamma), end_time(_end_time), ann_fact(0.9999), warmup(true),
+    iter(0) {}
     void init() {
-      timeval tv;
-      gettimeofday(&tv, 0);
-      start_time = tv.tv_sec + double(tv.tv_usec) / 1e6;
+      avg_cost = base->getCurrCost();
     }
     void acceptEvent() {
       avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost;
+      iter++;
     }
     void improveEvent() {
     }
     void rejectEvent() {
+      iter++;
     }
     bool next() {
-      timeval tv;
-      gettimeofday(&tv, 0);
-      double elapsed_time = tv.tv_sec + double(tv.tv_usec) / 1e6 - start_time;
-      if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
-	// decrease the annealing factor
-        ann_fact *= beta;
+      if (warmup) {
+        static double max_cost_diff = 0.0;
+        double cost_diff = base->getCurrCost() - base->getPrevCost();
+        // jo ez igy egyaltalan? -> prev_cost
+        if ((cost_diff > 0.0) && (cost_diff > max_cost_diff)) {
+          max_cost_diff = cost_diff;
+        }
+        // How to set the starting temperature when all the 100 first
+        // iterations improve the solution?
+        if (iter > 100) {
+          // calculate starting threshold and starting temperature
+          start_threshold = fabs(base->getBestCost() - avg_cost);
+          temp = exp(max_cost_diff) / 0.5;
+          warmup = false;
+          timer.reset();
+        }
+        return true;
       }
       else {
-        // increase the temperature
-        temp *= gamma;
+        double elapsed_time = timer.getRealTime();
+        if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
+          // decrease the annealing factor
+          ann_fact *= beta;
+        }
+        else {
+          // increase the temperature
+          temp *= gamma;
+        }
+        temp *= ann_fact;
+        return elapsed_time < end_time;
       }
-      temp *= ann_fact;
-      return elapsed_time < end_time;
     }
     bool accept() {
-      return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
-        temp));
+      if (warmup) {
+        // we accept eveything during the "warm up" phase
+        return true;
+      }
+      else {
+        double cost_diff = base->getPrevCost() - base->getCurrCost();
+        if (cost_diff < 0.0) {
+          return (drand48() <= exp(cost_diff / temp));
+        }
+        else {
+          return true;
+        }
+      }
     }
   };