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@2229
|
260 |
return (rnd.getReal() <= 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@2229
|
368 |
return (rnd.getReal() <= 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
|