deba@2067
|
1 |
/* -*- C++ -*-
|
deba@2067
|
2 |
*
|
deba@2067
|
3 |
* This file is a part of LEMON, a generic C++ optimization library
|
deba@2067
|
4 |
*
|
deba@2067
|
5 |
* Copyright (C) 2003-2006
|
deba@2067
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
deba@2067
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
deba@2067
|
8 |
*
|
deba@2067
|
9 |
* Permission to use, modify and distribute this software is granted
|
deba@2067
|
10 |
* provided that this copyright notice appears in all copies. For
|
deba@2067
|
11 |
* precise terms see the accompanying LICENSE file.
|
deba@2067
|
12 |
*
|
deba@2067
|
13 |
* This software is provided "AS IS" with no warranty of any kind,
|
deba@2067
|
14 |
* express or implied, and with no claim as to its suitability for any
|
deba@2067
|
15 |
* purpose.
|
deba@2067
|
16 |
*
|
deba@2067
|
17 |
*/
|
deba@2067
|
18 |
|
deba@2067
|
19 |
|
deba@2067
|
20 |
#ifndef LEMON_TABU_SEARCH_H
|
deba@2067
|
21 |
#define LEMON_TABU_SEARCH_H
|
deba@2067
|
22 |
|
deba@2067
|
23 |
/// \ingroup experimental
|
deba@2067
|
24 |
/// \file
|
deba@2067
|
25 |
/// \brief TabuSearch algorithm.
|
deba@2067
|
26 |
///
|
deba@2067
|
27 |
/// \author Szabadkai Mark
|
deba@2067
|
28 |
|
deba@2067
|
29 |
#include <lemon/bits/utility.h>
|
deba@2067
|
30 |
#include <lemon/error.h>
|
deba@2067
|
31 |
#include <lemon/time_measure.h>
|
deba@2067
|
32 |
#include <functional>
|
deba@2067
|
33 |
#include <deque>
|
deba@2067
|
34 |
|
deba@2067
|
35 |
|
deba@2067
|
36 |
namespace lemon {
|
deba@2067
|
37 |
|
deba@2067
|
38 |
/// \brief Default Traits for TabuSearch class.
|
deba@2067
|
39 |
///
|
deba@2067
|
40 |
/// This template defines the needed types for the \ref TabuSearch class.
|
deba@2067
|
41 |
/// Is main purpos is to simplify the main class's template interface,
|
deba@2067
|
42 |
/// but it provides the EdgeIt type, passing to the concrete graph wheter
|
deba@2067
|
43 |
/// it is directed or undirected.
|
deba@2067
|
44 |
#ifdef DOXYGEN
|
deba@2067
|
45 |
template< typename GRAPH, typename VALUE,
|
deba@2067
|
46 |
typename HEIGHTMAP, typename BETTER, bool UNDIR >
|
deba@2067
|
47 |
#else
|
deba@2067
|
48 |
template< typename GRAPH, typename VALUE,
|
deba@2067
|
49 |
typename HEIGHTMAP = typename GRAPH::template NodeMap<VALUE>,
|
deba@2067
|
50 |
typename BETTER = std::less<VALUE>,
|
deba@2067
|
51 |
bool UNDIR = UndirectedTagIndicator<GRAPH>::value >
|
deba@2067
|
52 |
#endif
|
deba@2067
|
53 |
struct TabuSearchDefaultTraits {
|
deba@2067
|
54 |
typedef VALUE Value;
|
deba@2067
|
55 |
typedef BETTER Better;
|
deba@2067
|
56 |
|
deba@2067
|
57 |
typedef GRAPH Graph;
|
deba@2067
|
58 |
typedef typename GRAPH::Node Node;
|
deba@2067
|
59 |
typedef HEIGHTMAP HeightMap;
|
deba@2067
|
60 |
|
deba@2067
|
61 |
typedef typename GRAPH::IncEdgeIt EdgeIt;
|
deba@2067
|
62 |
};
|
deba@2067
|
63 |
|
deba@2067
|
64 |
template< typename GRAPH, typename VALUE,
|
deba@2067
|
65 |
typename HEIGHTMAP, typename BETTER >
|
deba@2067
|
66 |
struct TabuSearchDefaultTraits< GRAPH, VALUE, HEIGHTMAP, BETTER, false > {
|
deba@2067
|
67 |
typedef VALUE Value;
|
deba@2067
|
68 |
typedef BETTER Better;
|
deba@2067
|
69 |
|
deba@2067
|
70 |
typedef GRAPH Graph;
|
deba@2067
|
71 |
typedef typename GRAPH::Node Node;
|
deba@2067
|
72 |
typedef HEIGHTMAP HeightMap;
|
deba@2067
|
73 |
|
deba@2067
|
74 |
typedef typename GRAPH::OutEdgeIt EdgeIt;
|
deba@2067
|
75 |
};
|
deba@2067
|
76 |
|
deba@2067
|
77 |
|
deba@2067
|
78 |
|
deba@2067
|
79 |
/// \brief Policy hierarchy to controll the search algorithm.
|
deba@2067
|
80 |
///
|
deba@2067
|
81 |
/// The fallowing template hierarchy offers a clean interface to define own
|
deba@2067
|
82 |
/// policies, and combine existing ones.
|
deba@2067
|
83 |
template< typename TS >
|
deba@2067
|
84 |
struct TabuSearchPolicyConcept {
|
deba@2067
|
85 |
void target( TS *ts ) {}
|
deba@2067
|
86 |
|
deba@2067
|
87 |
void reset() {}
|
deba@2067
|
88 |
bool onStep() { return false; }
|
deba@2067
|
89 |
bool onStick() { return false; }
|
deba@2067
|
90 |
bool onImprove( const typename TS::Value &best ) { return false; }
|
deba@2067
|
91 |
};
|
deba@2067
|
92 |
|
deba@2067
|
93 |
template< typename TS >
|
deba@2067
|
94 |
struct YesPolicy {
|
deba@2067
|
95 |
void target( TS *ts ) {}
|
deba@2067
|
96 |
|
deba@2067
|
97 |
void reset() {}
|
deba@2067
|
98 |
bool onStep() { return true; }
|
deba@2067
|
99 |
bool onStick() { return true; }
|
deba@2067
|
100 |
bool onImprove( const typename TS::Value &best ) { return true; }
|
deba@2067
|
101 |
};
|
deba@2067
|
102 |
|
deba@2067
|
103 |
template< typename TS >
|
deba@2067
|
104 |
struct NoPolicy : public TabuSearchPolicyConcept<TS> {};
|
deba@2067
|
105 |
|
deba@2067
|
106 |
/// \brief Some basic methode, how tow Policies can be combined
|
deba@2067
|
107 |
struct PolicyAndCombination {
|
deba@2067
|
108 |
static bool evaluate( const bool r1, const bool r2 ) {
|
deba@2067
|
109 |
return r1 && r2;
|
deba@2067
|
110 |
}
|
deba@2067
|
111 |
};
|
deba@2067
|
112 |
|
deba@2067
|
113 |
struct PolicyOrCombination {
|
deba@2067
|
114 |
static bool evaluate( const bool r1, const bool r2 ) {
|
deba@2067
|
115 |
return r1 || r2;
|
deba@2067
|
116 |
}
|
deba@2067
|
117 |
};
|
deba@2067
|
118 |
|
deba@2067
|
119 |
/// \brief CombinePolicies
|
deba@2067
|
120 |
///
|
deba@2067
|
121 |
/// It combines tow policies using the given combination methode (mainly
|
deba@2067
|
122 |
/// some of the basic logical methodes) to create a new one.
|
deba@2067
|
123 |
#ifdef DOXYGEN
|
deba@2067
|
124 |
template< template<typename> class CP1, template<typename> class CP2,
|
deba@2067
|
125 |
typename COMBINATION >
|
deba@2067
|
126 |
#else
|
deba@2067
|
127 |
template< template<typename> class CP1, template<typename> class CP2,
|
deba@2067
|
128 |
typename COMBINATION = PolicyAndCombination >
|
deba@2067
|
129 |
#endif
|
deba@2067
|
130 |
struct CombinePolicies {
|
deba@2067
|
131 |
template< typename TS >
|
deba@2067
|
132 |
struct Policy {
|
deba@2067
|
133 |
typedef CP1<TS> Policy1;
|
deba@2067
|
134 |
typedef CP2<TS> Policy2;
|
deba@2067
|
135 |
|
deba@2067
|
136 |
Policy1 policy1;
|
deba@2067
|
137 |
Policy2 policy2;
|
deba@2067
|
138 |
|
deba@2067
|
139 |
inline Policy() : policy1(), policy2() {}
|
deba@2067
|
140 |
inline Policy( const Policy1 &cp1, const Policy2 &cp2 )
|
deba@2067
|
141 |
: policy1(cp1), policy2(cp2) {}
|
deba@2067
|
142 |
|
deba@2067
|
143 |
void target( TS *ts ) {
|
deba@2067
|
144 |
policy1.target(ts), policy2.target(ts);
|
deba@2067
|
145 |
};
|
deba@2067
|
146 |
|
deba@2067
|
147 |
void reset() {
|
deba@2067
|
148 |
policy1.reset(), policy2.reset();
|
deba@2067
|
149 |
}
|
deba@2067
|
150 |
|
deba@2067
|
151 |
bool onStep() {
|
deba@2067
|
152 |
return cmb.evaluate( policy1.onStep(), policy2.onStep() );
|
deba@2067
|
153 |
}
|
deba@2067
|
154 |
|
deba@2067
|
155 |
bool onStick() {
|
deba@2067
|
156 |
return cmb.evaluate( policy1.onStick(), policy2.onStick() );
|
deba@2067
|
157 |
}
|
deba@2067
|
158 |
|
deba@2067
|
159 |
bool onImprove( const typename TS::Value &best ) {
|
deba@2067
|
160 |
return cmb.evaluate( policy1.onImprove(best),
|
deba@2067
|
161 |
policy2.onImprove(best) );
|
deba@2067
|
162 |
}
|
deba@2067
|
163 |
|
deba@2067
|
164 |
private:
|
deba@2067
|
165 |
COMBINATION cmb;
|
deba@2067
|
166 |
};
|
deba@2067
|
167 |
};
|
deba@2067
|
168 |
|
deba@2067
|
169 |
|
deba@2067
|
170 |
/// \brief IterationPolicy limits the number of iterations and the
|
deba@2067
|
171 |
/// number of iterations without improvement
|
deba@2067
|
172 |
template< typename TS >
|
deba@2067
|
173 |
struct IterationPolicy {
|
deba@2067
|
174 |
IterationPolicy() : _it_lim(100000), _noimpr_it_lim(5000) {}
|
deba@2067
|
175 |
IterationPolicy( const long int itl, const long int noimpritl )
|
deba@2067
|
176 |
: _it_lim(itl), _noimpr_it_lim(noimpritl)
|
deba@2067
|
177 |
{}
|
deba@2067
|
178 |
|
deba@2067
|
179 |
void target( TS *ts ) {}
|
deba@2067
|
180 |
|
deba@2067
|
181 |
void reset() {
|
deba@2067
|
182 |
_it = _noimpr_it = 0;
|
deba@2067
|
183 |
}
|
deba@2067
|
184 |
|
deba@2067
|
185 |
bool onStep() {
|
deba@2067
|
186 |
++_it; ++_noimpr_it;
|
deba@2067
|
187 |
return (_it <= _it_lim) && (_noimpr_it <= _noimpr_it_lim);
|
deba@2067
|
188 |
}
|
deba@2067
|
189 |
|
deba@2067
|
190 |
bool onStick() {
|
deba@2067
|
191 |
return false;
|
deba@2067
|
192 |
}
|
deba@2067
|
193 |
|
deba@2067
|
194 |
bool onImprove( const typename TS::Value &best ) {
|
deba@2067
|
195 |
_noimpr_it = 0;
|
deba@2067
|
196 |
return true;
|
deba@2067
|
197 |
}
|
deba@2067
|
198 |
|
deba@2067
|
199 |
long int iterationLimit() const {
|
deba@2067
|
200 |
return _it_lim;
|
deba@2067
|
201 |
}
|
deba@2067
|
202 |
|
deba@2067
|
203 |
void iterationLimit( const long int itl ) {
|
deba@2067
|
204 |
_it_lim = itl;
|
deba@2067
|
205 |
}
|
deba@2067
|
206 |
|
deba@2067
|
207 |
long int noImprovementIterationLimit() const {
|
deba@2067
|
208 |
return _noimpr_it_lim;
|
deba@2067
|
209 |
}
|
deba@2067
|
210 |
|
deba@2067
|
211 |
void noImprovementIterationLimit( const long int noimpritl ) {
|
deba@2067
|
212 |
_noimpr_it_lim = noimpritl;
|
deba@2067
|
213 |
}
|
deba@2067
|
214 |
|
deba@2067
|
215 |
private:
|
deba@2067
|
216 |
long int _it_lim, _noimpr_it_lim;
|
deba@2067
|
217 |
long int _it, _noimpr_it;
|
deba@2067
|
218 |
};
|
deba@2067
|
219 |
|
deba@2067
|
220 |
/// \brief HeightPolicy stops the search when a given height is reached or
|
deba@2067
|
221 |
/// exceeds
|
deba@2067
|
222 |
template< typename TS >
|
deba@2067
|
223 |
struct HeightPolicy {
|
deba@2067
|
224 |
typedef typename TS::Value Value;
|
deba@2067
|
225 |
|
deba@2067
|
226 |
HeightPolicy() : _height_lim(), _found(false) {}
|
deba@2067
|
227 |
HeightPolicy( const Value &hl ) : _height_lim(hl), _found(false) {}
|
deba@2067
|
228 |
|
deba@2067
|
229 |
void target( TS *ts ) {}
|
deba@2067
|
230 |
|
deba@2067
|
231 |
void reset() {
|
deba@2067
|
232 |
_found = false;
|
deba@2067
|
233 |
}
|
deba@2067
|
234 |
|
deba@2067
|
235 |
bool onStep() {
|
deba@2067
|
236 |
return !_found;
|
deba@2067
|
237 |
}
|
deba@2067
|
238 |
|
deba@2067
|
239 |
bool onStick() {
|
deba@2067
|
240 |
return false;
|
deba@2067
|
241 |
}
|
deba@2067
|
242 |
|
deba@2067
|
243 |
bool onImprove( const Value &best ) {
|
deba@2067
|
244 |
typename TS::Better better;
|
deba@2067
|
245 |
_found = better(best, _height_lim) || (best == _height_lim);
|
deba@2067
|
246 |
return !_found;
|
deba@2067
|
247 |
}
|
deba@2067
|
248 |
|
deba@2067
|
249 |
Value heightLimi() const {
|
deba@2067
|
250 |
return _height_lim;
|
deba@2067
|
251 |
}
|
deba@2067
|
252 |
|
deba@2067
|
253 |
void heightLimi( const Value &hl ) {
|
deba@2067
|
254 |
_height_lim = hl;
|
deba@2067
|
255 |
}
|
deba@2067
|
256 |
|
deba@2067
|
257 |
private:
|
deba@2067
|
258 |
Value _height_lim;
|
deba@2067
|
259 |
bool _found;
|
deba@2067
|
260 |
};
|
deba@2067
|
261 |
|
deba@2067
|
262 |
/// \brief TimePolicy limits the time for searching.
|
deba@2067
|
263 |
template< typename TS >
|
deba@2067
|
264 |
struct TimePolicy {
|
deba@2067
|
265 |
TimePolicy() : _time_lim(60.0), _timeisup(false) {}
|
deba@2067
|
266 |
TimePolicy( const double tl ) : _time_lim(tl), _timeisup(false) {}
|
deba@2067
|
267 |
|
deba@2067
|
268 |
void target( TS *ts ) {}
|
deba@2067
|
269 |
|
deba@2067
|
270 |
void reset() {
|
deba@2067
|
271 |
_timeisup = false;
|
deba@2067
|
272 |
_t.reset();
|
deba@2067
|
273 |
}
|
deba@2067
|
274 |
|
deba@2067
|
275 |
bool onStep() {
|
deba@2067
|
276 |
update();
|
deba@2067
|
277 |
return !_timeisup;
|
deba@2067
|
278 |
}
|
deba@2067
|
279 |
|
deba@2067
|
280 |
bool onStick() {
|
deba@2067
|
281 |
return false;
|
deba@2067
|
282 |
}
|
deba@2067
|
283 |
|
deba@2067
|
284 |
bool onImprove( const typename TS::Value &best ) {
|
deba@2067
|
285 |
update();
|
deba@2067
|
286 |
return !_timeisup;
|
deba@2067
|
287 |
}
|
deba@2067
|
288 |
|
deba@2067
|
289 |
double timeLimit() const {
|
deba@2067
|
290 |
return _time_lim;
|
deba@2067
|
291 |
}
|
deba@2067
|
292 |
|
deba@2067
|
293 |
void setTimeLimit( const double tl ) {
|
deba@2067
|
294 |
_time_lim = tl;
|
deba@2067
|
295 |
update();
|
deba@2067
|
296 |
}
|
deba@2067
|
297 |
|
deba@2067
|
298 |
private:
|
deba@2067
|
299 |
lemon::Timer _t;
|
deba@2067
|
300 |
double _time_lim;
|
deba@2067
|
301 |
bool _timeisup;
|
deba@2067
|
302 |
|
deba@2067
|
303 |
inline void update() {
|
deba@2067
|
304 |
_timeisup = _t.realTime() > _time_lim;
|
deba@2067
|
305 |
}
|
deba@2067
|
306 |
};
|
deba@2067
|
307 |
|
deba@2067
|
308 |
|
deba@2067
|
309 |
|
deba@2067
|
310 |
/// \brief TabuSearch main class
|
deba@2067
|
311 |
///
|
deba@2067
|
312 |
/// This class offers the implementation of tabu-search algorithm. The
|
deba@2067
|
313 |
/// tabu-serach is a local-search. It starts from a specified point of the
|
deba@2067
|
314 |
/// problem's graph representation, and in every step it goes to the localy
|
deba@2067
|
315 |
/// best next Node except those in tabu set. The maximum size of this tabu
|
deba@2067
|
316 |
/// set defines how many Node will be remembered. The best Node ever found
|
deba@2067
|
317 |
/// will also stored, so we wont lose it, even is the search continues.
|
deba@2067
|
318 |
/// The class can be used on any kind of Graph and with any kind of Value
|
deba@2067
|
319 |
/// with a total-settlement on it.
|
deba@2067
|
320 |
///
|
deba@2067
|
321 |
/// \param _Graph The graph type the algorithm runs on.
|
deba@2067
|
322 |
/// \param _Value The values' type associated to the nodes.
|
deba@2067
|
323 |
/// \param _Policy Controlls the search. Determinates when to stop, or how
|
deba@2067
|
324 |
/// manage stuck search. Default value is \ref IterationPolicy .
|
deba@2067
|
325 |
/// \param _Traits Collection of needed types. Default value is
|
deba@2067
|
326 |
/// \ref TabuSearchDefaultTraits .
|
deba@2067
|
327 |
///
|
deba@2067
|
328 |
/// \author Szabadkai Mark
|
deba@2067
|
329 |
#ifdef DOXYGEN
|
deba@2067
|
330 |
template< typename GRAPH, typename VALUE, template<typename> class POLICY, typename TRAITS >
|
deba@2067
|
331 |
#else
|
deba@2067
|
332 |
template< typename GRAPH, typename VALUE,
|
deba@2067
|
333 |
template<typename> class POLICY = IterationPolicy,
|
deba@2067
|
334 |
typename TRAITS = TabuSearchDefaultTraits<GRAPH, VALUE> >
|
deba@2067
|
335 |
#endif
|
deba@2067
|
336 |
class TabuSearch
|
deba@2067
|
337 |
{
|
deba@2067
|
338 |
public:
|
deba@2067
|
339 |
|
deba@2067
|
340 |
/// \brief Thrown by setting the size of the tabu-set and the given size
|
deba@2067
|
341 |
/// is less than 2.
|
deba@2067
|
342 |
class BadParameterError : public lemon::LogicError {
|
deba@2067
|
343 |
public:
|
alpar@2151
|
344 |
virtual const char* what() const throw() {
|
deba@2067
|
345 |
return "lemon::TabuSearch::BadParameterError";
|
deba@2067
|
346 |
}
|
deba@2067
|
347 |
};
|
deba@2067
|
348 |
|
deba@2067
|
349 |
///Public types
|
deba@2067
|
350 |
typedef TabuSearch<GRAPH,VALUE,POLICY,TRAITS> SelfType;
|
deba@2067
|
351 |
|
deba@2067
|
352 |
typedef typename TRAITS::Graph Graph;
|
deba@2067
|
353 |
typedef typename TRAITS::Node Node;
|
deba@2067
|
354 |
typedef typename TRAITS::Value Value;
|
deba@2067
|
355 |
typedef typename TRAITS::HeightMap HeightMap;
|
deba@2067
|
356 |
typedef typename TRAITS::Better Better;
|
deba@2067
|
357 |
typedef typename std::deque< Node >::const_iterator TabuIterator;
|
deba@2067
|
358 |
|
deba@2067
|
359 |
typedef POLICY<SelfType> Policy;
|
deba@2067
|
360 |
|
deba@2067
|
361 |
protected:
|
deba@2067
|
362 |
typedef typename TRAITS::EdgeIt EdgeIt;
|
deba@2067
|
363 |
|
deba@2067
|
364 |
const Graph &gr;
|
deba@2067
|
365 |
const HeightMap &height;
|
deba@2067
|
366 |
/// The tabu set. Teh current node is the first
|
deba@2067
|
367 |
std::deque< Node > tabu;
|
deba@2067
|
368 |
/// Maximal tabu size
|
deba@2067
|
369 |
unsigned int mts;
|
deba@2067
|
370 |
/// The best Node found
|
deba@2067
|
371 |
Node b;
|
deba@2067
|
372 |
|
deba@2067
|
373 |
Better better;
|
deba@2067
|
374 |
Policy pol;
|
deba@2067
|
375 |
|
deba@2067
|
376 |
public:
|
deba@2067
|
377 |
/// \brief Constructor
|
deba@2067
|
378 |
///
|
deba@2067
|
379 |
/// \param graph the graph the algorithm will run on.
|
deba@2067
|
380 |
/// \param hm the height map used by the algorithm.
|
deba@2067
|
381 |
/// \param tabusz the maximal size of the tabu set. Default value is 3
|
deba@2067
|
382 |
/// \param p the Policy controlling the search.
|
deba@2067
|
383 |
TabuSearch( const Graph &graph, const HeightMap &hm,
|
deba@2067
|
384 |
const int tabusz = 3, Policy p = Policy() )
|
deba@2067
|
385 |
: gr(graph), height(hm), mts(tabusz), pol(p)
|
deba@2067
|
386 |
{
|
deba@2067
|
387 |
pol.target(this);
|
deba@2067
|
388 |
}
|
deba@2067
|
389 |
|
deba@2067
|
390 |
/// \brief Destructor
|
deba@2067
|
391 |
~TabuSearch() {
|
deba@2067
|
392 |
pol.target(NULL);
|
deba@2067
|
393 |
}
|
deba@2067
|
394 |
|
deba@2067
|
395 |
/// Set/Get the size of the tabu set
|
deba@2067
|
396 |
void tabuSize( const unsigned int size )
|
deba@2067
|
397 |
{
|
deba@2067
|
398 |
if( size < 2 )
|
deba@2067
|
399 |
throw BadParameterError( "Tabu size must be at least 2!" );
|
deba@2067
|
400 |
mts = size;
|
deba@2067
|
401 |
while( mts < tabu.size() )
|
deba@2067
|
402 |
tabu.pop_back();
|
deba@2067
|
403 |
}
|
deba@2067
|
404 |
|
deba@2067
|
405 |
unsigned int tabuSize() const {
|
deba@2067
|
406 |
return mts;
|
deba@2067
|
407 |
}
|
deba@2067
|
408 |
|
deba@2067
|
409 |
/// Set/Get Policy
|
deba@2067
|
410 |
void policy( Policy p ) {
|
deba@2067
|
411 |
pol.target(NULL);
|
deba@2067
|
412 |
pol = p;
|
deba@2067
|
413 |
pol.target(this);
|
deba@2067
|
414 |
}
|
deba@2067
|
415 |
|
deba@2067
|
416 |
Policy& policy() {
|
deba@2067
|
417 |
return pol;
|
deba@2067
|
418 |
}
|
deba@2067
|
419 |
|
deba@2067
|
420 |
/// \name Execution control
|
deba@2067
|
421 |
/// The simplest way to execute the algorithm is to use the member
|
deba@2067
|
422 |
/// functions called \c run( 'startnode' ).
|
deba@2067
|
423 |
///@{
|
deba@2067
|
424 |
|
deba@2067
|
425 |
/// \brief Initializes the internal data.
|
deba@2067
|
426 |
///
|
deba@2067
|
427 |
/// \param startn The start node where the search begins.
|
deba@2067
|
428 |
void init( const Node startn ) {
|
deba@2067
|
429 |
tabu.clear();
|
deba@2067
|
430 |
tabu.push_front( startn );
|
deba@2067
|
431 |
b = startn;
|
deba@2067
|
432 |
pol.reset();
|
deba@2067
|
433 |
}
|
deba@2067
|
434 |
|
deba@2067
|
435 |
/// \brief Does one iteration
|
deba@2067
|
436 |
///
|
deba@2067
|
437 |
/// If the Policy allows it searches for the best next node, then steps
|
deba@2067
|
438 |
/// onto it.
|
deba@2067
|
439 |
/// \return %False if one Policy condition wants to stop the search.
|
deba@2067
|
440 |
bool step()
|
deba@2067
|
441 |
{
|
deba@2067
|
442 |
///Request premmision from ControllPolicy
|
deba@2067
|
443 |
if( !pol.onStep() )
|
deba@2067
|
444 |
return false;
|
deba@2067
|
445 |
|
deba@2067
|
446 |
///Find the best next potential node
|
deba@2067
|
447 |
Node n; bool found = false;
|
deba@2067
|
448 |
for( EdgeIt e(gr,tabu[0]); e != INVALID; ++e )
|
deba@2067
|
449 |
{
|
deba@2067
|
450 |
Node m = (gr.source(e) == tabu[0]) ? gr.target(e) : gr.source(e);
|
deba@2067
|
451 |
bool wrong = false;
|
deba@2067
|
452 |
for( int i = 1; i != (signed int)tabu.size(); ++i )
|
deba@2067
|
453 |
if( m == tabu[i] ) {
|
deba@2067
|
454 |
wrong = true;
|
deba@2067
|
455 |
break;
|
deba@2067
|
456 |
}
|
deba@2067
|
457 |
if( wrong )
|
deba@2067
|
458 |
continue;
|
deba@2067
|
459 |
|
deba@2067
|
460 |
if( !found ) {
|
deba@2067
|
461 |
n = m;
|
deba@2067
|
462 |
found = true;
|
deba@2067
|
463 |
} else
|
deba@2067
|
464 |
if( better(height[m], height[n]) ) {
|
deba@2067
|
465 |
n = m;
|
deba@2067
|
466 |
}
|
deba@2067
|
467 |
}
|
deba@2067
|
468 |
|
deba@2067
|
469 |
///Handle stuck search
|
deba@2067
|
470 |
if( !found ) {
|
deba@2067
|
471 |
return pol.onStick();
|
deba@2067
|
472 |
}
|
deba@2067
|
473 |
|
deba@2067
|
474 |
///Move on...
|
deba@2067
|
475 |
tabu.push_front(n);
|
deba@2067
|
476 |
while( mts < tabu.size() ) {
|
deba@2067
|
477 |
tabu.pop_back();
|
deba@2067
|
478 |
}
|
deba@2067
|
479 |
if( better(height[n], height[b]) ) {
|
deba@2067
|
480 |
b = n;
|
deba@2067
|
481 |
if( !pol.onImprove(height[b]) )
|
deba@2067
|
482 |
return false;
|
deba@2067
|
483 |
}
|
deba@2067
|
484 |
|
deba@2067
|
485 |
return true;
|
deba@2067
|
486 |
}
|
deba@2067
|
487 |
|
deba@2067
|
488 |
/// \brief Runs a search while the Policy stops it.
|
deba@2067
|
489 |
///
|
deba@2067
|
490 |
/// \param startn The start node where the search begins.
|
deba@2067
|
491 |
inline void run( const Node startn ) {
|
deba@2067
|
492 |
std::cin.unsetf( std::ios_base::skipws );
|
deba@2067
|
493 |
char c;
|
deba@2067
|
494 |
init( startn );
|
deba@2067
|
495 |
while( step() )
|
deba@2067
|
496 |
std::cin >> c;
|
deba@2067
|
497 |
std::cin.setf( std::ios_base::skipws );
|
deba@2067
|
498 |
}
|
deba@2067
|
499 |
|
deba@2067
|
500 |
///@}
|
deba@2067
|
501 |
|
deba@2067
|
502 |
/// \name Query Functions
|
deba@2067
|
503 |
/// The result of the TabuSearch algorithm can be obtained using these
|
deba@2067
|
504 |
/// functions.\n
|
deba@2067
|
505 |
///@{
|
deba@2067
|
506 |
|
deba@2067
|
507 |
/// \brief The node, the search is standing on.
|
deba@2067
|
508 |
inline Node current() const {
|
deba@2067
|
509 |
return tabu[0];
|
deba@2067
|
510 |
}
|
deba@2067
|
511 |
|
deba@2067
|
512 |
/// \brief The best node found until now.
|
deba@2067
|
513 |
inline Node best() const {
|
deba@2067
|
514 |
return b;
|
deba@2067
|
515 |
}
|
deba@2067
|
516 |
|
deba@2067
|
517 |
/// \brief Beginning to iterate on the current tabu set.
|
deba@2067
|
518 |
inline TabuIterator tabu_begin() const {
|
deba@2067
|
519 |
return tabu.begin();
|
deba@2067
|
520 |
}
|
deba@2067
|
521 |
|
deba@2067
|
522 |
/// \brief Ending to iterate on the current tabu set.
|
deba@2067
|
523 |
inline TabuIterator tabu_end() const {
|
deba@2067
|
524 |
return tabu.end();
|
deba@2067
|
525 |
}
|
deba@2067
|
526 |
|
deba@2067
|
527 |
///@}
|
deba@2067
|
528 |
};
|
deba@2067
|
529 |
}
|
deba@2067
|
530 |
#endif
|