6 #include <lemon/time_measure.h>
10 const double INFTY = 1e24;
16 Controller *controller;
21 double prev_prev_cost;
23 virtual void mutate() = 0;
24 virtual void revert() = 0;
25 virtual void saveAsBest() = 0;
28 best_cost = prev_cost = prev_prev_cost = INFTY;
30 void setController(Controller &_controller) {
31 controller = &_controller;
32 controller->setBase(this);
34 double getCurrCost() const { return curr_cost; }
35 double getPrevCost() const { return prev_cost; }
36 double getBestCost() const { return best_cost; }
41 if (controller->accept()) {
42 controller->acceptEvent();
43 if (curr_cost < best_cost) {
45 controller->improveEvent();
50 controller->rejectEvent();
52 } while (controller->next());
55 /*! \brief A base class for controllers. */
59 virtual void init() {}
60 /*! \brief This is called when a neighbouring state gets accepted. */
61 virtual void acceptEvent() {}
62 /*! \brief This is called when the accepted neighbouring state's cost is
63 * less than the best found one's.
65 virtual void improveEvent() {}
66 /*! \brief This is called when a neighbouring state gets rejected. */
67 virtual void rejectEvent() {}
68 virtual void setBase(SimAnnBase *_base) { base = _base; }
70 virtual bool next() = 0;
72 virtual bool accept() = 0;
77 class SimAnn : public SimAnnBase {
82 SimAnn() : SimAnnBase() {}
83 void setEntity(E &ent) {
84 curr_ent = new E(ent);
85 best_ent = new E(ent);
86 curr_cost = curr_ent->getCost();
88 E getBestEntity() { return *best_ent; }
90 prev_prev_cost = prev_cost;
91 prev_cost = curr_cost;
93 curr_cost = curr_ent->getCost();
97 curr_cost = prev_cost;
98 prev_cost = prev_prev_cost;
102 best_ent = new E(*curr_ent);
103 best_cost = curr_cost;
107 class EntitySkeleton {
109 /*! \return the cost of the entity */
110 double getCost() { return 0.0; }
111 /*! \brief Makes a minor change to the entity. */
113 /*! \brief Restores the entity to its previous state i.e. reverts the
114 * effects of the last mutate.
119 /*! \brief A simple controller for the simulated annealing class.
120 * \todo Find a way to set the various parameters.
122 class SimpleController : public SimAnnBase::Controller {
124 long iter, last_impr, max_iter, max_no_impr;
125 double temp, ann_fact;
126 /*! \param _max_iter maximum number of iterations
127 * \param _max_no_impr maximum number of consecutive iterations which do
128 * not yield a better solution
129 * \param _temp initial temperature
130 * \param _ann_fact annealing factor
132 SimpleController(long _max_iter = 500000, long _max_no_impr = 20000,
133 double _temp = 1000.0, double _ann_fact = 0.9999) : iter(0), last_impr(0),
134 max_iter(_max_iter), max_no_impr(_max_no_impr), temp(_temp),
135 ann_fact(_ann_fact) {}
139 void improveEvent() {
147 bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr);
151 double cost_diff = base->getPrevCost() - base->getCurrCost();
152 if (cost_diff < 0.0) {
153 bool ret = drand48() <= exp(cost_diff / temp);
162 /*! \brief A controller with preset running time for the simulated annealing
164 * \todo Find a better name.
166 class AdvancedController : public SimAnnBase::Controller {
169 /*! \param time the elapsed time in seconds */
170 virtual double threshold(double time) {
173 static double xm = 5.0 / end_time;
174 static double ym = start_threshold / (1 / log(1.2) - 1 / log(5.0 + 1.2));
175 return ym * (1 / log(xm * time + 1.2) - 1 / log(5.0 + 1.2));
177 return (-1.0) * start_threshold / end_time * time + start_threshold;
180 double alpha, beta, gamma;
181 double end_time, start_time;
182 double start_threshold;
184 double temp, ann_fact;
186 /*! \param _end_time running time in seconds
187 * \param _alpha parameter used to calculate the running average
188 * \param _beta parameter used to decrease the annealing factor
189 * \param _gamma parameter used to increase the temperature
191 AdvancedController(double _end_time, double _alpha = 0.2,
192 double _beta = 0.9, double _gamma = 1.6) : alpha(_alpha), beta(_beta),
193 gamma(_gamma), end_time(_end_time), ann_fact(0.99999999), warmup(true) {}
195 avg_cost = base->getCurrCost();
198 avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost;
203 // calculate starting threshold and starting temperature
204 start_threshold = 5.0 * fabs(base->getBestCost() - avg_cost);
205 //temp = max_cost_diff / log(0.5);
212 void improveEvent() {
221 double elapsed_time = timer.getRealTime();
222 if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
223 // decrease the annealing factor
227 // increase the temperature
229 ann_fact = 0.99999999;
232 return elapsed_time < end_time;
237 // we accept eveything during the "warm up" phase
241 double cost_diff = base->getPrevCost() - base->getCurrCost();
242 if (cost_diff < 0.0) {
243 return (drand48() <= exp(cost_diff / temp));