28 } |
28 } |
29 void setController(Controller &_controller) { |
29 void setController(Controller &_controller) { |
30 controller = &_controller; |
30 controller = &_controller; |
31 controller->setBase(this); |
31 controller->setBase(this); |
32 } |
32 } |
33 double getCurrCost() { return curr_cost; } |
33 double getCurrCost() const { return curr_cost; } |
34 double getPrevCost() { return prev_cost; } |
34 double getPrevCost() const { return prev_cost; } |
35 double getBestCost() { return best_cost; } |
35 double getBestCost() const { return best_cost; } |
36 void run() { |
36 void run() { |
37 controller->init(); |
37 controller->init(); |
38 while (controller->next()) { |
38 do { |
39 mutate(); |
39 mutate(); |
40 if (controller->accept()) { |
40 if (controller->accept()) { |
41 controller->acceptEvent(); |
41 controller->acceptEvent(); |
42 if (curr_cost < best_cost) { |
42 if (curr_cost < best_cost) { |
43 saveAsBest(); |
43 saveAsBest(); |
138 temp *= ann_fact; |
141 temp *= ann_fact; |
139 bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr); |
142 bool quit = (iter > max_iter) || (iter - last_impr > max_no_impr); |
140 return !quit; |
143 return !quit; |
141 } |
144 } |
142 bool accept() { |
145 bool accept() { |
143 return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() / |
146 double cost_diff = base->getPrevCost() - base->getCurrCost(); |
144 temp)); |
147 if (cost_diff < 0.0) { |
|
148 return (drand48() <= exp(cost_diff / temp)); |
|
149 } |
|
150 else { |
|
151 return true; |
|
152 } |
145 } |
153 } |
146 }; |
154 }; |
147 |
155 |
148 /*! \brief A controller with preset running time for the simulated annealing |
156 /*! \brief A controller with preset running time for the simulated annealing |
149 * class. |
157 * class. |
150 * \todo Find a better name. |
158 * \todo Find a better name. |
151 */ |
159 */ |
152 class AdvancedController : public SimAnnBase::Controller { |
160 class AdvancedController : public SimAnnBase::Controller { |
153 private: |
161 private: |
|
162 Timer timer; |
154 /*! \param time the elapsed time in seconds */ |
163 /*! \param time the elapsed time in seconds */ |
155 double threshold(double time) { return 0.0; } |
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)); |
|
169 } |
156 public: |
170 public: |
157 double alpha, beta, gamma; |
171 double alpha, beta, gamma; |
158 double end_time, start_time; |
172 double end_time, start_time; |
|
173 double start_threshold; |
159 double avg_cost; |
174 double avg_cost; |
160 double temp, ann_fact; |
175 double temp, ann_fact; |
161 /*! \param _end_time running_time |
176 bool warmup; |
|
177 long iter; |
|
178 /*! \param _end_time running time in seconds |
162 * \param _alpha parameter used to calculate the running average |
179 * \param _alpha parameter used to calculate the running average |
163 * \param _beta parameter used to decrease the annealing factor |
180 * \param _beta parameter used to decrease the annealing factor |
164 * \param _gamma parameter used to increase the temperature |
181 * \param _gamma parameter used to increase the temperature |
165 */ |
182 */ |
166 AdvancedController(double _end_time, double _alpha = 0.2, |
183 AdvancedController(double _end_time, double _alpha = 0.2, |
167 double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta), |
184 double _beta = 0.9, double _gamma = 1.2) : alpha(_alpha), beta(_beta), |
168 gamma(_gamma), end_time(_end_time) {} |
185 gamma(_gamma), end_time(_end_time), ann_fact(0.9999), warmup(true), |
|
186 iter(0) {} |
169 void init() { |
187 void init() { |
170 timeval tv; |
188 avg_cost = base->getCurrCost(); |
171 gettimeofday(&tv, 0); |
|
172 start_time = tv.tv_sec + double(tv.tv_usec) / 1e6; |
|
173 } |
189 } |
174 void acceptEvent() { |
190 void acceptEvent() { |
175 avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost; |
191 avg_cost = alpha * base->getCurrCost() + (1.0 - alpha) * avg_cost; |
|
192 iter++; |
176 } |
193 } |
177 void improveEvent() { |
194 void improveEvent() { |
178 } |
195 } |
179 void rejectEvent() { |
196 void rejectEvent() { |
|
197 iter++; |
180 } |
198 } |
181 bool next() { |
199 bool next() { |
182 timeval tv; |
200 if (warmup) { |
183 gettimeofday(&tv, 0); |
201 static double max_cost_diff = 0.0; |
184 double elapsed_time = tv.tv_sec + double(tv.tv_usec) / 1e6 - start_time; |
202 double cost_diff = base->getCurrCost() - base->getPrevCost(); |
185 if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) { |
203 // jo ez igy egyaltalan? -> prev_cost |
186 // decrease the annealing factor |
204 if ((cost_diff > 0.0) && (cost_diff > max_cost_diff)) { |
187 ann_fact *= beta; |
205 max_cost_diff = cost_diff; |
|
206 } |
|
207 // How to set the starting temperature when all the 100 first |
|
208 // iterations improve the solution? |
|
209 if (iter > 100) { |
|
210 // calculate starting threshold and starting temperature |
|
211 start_threshold = fabs(base->getBestCost() - avg_cost); |
|
212 temp = exp(max_cost_diff) / 0.5; |
|
213 warmup = false; |
|
214 timer.reset(); |
|
215 } |
|
216 return true; |
188 } |
217 } |
189 else { |
218 else { |
190 // increase the temperature |
219 double elapsed_time = timer.getRealTime(); |
191 temp *= gamma; |
220 if (fabs(avg_cost - base->getBestCost()) > threshold(elapsed_time)) { |
192 } |
221 // decrease the annealing factor |
193 temp *= ann_fact; |
222 ann_fact *= beta; |
194 return elapsed_time < end_time; |
223 } |
|
224 else { |
|
225 // increase the temperature |
|
226 temp *= gamma; |
|
227 } |
|
228 temp *= ann_fact; |
|
229 return elapsed_time < end_time; |
|
230 } |
195 } |
231 } |
196 bool accept() { |
232 bool accept() { |
197 return (drand48() <= exp(base->getPrevCost() - base->getCurrCost() / |
233 if (warmup) { |
198 temp)); |
234 // we accept eveything during the "warm up" phase |
|
235 return true; |
|
236 } |
|
237 else { |
|
238 double cost_diff = base->getPrevCost() - base->getCurrCost(); |
|
239 if (cost_diff < 0.0) { |
|
240 return (drand48() <= exp(cost_diff / temp)); |
|
241 } |
|
242 else { |
|
243 return true; |
|
244 } |
|
245 } |
199 } |
246 } |
200 }; |
247 }; |
201 |
248 |
202 } |
249 } |
203 |
250 |