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