- The number of gcc-4.0 warnings has significantly decreases.
- Some code clean-up in gui
     4 /// \ingroup experimental
 
     6 /// \brief Simulated annealing framework.
 
     7 /// \author Akos Ladanyi
 
    11 #include <lemon/time_measure.h>
 
    15 /// \addtogroup experimental
 
    18   /*! \brief A base class for controllers. */
 
    19   class ControllerBase {
 
    20     friend class SimAnnBase;
 
    22     /*! \brief Pointer to the simulated annealing base class. */
 
    24     /*! \brief Initializes the controller. */
 
    25     virtual void init() {}
 
    26     /*! \brief This is called when a neighbouring state gets accepted. */
 
    27     virtual void acceptEvent() {}
 
    28     /*! \brief This is called when the accepted neighbouring state's cost is
 
    29      *  less than the best found one's.
 
    31     virtual void improveEvent() {}
 
    32     /*! \brief This is called when a neighbouring state gets rejected. */
 
    33     virtual void rejectEvent() {}
 
    34     /*! \brief Decides whether to continue the annealing process or not. */
 
    35     virtual bool next() = 0;
 
    36     /*! \brief Decides whether to accept the current solution or not. */
 
    37     virtual bool accept() = 0;
 
    40   /*! \brief Skeleton of an entity class. */
 
    43     /*! \brief Makes a minor change to the entity.
 
    44      *  \return the new cost
 
    46     virtual double mutate() = 0;
 
    47     /*! \brief Restores the entity to its previous state i.e. reverts the
 
    48      *  effects of the last mutate().
 
    50     virtual void revert() = 0;
 
    51     /*! \brief Makes a copy of the entity. */
 
    52     virtual EntityBase* clone() = 0;
 
    53     /*! \brief Makes a major change to the entity. */
 
    54     virtual void randomize() = 0;
 
    57   /*! \brief Simulated annealing base class. */
 
    60     /*! Pointer to the controller. */
 
    61     ControllerBase *controller;
 
    62     /*! \brief Cost of the current solution. */
 
    64     /*! \brief Cost of the best solution. */
 
    66     /*! \brief Cost of the previous solution. */
 
    68     /*! \brief Cost of the solution preceding the previous one. */
 
    69     double prev_prev_cost;
 
    70     /*! \brief Number of iterations. */
 
    72     /*! \brief Number of iterations which did not improve the solution since
 
    73      *  the last improvement. */
 
    76     /*! \brief Step to a neighbouring state. */
 
    77     virtual double mutate() = 0;
 
    78     /*! \brief Reverts the last mutate(). */
 
    79     virtual void revert() = 0;
 
    80     /*! \brief Saves the current solution as the best one. */
 
    81     virtual void saveAsBest() = 0;
 
    82     /*! \brief Does initializations before each run. */
 
    85       curr_cost = prev_cost = prev_prev_cost = best_cost =
 
    86         std::numeric_limits<double>::infinity();
 
    90     /*! \brief Sets the controller class to use. */
 
    91     void setController(ControllerBase &_controller) {
 
    92       controller = &_controller;
 
    93       controller->simann = this;
 
    95     /*! \brief Returns the cost of the current solution. */
 
    96     double getCurrCost() const { return curr_cost; }
 
    97     /*! \brief Returns the cost of the previous solution. */
 
    98     double getPrevCost() const { return prev_cost; }
 
    99     /*! \brief Returns the cost of the best solution. */
 
   100     double getBestCost() const { return best_cost; }
 
   101     /*! \brief Returns the number of iterations. */
 
   102     long getIter() const { return iter; }
 
   103     /*! \brief Returns the number of the last iteration when the solution was
 
   106     long getLastImpr() const { return last_impr; }
 
   107     /*! \brief Performs one iteration. */
 
   110       prev_prev_cost = prev_cost;
 
   111       prev_cost = curr_cost;
 
   112       curr_cost = mutate();
 
   113       if (controller->accept()) {
 
   114         controller->acceptEvent();
 
   116         if (curr_cost < best_cost) {
 
   117           best_cost = curr_cost;
 
   119           controller->improveEvent();
 
   124         curr_cost = prev_cost;
 
   125         prev_cost = prev_prev_cost;
 
   126         controller->rejectEvent();
 
   128       return controller->next();
 
   130     /*! \brief Performs a given number of iterations.
 
   131      *  \param n the number of iterations
 
   134       for(; n > 0 && step(); --n) ;
 
   137     /*! \brief Starts the annealing process. */
 
   140       do { } while (step());
 
   144   /*! \brief Simulated annealing class. */
 
   145   class SimAnn : public SimAnnBase {
 
   147     /*! \brief Pointer to the current entity. */
 
   148     EntityBase *curr_ent;
 
   149     /*! \brief Pointer to the best entity. */
 
   150     EntityBase *best_ent;
 
   151     /*! \brief Does initializations before each run. */
 
   154       if (best_ent) delete best_ent;
 
   156       curr_ent->randomize();
 
   159     /*! \brief Constructor. */
 
   160     SimAnn() : curr_ent(NULL), best_ent(NULL) {}
 
   161     /*! \brief Destructor. */
 
   163       if (best_ent) delete best_ent;
 
   165     /*! \brief Step to a neighbouring state. */
 
   167       return curr_ent->mutate();
 
   169     /*! \brief Reverts the last mutate(). */
 
   173     /*! \brief Saves the current solution as the best one. */
 
   175       if (best_ent) delete best_ent;
 
   176       best_ent = curr_ent->clone();
 
   178     /*! \brief Sets the current entity. */
 
   179     void setEntity(EntityBase &_ent) {
 
   182     /*! \brief Returns a copy of the best found entity. */
 
   183     EntityBase* getBestEntity() { return best_ent->clone(); }
 
   186   /*! \brief A simple controller for the simulated annealing class. */
 
   187   class SimpleController : public ControllerBase {
 
   189     /*! \brief Maximum number of iterations. */
 
   191     /*! \brief Maximum number of iterations which do not improve the
 
   194     /*! \brief Temperature. */
 
   196     /*! \brief Annealing factor. */
 
   198     /*! \brief Constructor.
 
   199      *  \param _max_iter maximum number of iterations
 
   200      *  \param _max_no_impr maximum number of consecutive iterations which do
 
   201      *         not yield a better solution
 
   202      *  \param _temp initial temperature
 
   203      *  \param _ann_fact annealing factor
 
   205     SimpleController(long _max_iter = 500000, long _max_no_impr = 20000,
 
   206     double _temp = 1000.0, double _ann_fact = 0.9999) : max_iter(_max_iter),
 
   207       max_no_impr(_max_no_impr), temp(_temp), ann_fact(_ann_fact)
 
   211     /*! \brief This is called when a neighbouring state gets accepted. */
 
   212     void acceptEvent() {}
 
   213     /*! \brief This is called when the accepted neighbouring state's cost is
 
   214      *  less than the best found one's.
 
   216     void improveEvent() {}
 
   217     /*! \brief This is called when a neighbouring state gets rejected. */
 
   218     void rejectEvent() {}
 
   219     /*! \brief Decides whether to continue the annealing process or not. Also
 
   220      *  decreases the temperature. */
 
   223       bool quit = (simann->getIter() > max_iter) ||
 
   224         (simann->getIter() - simann->getLastImpr() > max_no_impr);
 
   227     /*! \brief Decides whether to accept the current solution or not. */
 
   229       double cost_diff = simann->getPrevCost() - simann->getCurrCost();
 
   230       return (drand48() <= exp(cost_diff / temp));
 
   234   /*! \brief A controller with preset running time for the simulated annealing
 
   237    *  With this controller you can set the running time of the annealing
 
   238    *  process in advance. It works the following way: the controller measures
 
   239    *  a kind of divergence. The divergence is the difference of the average
 
   240    *  cost of the recently found solutions the cost of the best found one. In
 
   241    *  case this divergence is greater than a given threshold, then we decrease
 
   242    *  the annealing factor, that is we cool the system faster. In case the
 
   243    *  divergence is lower than the threshold, then we increase the temperature.
 
   244    *  The threshold is a function of the elapsed time which reaches zero at the
 
   247   class AdvancedController : public ControllerBase {
 
   250     /*! \param time the elapsed time in seconds */
 
   251     virtual double threshold(double time) {
 
   252       return (-1.0) * start_threshold / end_time * time + start_threshold;
 
   258     /*! \brief The time at the end of the algorithm. */
 
   260     /*! \brief The time at the start of the algorithm. */
 
   262     /*! \brief Starting threshold. */
 
   263     double start_threshold;
 
   264     /*! \brief Average cost of recent solutions. */
 
   266     /*! \brief Temperature. */
 
   268     /*! \brief Annealing factor. */
 
   270     /*! \brief Initial annealing factor. */
 
   271     double init_ann_fact;
 
   273     /*! \brief Constructor.
 
   274      *  \param _end_time running time in seconds
 
   275      *  \param _alpha parameter used to calculate the running average
 
   276      *  \param _beta parameter used to decrease the annealing factor
 
   277      *  \param _gamma parameter used to increase the temperature
 
   278      *  \param _ann_fact initial annealing factor
 
   280     AdvancedController(double _end_time, double _alpha = 0.2,
 
   281     double _beta = 0.9, double _gamma = 1.6, double _ann_fact = 0.9999) :
 
   282     alpha(_alpha), beta(_beta), gamma(_gamma), end_time(_end_time),
 
   283     ann_fact(_ann_fact), init_ann_fact(_ann_fact), warmup(true)
 
   288       avg_cost = simann->getCurrCost();
 
   290     /*! \brief This is called when a neighbouring state gets accepted. */
 
   292       avg_cost = alpha * simann->getCurrCost() + (1.0 - alpha) * avg_cost;
 
   297           // calculate starting threshold and starting temperature
 
   298           start_threshold = 5.0 * fabs(simann->getBestCost() - avg_cost);
 
   305     /*! \brief Decides whether to continue the annealing process or not. */
 
   311         double elapsed_time = timer.getRealTime();
 
   312         if (fabs(avg_cost - simann->getBestCost()) > threshold(elapsed_time)) {
 
   313           // decrease the annealing factor
 
   317           // increase the temperature
 
   319           // reset the annealing factor
 
   320           ann_fact = init_ann_fact;
 
   323         return elapsed_time < end_time;
 
   326     /*! \brief Decides whether to accept the current solution or not. */
 
   329         // we accept eveything during the "warm up" phase
 
   333         double cost_diff = simann->getPrevCost() - simann->getCurrCost();
 
   334         if (cost_diff < 0.0) {
 
   335           return (drand48() <= exp(cost_diff / temp));