lemon/simann.h
author deba
Tue, 17 Oct 2006 10:50:57 +0000
changeset 2247 269a0dcee70b
parent 2229 4dbb6dd2dd4b
child 2304 108d6db4f32a
permissions -rw-r--r--
Update the Path concept
Concept check for paths

DirPath renamed to Path
The interface updated to the new lemon interface
Make difference between the empty path and the path from one node
Builder interface have not been changed
// I wanted but there was not accordance about it

UPath is removed
It was a buggy implementation, it could not iterate on the
nodes in the right order
Right way to use undirected paths => path of edges in undirected graphs

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