6 #include <lemon/time_measure.h>
10 const double INFTY = 1e24;
16 Controller *controller;
22 virtual void mutate() = 0;
23 virtual void revert() = 0;
24 virtual void saveAsBest() = 0;
27 curr_cost = prev_cost = best_cost = INFTY;
29 void setController(Controller &_controller) {
30 controller = &_controller;
31 controller->setBase(this);
33 double getCurrCost() const { return curr_cost; }
34 double getPrevCost() const { return prev_cost; }
35 double getBestCost() const { return best_cost; }
40 if (controller->accept()) {
41 controller->acceptEvent();
42 if (curr_cost < best_cost) {
44 controller->improveEvent();
49 controller->rejectEvent();
51 } while (controller->next());
54 /*! \brief A base class for controllers. */
58 virtual void init() {}
59 /*! \brief This is called when a neighbouring state gets accepted. */
60 virtual void acceptEvent() {}
61 /*! \brief This is called when the accepted neighbouring state's cost is
62 * less than the best found one's.
64 virtual void improveEvent() {}
65 /*! \brief This is called when a neighbouring state gets rejected. */
66 virtual void rejectEvent() {}
67 virtual void setBase(SimAnnBase *_base) { base = _base; }
69 virtual bool next() = 0;
71 virtual bool accept() = 0;
75 /*! \todo atgondolni mi is ez a prev_cost */
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);
87 E getBestEntity() { return *best_ent; }
89 prev_cost = curr_cost;
90 curr_cost = curr_ent->mutate();
94 curr_cost = prev_cost;
97 *best_ent = *curr_ent;
98 best_cost = curr_cost;
102 class EntitySkeleton {
104 /*! \brief Makes a minor change to the entity.
105 * \return the new cost
107 double mutate() { return 0.0; }
108 /*! \brief Restores the entity to its previous state i.e. reverts the
109 * effects of the last mutate.
114 /*! \brief A simple controller for the simulated annealing class.
115 * \todo Find a way to set the various parameters.
117 class SimpleController : public SimAnnBase::Controller {
119 long iter, last_impr, max_iter, max_no_impr;
120 double temp, ann_fact;
121 /*! \param _max_iter maximum number of iterations
122 * \param _max_no_impr maximum number of consecutive iterations which do
123 * not yield a better solution
124 * \param _temp initial temperature
125 * \param _ann_fact annealing factor
127 SimpleController(long _max_iter = 500000, long _max_no_impr = 20000,
128 double _temp = 1000, double _ann_fact = 0.9999) : iter(0), last_impr(0),
129 max_iter(_max_iter), max_no_impr(_max_no_impr), temp(_temp),
130 ann_fact(_ann_fact) {}
134 void improveEvent() {
142 bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr);
146 double cost_diff = base->getPrevCost() - base->getCurrCost();
147 if (cost_diff < 0.0) {
148 return (drand48() <= exp(cost_diff / temp));
156 /*! \brief A controller with preset running time for the simulated annealing
158 * \todo Find a better name.
160 class AdvancedController : public SimAnnBase::Controller {
163 /*! \param time the elapsed time in seconds */
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));
171 double alpha, beta, gamma;
172 double end_time, start_time;
173 double start_threshold;
175 double temp, ann_fact;
178 /*! \param _end_time running time in seconds
179 * \param _alpha parameter used to calculate the running average
180 * \param _beta parameter used to decrease the annealing factor
181 * \param _gamma parameter used to increase the temperature
183 AdvancedController(double _end_time, double _alpha = 0.2,
184 double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta),
185 gamma(_gamma), end_time(_end_time), ann_fact(0.9999), warmup(true),
188 avg_cost = base->getCurrCost();
191 avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost;
194 void improveEvent() {
201 static double max_cost_diff = 0.0;
202 double cost_diff = base->getCurrCost() - base->getPrevCost();
203 // jo ez igy egyaltalan? -> prev_cost
204 if ((cost_diff > 0.0) && (cost_diff > max_cost_diff)) {
205 max_cost_diff = cost_diff;
207 // How to set the starting temperature when all the 100 first
208 // iterations improve the solution?
210 // calculate starting threshold and starting temperature
211 start_threshold = fabs(base->getBestCost() - avg_cost);
212 temp = exp(max_cost_diff) / 0.5;
219 double elapsed_time = timer.getRealTime();
220 if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) {
221 // decrease the annealing factor
225 // increase the temperature
229 return elapsed_time < end_time;
234 // we accept eveything during the "warm up" phase
238 double cost_diff = base->getPrevCost() - base->getCurrCost();
239 if (cost_diff < 0.0) {
240 return (drand48() <= exp(cost_diff / temp));