Fight with Doxygen.
Victory hasn't been reached yet, but it's on the horizon.
5 /// \ingroup experimental
7 /// \brief Simulated annealing framework.
9 /// \todo A test and some demo should be added
10 /// \todo Doc should be improved
11 /// \author Akos Ladanyi
16 #include <lemon/time_measure.h>
20 /// \addtogroup experimental
25 /// \brief A base class for controllers.
26 class ControllerBase {
28 friend class SimAnnBase;
29 /// \brief Pointer to the simulated annealing base class.
31 /// \brief Initializes the controller.
32 virtual void init() {}
33 /// \brief This is called by the simulated annealing class when a
34 /// neighbouring state gets accepted.
35 virtual void acceptEvent() {}
36 /// \brief This is called by the simulated annealing class when the
37 /// accepted neighbouring state's cost is less than the best found one's.
38 virtual void improveEvent() {}
39 /// \brief This is called by the simulated annealing class when a
40 /// neighbouring state gets rejected.
41 virtual void rejectEvent() {}
42 /// \brief Decides whether to continue the annealing process or not.
43 virtual bool next() = 0;
44 /// \brief Decides whether to accept the current solution or not.
45 virtual bool accept() = 0;
46 /// \brief Destructor.
47 virtual ~ControllerBase() {}
50 /// \brief Skeleton of an entity class.
53 /// \brief Makes a minor change to the entity.
54 /// \return the new cost
55 virtual double mutate() = 0;
56 /// \brief Restores the entity to its previous state i.e. reverts the
57 /// effects of the last mutate().
58 virtual void revert() = 0;
59 /// \brief Makes a copy of the entity.
60 virtual EntityBase* clone() = 0;
61 /// \brief Makes a major change to the entity.
62 virtual void randomize() = 0;
63 /// \brief Destructor.
64 virtual ~EntityBase() {}
67 /// \brief Simulated annealing abstract base class.
68 /// Can be used to derive a custom simulated annealing class if \ref SimAnn
69 /// doesn't fit your needs.
72 /// \brief Pointer to the controller.
73 ControllerBase *controller;
74 /// \brief Cost of the current solution.
76 /// \brief Cost of the best solution.
78 /// \brief Cost of the previous solution.
80 /// \brief Cost of the solution preceding the previous one.
81 double prev_prev_cost;
82 /// \brief Number of iterations.
84 /// \brief Number of iterations which did not improve the solution since
85 /// the last improvement.
88 /// \brief Step to a neighbouring state.
89 virtual double mutate() = 0;
90 /// \brief Reverts the last mutate().
91 virtual void revert() = 0;
92 /// \brief Saves the current solution as the best one.
93 virtual void saveAsBest() = 0;
94 /// \brief Does initializations before each run.
97 curr_cost = prev_cost = prev_prev_cost = best_cost =
98 std::numeric_limits<double>::infinity();
102 /// \brief Sets the controller class to use.
103 void setController(ControllerBase &_controller) {
104 controller = &_controller;
105 controller->simann = this;
107 /// \brief Returns the cost of the current solution.
108 double getCurrCost() const { return curr_cost; }
109 /// \brief Returns the cost of the previous solution.
110 double getPrevCost() const { return prev_cost; }
111 /// \brief Returns the cost of the best solution.
112 double getBestCost() const { return best_cost; }
113 /// \brief Returns the number of iterations done.
114 long getIter() const { return iter; }
115 /// \brief Returns the ordinal number of the last iteration when the
116 /// solution was improved.
117 long getLastImpr() const { return last_impr; }
118 /// \brief Performs one iteration.
121 prev_prev_cost = prev_cost;
122 prev_cost = curr_cost;
123 curr_cost = mutate();
124 if (controller->accept()) {
125 controller->acceptEvent();
127 if (curr_cost < best_cost) {
128 best_cost = curr_cost;
130 controller->improveEvent();
135 curr_cost = prev_cost;
136 prev_cost = prev_prev_cost;
137 controller->rejectEvent();
139 return controller->next();
141 /// \brief Performs a given number of iterations.
142 /// \param n the number of iterations
144 for(; n > 0 && step(); --n) ;
147 /// \brief Starts the annealing process.
150 do { } while (step());
152 /// \brief Destructor.
153 virtual ~SimAnnBase() {}
156 /// \brief Simulated annealing class.
157 class SimAnn : public SimAnnBase {
159 /// \brief Pointer to the current entity.
160 EntityBase *curr_ent;
161 /// \brief Pointer to the best entity.
162 EntityBase *best_ent;
163 /// \brief Does initializations before each run.
166 if (best_ent) delete best_ent;
168 curr_ent->randomize();
171 /// \brief Constructor.
172 SimAnn() : curr_ent(NULL), best_ent(NULL) {}
173 /// \brief Destructor.
175 if (best_ent) delete best_ent;
177 /// \brief Step to a neighbouring state.
179 return curr_ent->mutate();
181 /// \brief Reverts the last mutate().
185 /// \brief Saves the current solution as the best one.
187 if (best_ent) delete best_ent;
188 best_ent = curr_ent->clone();
190 /// \brief Sets the current entity.
191 void setEntity(EntityBase &_ent) {
194 /// \brief Returns a copy of the best found entity.
195 EntityBase* getBestEntity() { return best_ent->clone(); }
198 /// \brief A simple controller for the simulated annealing class.
199 /// This controller starts from a given initial temperature and evenly
201 class SimpleController : public ControllerBase {
203 /// \brief Maximum number of iterations.
205 /// \brief Maximum number of iterations which do not improve the
208 /// \brief Temperature.
210 /// \brief Annealing factor.
212 /// \brief Constructor.
213 /// \param _max_iter maximum number of iterations
214 /// \param _max_no_impr maximum number of consecutive iterations which do
215 /// not yield a better solution
216 /// \param _temp initial temperature
217 /// \param _ann_fact annealing factor
219 SimpleController(long _max_iter = 500000, long _max_no_impr = 20000,
220 double _temp = 1000.0, double _ann_fact = 0.9999) : max_iter(_max_iter),
221 max_no_impr(_max_no_impr), temp(_temp), ann_fact(_ann_fact)
225 /// \brief This is called when a neighbouring state gets accepted.
226 void acceptEvent() {}
227 /// \brief This is called when the accepted neighbouring state's cost is
228 /// less than the best found one's.
229 void improveEvent() {}
230 /// \brief This is called when a neighbouring state gets rejected.
231 void rejectEvent() {}
232 /// \brief Decides whether to continue the annealing process or not. Also
233 /// decreases the temperature.
236 bool quit = (simann->getIter() > max_iter) ||
237 (simann->getIter() - simann->getLastImpr() > max_no_impr);
240 /// \brief Decides whether to accept the current solution or not.
242 double cost_diff = simann->getCurrCost() - simann->getPrevCost();
243 return (drand48() <= exp(-(cost_diff / temp)));
245 /// \brief Destructor.
246 virtual ~SimpleController() {}
249 /// \brief A controller with preset running time for the simulated annealing
251 /// With this controller you can set the running time of the annealing
252 /// process in advance. It works the following way: the controller measures
253 /// a kind of divergence. The divergence is the difference of the average
254 /// cost of the recently found solutions the cost of the best found one. In
255 /// case this divergence is greater than a given threshold, then we decrease
256 /// the annealing factor, that is we cool the system faster. In case the
257 /// divergence is lower than the threshold, then we increase the temperature.
258 /// The threshold is a function of the elapsed time which reaches zero at the
259 /// desired end time.
260 class AdvancedController : public ControllerBase {
262 /// \brief Timer class to measure the elapsed time.
264 /// \brief Calculates the threshold value.
265 /// \param time the elapsed time in seconds
266 virtual double threshold(double time) {
267 return (-1.0) * start_threshold / end_time * time + start_threshold;
269 /// \brief Parameter used to calculate the running average.
271 /// \brief Parameter used to decrease the annealing factor.
273 /// \brief Parameter used to increase the temperature.
275 /// \brief The time at the end of the algorithm.
277 /// \brief The time at the start of the algorithm.
279 /// \brief Starting threshold.
280 double start_threshold;
281 /// \brief Average cost of recent solutions.
283 /// \brief Temperature.
285 /// \brief Annealing factor.
287 /// \brief Initial annealing factor.
288 double init_ann_fact;
289 /// \brief True when the annealing process has been started.
292 /// \brief Constructor.
293 /// \param _end_time running time in seconds
294 /// \param _alpha parameter used to calculate the running average
295 /// \param _beta parameter used to decrease the annealing factor
296 /// \param _gamma parameter used to increase the temperature
297 /// \param _ann_fact initial annealing factor
298 AdvancedController(double _end_time, double _alpha = 0.2,
299 double _beta = 0.9, double _gamma = 1.6, double _ann_fact = 0.9999) :
300 alpha(_alpha), beta(_beta), gamma(_gamma), end_time(_end_time),
301 ann_fact(_ann_fact), init_ann_fact(_ann_fact), start(false)
305 /// \brief Does initializations before each run.
307 avg_cost = simann->getCurrCost();
309 /// \brief This is called when a neighbouring state gets accepted.
311 avg_cost = alpha * simann->getCurrCost() + (1.0 - alpha) * avg_cost;
316 // calculate starting threshold and starting temperature
317 start_threshold = 5.0 * fabs(simann->getBestCost() - avg_cost);
324 /// \brief Decides whether to continue the annealing process or not.
330 double elapsed_time = timer.realTime();
331 if (fabs(avg_cost - simann->getBestCost()) > threshold(elapsed_time)) {
332 // decrease the annealing factor
336 // increase the temperature
338 // reset the annealing factor
339 ann_fact = init_ann_fact;
342 return elapsed_time < end_time;
345 /// \brief Decides whether to accept the current solution or not.
351 double cost_diff = simann->getCurrCost() - simann->getPrevCost();
352 return (drand48() <= exp(-(cost_diff / temp)));
355 /// \brief Destructor.
356 virtual ~AdvancedController() {}