src/work/akos/simann.h
changeset 1021 fd1d073b6557
parent 1000 7f4d07047ed8
child 1023 3268fef5d623
equal deleted inserted replaced
4:a2a9c298de4a 5:d6928bd4d8b5
     1 #ifndef LEMON_SIMANN_H
     1 #ifndef LEMON_SIMANN_H
     2 #define LEMON_SIMANN_H
     2 #define LEMON_SIMANN_H
     3 
     3 
     4 #include <cstdlib>
     4 #include <cstdlib>
     5 #include <cmath>
     5 #include <cmath>
     6 #include <sys/time.h>
     6 #include <lemon/time_measure.h>
     7 
     7 
     8 namespace lemon {
     8 namespace lemon {
     9 
     9 
    10   const double INFTY = 1e24;
    10   const double INFTY = 1e24;
    11 
    11 
    28     }
    28     }
    29     void setController(Controller &_controller) {
    29     void setController(Controller &_controller) {
    30       controller = &_controller;
    30       controller = &_controller;
    31       controller->setBase(this);
    31       controller->setBase(this);
    32     }
    32     }
    33     double getCurrCost() { return curr_cost; }
    33     double getCurrCost() const { return curr_cost; }
    34     double getPrevCost() { return prev_cost; }
    34     double getPrevCost() const { return prev_cost; }
    35     double getBestCost() { return best_cost; }
    35     double getBestCost() const { return best_cost; }
    36     void run() {
    36     void run() {
    37       controller->init();
    37       controller->init();
    38       while (controller->next()) {
    38       do {
    39         mutate();
    39         mutate();
    40         if (controller->accept()) {
    40         if (controller->accept()) {
    41           controller->acceptEvent();
    41           controller->acceptEvent();
    42           if (curr_cost < best_cost) {
    42           if (curr_cost < best_cost) {
    43             saveAsBest();
    43             saveAsBest();
    46         }
    46         }
    47         else {
    47         else {
    48           revert();
    48           revert();
    49           controller->rejectEvent();
    49           controller->rejectEvent();
    50         }
    50         }
    51       }
    51       } while (controller->next());
    52     }
    52     }
    53 
    53 
    54     /*! \brief A base class for controllers. */
    54     /*! \brief A base class for controllers. */
    55     class Controller {
    55     class Controller {
    56     public:
    56     public:
    70       /*! */
    70       /*! */
    71       virtual bool accept() = 0;
    71       virtual bool accept() = 0;
    72     };
    72     };
    73   };
    73   };
    74 
    74 
       
    75   /*! \todo atgondolni mi is ez a prev_cost */
    75   template <typename E>
    76   template <typename E>
    76   class SimAnn : public SimAnnBase {
    77   class SimAnn : public SimAnnBase {
    77   private:
    78   private:
    78     E *curr_ent;
    79     E *curr_ent;
    79     E *best_ent;
    80     E *best_ent;
    83       curr_ent = new E(ent);
    84       curr_ent = new E(ent);
    84       best_ent = new E(ent);
    85       best_ent = new E(ent);
    85     }
    86     }
    86     E getBestEntity() { return *best_ent; }
    87     E getBestEntity() { return *best_ent; }
    87     void mutate() {
    88     void mutate() {
    88       curr_ent->mutate();
    89       prev_cost = curr_cost;
       
    90       curr_cost = curr_ent->mutate();
    89     }
    91     }
    90     void revert() {
    92     void revert() {
    91       curr_ent->revert();
    93       curr_ent->revert();
       
    94       curr_cost = prev_cost;
    92     }
    95     }
    93     void saveAsBest() {
    96     void saveAsBest() {
    94       *best_ent = *curr_ent;
    97       *best_ent = *curr_ent;
    95       best_cost = curr_cost;
    98       best_cost = curr_cost;
    96     }
    99     }
   138       temp *= ann_fact;
   141       temp *= ann_fact;
   139       bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr);
   142       bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr);
   140       return !quit;
   143       return !quit;
   141     }
   144     }
   142     bool accept() {
   145     bool accept() {
   143       return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
   146       double cost_diff = base->getPrevCost() - base->getCurrCost();
   144         temp));
   147       if (cost_diff < 0.0) {
       
   148         return (drand48() <= exp(cost_diff / temp));
       
   149       }
       
   150       else {
       
   151         return true;
       
   152       }
   145     }
   153     }
   146   };
   154   };
   147 
   155 
   148   /*! \brief A controller with preset running time for the simulated annealing
   156   /*! \brief A controller with preset running time for the simulated annealing
   149    *  class.
   157    *  class.
   150    *  \todo Find a better name.
   158    *  \todo Find a better name.
   151    */
   159    */
   152   class AdvancedController : public SimAnnBase::Controller {
   160   class AdvancedController : public SimAnnBase::Controller {
   153   private:
   161   private:
       
   162     Timer timer;
   154     /*! \param time the elapsed time in seconds */
   163     /*! \param time the elapsed time in seconds */
   155     double threshold(double time) { return 0.0; }
   164     virtual double threshold(double time) {
       
   165       // this is the function 1 / log(x) scaled and offset
       
   166       static double xm = 5.0 / end_time;
       
   167       static double ym = start_threshold / (1 / log(1.2) - 1 / log(5.0 + 1.2));
       
   168       return ym * (1 / log(xm * time + 1.2) - 1 / log(5.0 + 1.2));
       
   169     }
   156   public:
   170   public:
   157     double alpha, beta, gamma;
   171     double alpha, beta, gamma;
   158     double end_time, start_time;
   172     double end_time, start_time;
       
   173     double start_threshold;
   159     double avg_cost;
   174     double avg_cost;
   160     double temp, ann_fact;
   175     double temp, ann_fact;
   161     /*! \param _end_time running_time
   176     bool warmup;
       
   177     long iter;
       
   178     /*! \param _end_time running time in seconds
   162      *  \param _alpha parameter used to calculate the running average
   179      *  \param _alpha parameter used to calculate the running average
   163      *  \param _beta parameter used to decrease the annealing factor
   180      *  \param _beta parameter used to decrease the annealing factor
   164      *  \param _gamma parameter used to increase the temperature
   181      *  \param _gamma parameter used to increase the temperature
   165      */
   182      */
   166     AdvancedController(double _end_time, double _alpha = 0.2,
   183     AdvancedController(double _end_time, double _alpha = 0.2,
   167     double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta),
   184     double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta),
   168     gamma(_gamma), end_time(_end_time) {}
   185     gamma(_gamma), end_time(_end_time), ann_fact(0.9999), warmup(true),
       
   186     iter(0) {}
   169     void init() {
   187     void init() {
   170       timeval tv;
   188       avg_cost = base->getCurrCost();
   171       gettimeofday(&tv, 0);
       
   172       start_time = tv.tv_sec + double(tv.tv_usec) / 1e6;
       
   173     }
   189     }
   174     void acceptEvent() {
   190     void acceptEvent() {
   175       avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost;
   191       avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost;
       
   192       iter++;
   176     }
   193     }
   177     void improveEvent() {
   194     void improveEvent() {
   178     }
   195     }
   179     void rejectEvent() {
   196     void rejectEvent() {
       
   197       iter++;
   180     }
   198     }
   181     bool next() {
   199     bool next() {
   182       timeval tv;
   200       if (warmup) {
   183       gettimeofday(&tv, 0);
   201         static double max_cost_diff = 0.0;
   184       double elapsed_time = tv.tv_sec + double(tv.tv_usec) / 1e6 - start_time;
   202         double cost_diff = base->getCurrCost() - base->getPrevCost();
   185       if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
   203         // jo ez igy egyaltalan? -> prev_cost
   186 	// decrease the annealing factor
   204         if ((cost_diff > 0.0) && (cost_diff > max_cost_diff)) {
   187         ann_fact *= beta;
   205           max_cost_diff = cost_diff;
       
   206         }
       
   207         // How to set the starting temperature when all the 100 first
       
   208         // iterations improve the solution?
       
   209         if (iter > 100) {
       
   210           // calculate starting threshold and starting temperature
       
   211           start_threshold = fabs(base->getBestCost() - avg_cost);
       
   212           temp = exp(max_cost_diff) / 0.5;
       
   213           warmup = false;
       
   214           timer.reset();
       
   215         }
       
   216         return true;
   188       }
   217       }
   189       else {
   218       else {
   190         // increase the temperature
   219         double elapsed_time = timer.getRealTime();
   191         temp *= gamma;
   220         if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
   192       }
   221           // decrease the annealing factor
   193       temp *= ann_fact;
   222           ann_fact *= beta;
   194       return elapsed_time < end_time;
   223         }
       
   224         else {
       
   225           // increase the temperature
       
   226           temp *= gamma;
       
   227         }
       
   228         temp *= ann_fact;
       
   229         return elapsed_time < end_time;
       
   230       }
   195     }
   231     }
   196     bool accept() {
   232     bool accept() {
   197       return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
   233       if (warmup) {
   198         temp));
   234         // we accept eveything during the "warm up" phase
       
   235         return true;
       
   236       }
       
   237       else {
       
   238         double cost_diff = base->getPrevCost() - base->getCurrCost();
       
   239         if (cost_diff < 0.0) {
       
   240           return (drand48() <= exp(cost_diff / temp));
       
   241         }
       
   242         else {
       
   243           return true;
       
   244         }
       
   245       }
   199     }
   246     }
   200   };
   247   };
   201 
   248 
   202 }
   249 }
   203 
   250