lemon/tabu_search.h
author alpar
Mon, 04 Sep 2006 19:12:44 +0000
changeset 2194 eaf16c8f6fef
parent 2067 cd414bfbe38b
child 2370 ed6539025f27
permissions -rw-r--r--
'make doc' is now working also in case of external build.
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