3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
20 #ifndef LEMON_TABU_SEARCH_H
21 #define LEMON_TABU_SEARCH_H
23 /// \ingroup experimental
25 /// \brief TabuSearch algorithm.
27 /// \author Szabadkai Mark
29 #include <lemon/bits/utility.h>
30 #include <lemon/error.h>
31 #include <lemon/time_measure.h>
38 /// \brief Default Traits for TabuSearch class.
40 /// This template defines the needed types for the \ref TabuSearch class.
41 /// Is main purpos is to simplify the main class's template interface,
42 /// but it provides the EdgeIt type, passing to the concrete graph wheter
43 /// it is directed or undirected.
45 template< typename GRAPH, typename VALUE,
46 typename HEIGHTMAP, typename BETTER, bool UNDIR >
48 template< typename GRAPH, typename VALUE,
49 typename HEIGHTMAP = typename GRAPH::template NodeMap<VALUE>,
50 typename BETTER = std::less<VALUE>,
51 bool UNDIR = UndirectedTagIndicator<GRAPH>::value >
53 struct TabuSearchDefaultTraits {
55 typedef BETTER Better;
58 typedef typename GRAPH::Node Node;
59 typedef HEIGHTMAP HeightMap;
61 typedef typename GRAPH::IncEdgeIt EdgeIt;
64 template< typename GRAPH, typename VALUE,
65 typename HEIGHTMAP, typename BETTER >
66 struct TabuSearchDefaultTraits< GRAPH, VALUE, HEIGHTMAP, BETTER, false > {
68 typedef BETTER Better;
71 typedef typename GRAPH::Node Node;
72 typedef HEIGHTMAP HeightMap;
74 typedef typename GRAPH::OutEdgeIt EdgeIt;
79 /// \brief Policy hierarchy to controll the search algorithm.
81 /// The fallowing template hierarchy offers a clean interface to define own
82 /// policies, and combine existing ones.
83 template< typename TS >
84 struct TabuSearchPolicyConcept {
85 void target( TS *ts ) {}
88 bool onStep() { return false; }
89 bool onStick() { return false; }
90 bool onImprove( const typename TS::Value &best ) { return false; }
93 template< typename TS >
95 void target( TS *ts ) {}
98 bool onStep() { return true; }
99 bool onStick() { return true; }
100 bool onImprove( const typename TS::Value &best ) { return true; }
103 template< typename TS >
104 struct NoPolicy : public TabuSearchPolicyConcept<TS> {};
106 /// \brief Some basic methode, how tow Policies can be combined
107 struct PolicyAndCombination {
108 static bool evaluate( const bool r1, const bool r2 ) {
113 struct PolicyOrCombination {
114 static bool evaluate( const bool r1, const bool r2 ) {
119 /// \brief CombinePolicies
121 /// It combines tow policies using the given combination methode (mainly
122 /// some of the basic logical methodes) to create a new one.
124 template< template<typename> class CP1, template<typename> class CP2,
125 typename COMBINATION >
127 template< template<typename> class CP1, template<typename> class CP2,
128 typename COMBINATION = PolicyAndCombination >
130 struct CombinePolicies {
131 template< typename TS >
133 typedef CP1<TS> Policy1;
134 typedef CP2<TS> Policy2;
139 inline Policy() : policy1(), policy2() {}
140 inline Policy( const Policy1 &cp1, const Policy2 &cp2 )
141 : policy1(cp1), policy2(cp2) {}
143 void target( TS *ts ) {
144 policy1.target(ts), policy2.target(ts);
148 policy1.reset(), policy2.reset();
152 return cmb.evaluate( policy1.onStep(), policy2.onStep() );
156 return cmb.evaluate( policy1.onStick(), policy2.onStick() );
159 bool onImprove( const typename TS::Value &best ) {
160 return cmb.evaluate( policy1.onImprove(best),
161 policy2.onImprove(best) );
170 /// \brief IterationPolicy limits the number of iterations and the
171 /// number of iterations without improvement
172 template< typename TS >
173 struct IterationPolicy {
174 IterationPolicy() : _it_lim(100000), _noimpr_it_lim(5000) {}
175 IterationPolicy( const long int itl, const long int noimpritl )
176 : _it_lim(itl), _noimpr_it_lim(noimpritl)
179 void target( TS *ts ) {}
182 _it = _noimpr_it = 0;
187 return (_it <= _it_lim) && (_noimpr_it <= _noimpr_it_lim);
194 bool onImprove( const typename TS::Value &best ) {
199 long int iterationLimit() const {
203 void iterationLimit( const long int itl ) {
207 long int noImprovementIterationLimit() const {
208 return _noimpr_it_lim;
211 void noImprovementIterationLimit( const long int noimpritl ) {
212 _noimpr_it_lim = noimpritl;
216 long int _it_lim, _noimpr_it_lim;
217 long int _it, _noimpr_it;
220 /// \brief HeightPolicy stops the search when a given height is reached or
222 template< typename TS >
223 struct HeightPolicy {
224 typedef typename TS::Value Value;
226 HeightPolicy() : _height_lim(), _found(false) {}
227 HeightPolicy( const Value &hl ) : _height_lim(hl), _found(false) {}
229 void target( TS *ts ) {}
243 bool onImprove( const Value &best ) {
244 typename TS::Better better;
245 _found = better(best, _height_lim) || (best == _height_lim);
249 Value heightLimi() const {
253 void heightLimi( const Value &hl ) {
262 /// \brief TimePolicy limits the time for searching.
263 template< typename TS >
265 TimePolicy() : _time_lim(60.0), _timeisup(false) {}
266 TimePolicy( const double tl ) : _time_lim(tl), _timeisup(false) {}
268 void target( TS *ts ) {}
284 bool onImprove( const typename TS::Value &best ) {
289 double timeLimit() const {
293 void setTimeLimit( const double tl ) {
303 inline void update() {
304 _timeisup = _t.realTime() > _time_lim;
310 /// \brief TabuSearch main class
312 /// This class offers the implementation of tabu-search algorithm. The
313 /// tabu-serach is a local-search. It starts from a specified point of the
314 /// problem's graph representation, and in every step it goes to the localy
315 /// best next Node except those in tabu set. The maximum size of this tabu
316 /// set defines how many Node will be remembered. The best Node ever found
317 /// will also stored, so we wont lose it, even is the search continues.
318 /// The class can be used on any kind of Graph and with any kind of Value
319 /// with a total-settlement on it.
321 /// \param _Graph The graph type the algorithm runs on.
322 /// \param _Value The values' type associated to the nodes.
323 /// \param _Policy Controlls the search. Determinates when to stop, or how
324 /// manage stuck search. Default value is \ref IterationPolicy .
325 /// \param _Traits Collection of needed types. Default value is
326 /// \ref TabuSearchDefaultTraits .
328 /// \author Szabadkai Mark
330 template< typename GRAPH, typename VALUE, template<typename> class POLICY, typename TRAITS >
332 template< typename GRAPH, typename VALUE,
333 template<typename> class POLICY = IterationPolicy,
334 typename TRAITS = TabuSearchDefaultTraits<GRAPH, VALUE> >
340 /// \brief Thrown by setting the size of the tabu-set and the given size
342 class BadParameterError : public lemon::LogicError {
344 virtual const char* what() const throw() {
345 return "lemon::TabuSearch::BadParameterError";
350 typedef TabuSearch<GRAPH,VALUE,POLICY,TRAITS> SelfType;
352 typedef typename TRAITS::Graph Graph;
353 typedef typename TRAITS::Node Node;
354 typedef typename TRAITS::Value Value;
355 typedef typename TRAITS::HeightMap HeightMap;
356 typedef typename TRAITS::Better Better;
357 typedef typename std::deque< Node >::const_iterator TabuIterator;
359 typedef POLICY<SelfType> Policy;
362 typedef typename TRAITS::EdgeIt EdgeIt;
365 const HeightMap &height;
366 /// The tabu set. Teh current node is the first
367 std::deque< Node > tabu;
368 /// Maximal tabu size
370 /// The best Node found
377 /// \brief Constructor
379 /// \param graph the graph the algorithm will run on.
380 /// \param hm the height map used by the algorithm.
381 /// \param tabusz the maximal size of the tabu set. Default value is 3
382 /// \param p the Policy controlling the search.
383 TabuSearch( const Graph &graph, const HeightMap &hm,
384 const int tabusz = 3, Policy p = Policy() )
385 : gr(graph), height(hm), mts(tabusz), pol(p)
390 /// \brief Destructor
395 /// Set/Get the size of the tabu set
396 void tabuSize( const unsigned int size )
399 throw BadParameterError( "Tabu size must be at least 2!" );
401 while( mts < tabu.size() )
405 unsigned int tabuSize() const {
410 void policy( Policy p ) {
420 /// \name Execution control
421 /// The simplest way to execute the algorithm is to use the member
422 /// functions called \c run( 'startnode' ).
425 /// \brief Initializes the internal data.
427 /// \param startn The start node where the search begins.
428 void init( const Node startn ) {
430 tabu.push_front( startn );
435 /// \brief Does one iteration
437 /// If the Policy allows it searches for the best next node, then steps
439 /// \return %False if one Policy condition wants to stop the search.
442 ///Request premmision from ControllPolicy
446 ///Find the best next potential node
447 Node n; bool found = false;
448 for( EdgeIt e(gr,tabu[0]); e != INVALID; ++e )
450 Node m = (gr.source(e) == tabu[0]) ? gr.target(e) : gr.source(e);
452 for( int i = 1; i != (signed int)tabu.size(); ++i )
464 if( better(height[m], height[n]) ) {
469 ///Handle stuck search
471 return pol.onStick();
476 while( mts < tabu.size() ) {
479 if( better(height[n], height[b]) ) {
481 if( !pol.onImprove(height[b]) )
488 /// \brief Runs a search while the Policy stops it.
490 /// \param startn The start node where the search begins.
491 inline void run( const Node startn ) {
492 std::cin.unsetf( std::ios_base::skipws );
497 std::cin.setf( std::ios_base::skipws );
502 /// \name Query Functions
503 /// The result of the TabuSearch algorithm can be obtained using these
507 /// \brief The node, the search is standing on.
508 inline Node current() const {
512 /// \brief The best node found until now.
513 inline Node best() const {
517 /// \brief Beginning to iterate on the current tabu set.
518 inline TabuIterator tabu_begin() const {
522 /// \brief Ending to iterate on the current tabu set.
523 inline TabuIterator tabu_end() const {