src/work/akos/simann.h
author alpar
Sat, 13 Nov 2004 12:53:28 +0000
changeset 986 e997802b855c
parent 957 4dd4eaee28e7
child 1000 7f4d07047ed8
permissions -rw-r--r--
Naming changes:
- head -> target
- tail -> source
ladanyi@942
     1
#ifndef LEMON_SIMANN_H
ladanyi@942
     2
#define LEMON_SIMANN_H
ladanyi@918
     3
ladanyi@966
     4
#include <cstdlib>
ladanyi@966
     5
#include <cmath>
ladanyi@966
     6
#include <sys/time.h>
ladanyi@966
     7
ladanyi@942
     8
namespace lemon {
ladanyi@918
     9
ladanyi@942
    10
  const double INFTY = 1e24;
ladanyi@918
    11
ladanyi@942
    12
  class SimAnnBase {
ladanyi@918
    13
  public:
ladanyi@942
    14
    class Controller;
ladanyi@942
    15
  private:
ladanyi@942
    16
    Controller *controller;
ladanyi@942
    17
  protected:
ladanyi@942
    18
    double curr_cost;
ladanyi@942
    19
    double prev_cost;
ladanyi@942
    20
    double best_cost;
ladanyi@918
    21
ladanyi@942
    22
    virtual void mutate() = 0;
ladanyi@942
    23
    virtual void revert() = 0;
ladanyi@942
    24
    virtual void saveAsBest() = 0;
ladanyi@942
    25
  public:
ladanyi@942
    26
    SimAnnBase() {
ladanyi@942
    27
      curr_cost = prev_cost = best_cost = INFTY;
ladanyi@942
    28
    }
ladanyi@957
    29
    void setController(Controller &_controller) {
ladanyi@957
    30
      controller = &_controller;
ladanyi@957
    31
      controller->setBase(this);
ladanyi@957
    32
    }
ladanyi@957
    33
    double getCurrCost() { return curr_cost; }
ladanyi@957
    34
    double getPrevCost() { return prev_cost; }
ladanyi@942
    35
    double getBestCost() { return best_cost; }
ladanyi@942
    36
    void run() {
ladanyi@966
    37
      controller->init();
ladanyi@942
    38
      while (controller->next()) {
ladanyi@942
    39
        mutate();
ladanyi@957
    40
        if (controller->accept()) {
ladanyi@942
    41
          controller->acceptEvent();
ladanyi@942
    42
          if (curr_cost < best_cost) {
ladanyi@942
    43
            saveAsBest();
ladanyi@942
    44
            controller->improveEvent();
ladanyi@942
    45
          }
ladanyi@942
    46
        }
ladanyi@942
    47
        else {
ladanyi@942
    48
          revert();
ladanyi@942
    49
          controller->rejectEvent();
ladanyi@942
    50
        }
ladanyi@918
    51
      }
ladanyi@918
    52
    }
ladanyi@918
    53
ladanyi@942
    54
    class Controller {
ladanyi@942
    55
    public:
ladanyi@957
    56
      SimAnnBase *base;
ladanyi@966
    57
      virtual void init() {}
ladanyi@942
    58
      virtual void acceptEvent() {}
ladanyi@942
    59
      virtual void improveEvent() {}
ladanyi@942
    60
      virtual void rejectEvent() {}
ladanyi@957
    61
      virtual void setBase(SimAnnBase *_base) { base = _base; }
ladanyi@942
    62
      virtual bool next() = 0;
ladanyi@957
    63
      virtual bool accept() = 0;
ladanyi@942
    64
    };
ladanyi@942
    65
  };
ladanyi@918
    66
ladanyi@942
    67
  template <typename E>
ladanyi@942
    68
  class SimAnn : public SimAnnBase {
ladanyi@942
    69
  private:
ladanyi@942
    70
    E *curr_ent;
ladanyi@942
    71
    E *best_ent;
ladanyi@942
    72
  public:
ladanyi@957
    73
    SimAnn() : SimAnnBase() {}
ladanyi@957
    74
    void setEntity(E &ent) {
ladanyi@957
    75
      curr_ent = new E(ent);
ladanyi@957
    76
      best_ent = new E(ent);
ladanyi@942
    77
    }
ladanyi@942
    78
    E getBestEntity() { return *best_ent; }
ladanyi@942
    79
    void mutate() {
ladanyi@942
    80
      curr_ent->mutate();
ladanyi@942
    81
    }
ladanyi@942
    82
    void revert() {
ladanyi@942
    83
      curr_ent->revert();
ladanyi@942
    84
    }
ladanyi@942
    85
    void saveAsBest() {
ladanyi@942
    86
      *best_ent = *curr_ent;
ladanyi@942
    87
      best_cost = curr_cost;
ladanyi@942
    88
    }
ladanyi@942
    89
  };
ladanyi@942
    90
ladanyi@956
    91
  class EntitySkeleton {
ladanyi@942
    92
  public:
ladanyi@966
    93
    /*! \brief Makes a minor change to the entity.
ladanyi@966
    94
     *  \return the new cost
ladanyi@966
    95
     */
ladanyi@942
    96
    double mutate() { return 0.0; }
ladanyi@966
    97
    /*! \brief Restores the entity to its previous state i.e. reverts the
ladanyi@966
    98
     *  effects of the last mutate.
ladanyi@966
    99
     */
ladanyi@942
   100
    void revert() {}
ladanyi@942
   101
  };
ladanyi@942
   102
ladanyi@966
   103
  /*! \brief A simple controller for the simulated annealing class.
ladanyi@966
   104
   *  \todo Find a way to set the various parameters.
ladanyi@966
   105
   */
ladanyi@956
   106
  class SimpleController : public SimAnnBase::Controller {
ladanyi@956
   107
  public:
ladanyi@956
   108
    long iter, last_impr, max_iter, max_no_impr;
ladanyi@956
   109
    double temp, annealing_factor;
ladanyi@957
   110
    SimpleController() {
ladanyi@956
   111
      iter = last_impr = 0;
ladanyi@956
   112
      max_iter = 500000;
ladanyi@956
   113
      max_no_impr = 20000;
ladanyi@956
   114
      annealing_factor = 0.9999;
ladanyi@956
   115
      temp = 1000;
ladanyi@956
   116
    }
ladanyi@956
   117
    void acceptEvent() {
ladanyi@956
   118
      iter++;
ladanyi@956
   119
    }
ladanyi@956
   120
    void improveEvent() {
ladanyi@956
   121
      last_impr = iter;
ladanyi@956
   122
    }
ladanyi@956
   123
    void rejectEvent() {
ladanyi@956
   124
      iter++;
ladanyi@956
   125
    }
ladanyi@956
   126
    bool next() {
ladanyi@956
   127
      temp *= annealing_factor;
ladanyi@956
   128
      bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr);
ladanyi@956
   129
      return !quit;
ladanyi@956
   130
    }
ladanyi@957
   131
    bool accept() {
ladanyi@966
   132
      return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
ladanyi@966
   133
        temp));
ladanyi@966
   134
    }
ladanyi@966
   135
  };
ladanyi@966
   136
ladanyi@966
   137
  /*! \brief A controller with preset running time for the simulated annealing
ladanyi@966
   138
   *  class.
ladanyi@966
   139
   *  \todo Find a better name.
ladanyi@966
   140
   */
ladanyi@966
   141
  class AdvancedController : public SimAnnBase::Controller {
ladanyi@966
   142
  private:
ladanyi@966
   143
    double threshold() { return 0.0; }
ladanyi@966
   144
  public:
ladanyi@966
   145
    double alpha;
ladanyi@966
   146
    double temp;
ladanyi@966
   147
    double avg_cost;
ladanyi@966
   148
    double start_time, end_time;
ladanyi@966
   149
    void init() {
ladanyi@966
   150
      timeval tv;
ladanyi@966
   151
      gettimeofday(&tv, 0);
ladanyi@966
   152
      start_time = tv.tv_sec + double(tv.tv_usec) / 1e6;
ladanyi@966
   153
    }
ladanyi@966
   154
    void acceptEvent() {
ladanyi@966
   155
      avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost;
ladanyi@966
   156
    }
ladanyi@966
   157
    void improveEvent() {
ladanyi@966
   158
    }
ladanyi@966
   159
    void rejectEvent() {
ladanyi@966
   160
    }
ladanyi@966
   161
    bool next() {
ladanyi@966
   162
      // abs(avg_cost - base->getBestCost())
ladanyi@966
   163
      // ha nagy: cooling factor novelese
ladanyi@966
   164
      // ha kicsi: homerseklet novelese
ladanyi@966
   165
      // de mennyivel?
ladanyi@966
   166
      timeval tv;
ladanyi@966
   167
      gettimeofday(&tv, 0);
ladanyi@966
   168
      double elapsed_time = tv.tv_sec + double(tv.tv_usec) / 1e6 - start_time;
ladanyi@966
   169
      return elapsed_time < end_time;
ladanyi@966
   170
    }
ladanyi@966
   171
    bool accept() {
ladanyi@966
   172
      return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() /
ladanyi@966
   173
        temp));
ladanyi@956
   174
    }
ladanyi@956
   175
  };
ladanyi@956
   176
ladanyi@942
   177
}
ladanyi@918
   178
ladanyi@918
   179
#endif