[Lemon-commits] [lemon_svn] deba: r2727 - hugo/trunk/lemon

Lemon SVN svn at lemon.cs.elte.hu
Mon Nov 6 20:54:47 CET 2006


Author: deba
Date: Thu Apr 27 16:53:23 2006
New Revision: 2727

Added:
   hugo/trunk/lemon/tabu_search.h
Modified:
   hugo/trunk/lemon/Makefile.am

Log:
Tabu Search by Szabadkai Mark



Modified: hugo/trunk/lemon/Makefile.am
==============================================================================
--- hugo/trunk/lemon/Makefile.am	(original)
+++ hugo/trunk/lemon/Makefile.am	Thu Apr 27 16:53:23 2006
@@ -78,6 +78,7 @@
 	simann.h \
 	smart_graph.h \
 	sub_graph.h \
+	tabu_search.h \
 	time_measure.h \
 	topology.h \
 	ugraph_adaptor.h \

Added: hugo/trunk/lemon/tabu_search.h
==============================================================================
--- (empty file)
+++ hugo/trunk/lemon/tabu_search.h	Thu Apr 27 16:53:23 2006
@@ -0,0 +1,530 @@
+/* -*- C++ -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library
+ *
+ * Copyright (C) 2003-2006
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+
+#ifndef LEMON_TABU_SEARCH_H
+#define LEMON_TABU_SEARCH_H
+
+/// \ingroup experimental
+/// \file
+/// \brief TabuSearch algorithm.
+///
+/// \author Szabadkai Mark
+
+#include <lemon/bits/utility.h>
+#include <lemon/error.h>
+#include <lemon/time_measure.h>
+#include <functional>
+#include <deque>
+
+
+namespace lemon {
+
+  /// \brief Default Traits for TabuSearch class.
+  /// 
+  /// This template defines the needed types for the \ref TabuSearch class.
+  /// Is main purpos is to simplify the main class's template interface,
+  /// but it provides the EdgeIt type, passing to the concrete graph wheter
+  /// it is directed or undirected.
+#ifdef DOXYGEN
+  template< typename GRAPH, typename VALUE, 
+            typename HEIGHTMAP, typename BETTER, bool UNDIR >
+#else
+  template< typename GRAPH, typename VALUE,
+            typename HEIGHTMAP = typename GRAPH::template NodeMap<VALUE>,
+            typename BETTER = std::less<VALUE>,
+            bool UNDIR = UndirectedTagIndicator<GRAPH>::value >
+#endif
+  struct TabuSearchDefaultTraits {
+    typedef  VALUE  Value; 
+    typedef  BETTER  Better;
+
+    typedef  GRAPH  Graph;
+    typedef  typename GRAPH::Node  Node;
+    typedef  HEIGHTMAP  HeightMap;
+
+    typedef  typename GRAPH::IncEdgeIt  EdgeIt;
+  };
+
+  template< typename GRAPH, typename VALUE, 
+            typename HEIGHTMAP, typename BETTER >
+  struct TabuSearchDefaultTraits< GRAPH, VALUE, HEIGHTMAP, BETTER, false > {
+    typedef  VALUE  Value;
+    typedef  BETTER  Better;
+
+    typedef  GRAPH  Graph;
+    typedef  typename GRAPH::Node  Node;
+    typedef  HEIGHTMAP  HeightMap;
+
+    typedef  typename GRAPH::OutEdgeIt  EdgeIt;
+  };
+
+
+
+  /// \brief Policy hierarchy to controll the search algorithm.
+  ///
+  /// The fallowing template hierarchy offers a clean interface to define own
+  /// policies, and combine existing ones.
+  template< typename TS >
+  struct TabuSearchPolicyConcept {
+    void  target( TS *ts ) {}
+
+    void  reset()  {}
+    bool  onStep() { return false; }
+    bool  onStick() { return false; }
+    bool  onImprove( const typename TS::Value &best ) { return false; }
+  };
+
+  template< typename TS >
+  struct YesPolicy {
+    void  target( TS *ts ) {}
+
+    void  reset()  {}
+    bool  onStep() { return true; }
+    bool  onStick() { return true; }
+    bool  onImprove( const typename TS::Value &best ) { return true; }
+  };
+
+  template< typename TS >
+  struct NoPolicy : public TabuSearchPolicyConcept<TS> {};
+
+  /// \brief Some basic methode, how tow Policies can be combined
+  struct PolicyAndCombination {
+    static bool  evaluate( const bool r1, const bool r2 ) {
+      return r1 && r2;
+    }
+  };
+
+  struct PolicyOrCombination {
+    static bool  evaluate( const bool r1, const bool r2 ) {
+      return r1 || r2;
+    }
+  };
+
+  /// \brief CombinePolicies
+  ///
+  /// It combines tow policies using the given combination methode (mainly
+  /// some of the basic logical methodes) to create a new one.
+#ifdef DOXYGEN
+  template< template<typename> class CP1, template<typename> class CP2, 
+            typename COMBINATION >
+#else
+  template< template<typename> class CP1, template<typename> class CP2,
+            typename COMBINATION = PolicyAndCombination >
+#endif
+  struct CombinePolicies {
+    template< typename TS >
+    struct Policy {
+      typedef CP1<TS>  Policy1;
+      typedef CP2<TS>  Policy2;
+      
+      Policy1  policy1;
+      Policy2  policy2;
+
+      inline Policy() : policy1(), policy2() {}
+      inline Policy( const Policy1 &cp1, const Policy2 &cp2 ) 
+        : policy1(cp1), policy2(cp2) {}
+
+      void  target( TS *ts ) {
+        policy1.target(ts), policy2.target(ts);
+      };
+
+      void  reset() {
+        policy1.reset(), policy2.reset();
+      }
+
+      bool  onStep() {
+        return cmb.evaluate( policy1.onStep(), policy2.onStep() );
+      }
+
+      bool  onStick() {
+        return cmb.evaluate( policy1.onStick(), policy2.onStick() );
+      }
+
+      bool  onImprove( const typename TS::Value &best ) {
+        return cmb.evaluate( policy1.onImprove(best), 
+                             policy2.onImprove(best) );
+      }
+
+    private:
+      COMBINATION cmb;
+    };
+  };
+
+
+  /// \brief IterationPolicy limits the number of iterations and the
+  /// number of iterations without improvement
+  template< typename TS >
+  struct IterationPolicy {
+    IterationPolicy() : _it_lim(100000), _noimpr_it_lim(5000) {}
+    IterationPolicy( const long int itl, const long int noimpritl )
+      : _it_lim(itl), _noimpr_it_lim(noimpritl)
+    {}
+
+    void  target( TS *ts ) {}
+
+    void  reset() {
+      _it = _noimpr_it = 0;
+    }
+
+    bool  onStep() {
+      ++_it; ++_noimpr_it;
+      return (_it <= _it_lim) && (_noimpr_it <= _noimpr_it_lim);
+    }
+		
+    bool  onStick() {
+      return false;
+    }
+
+    bool  onImprove( const typename TS::Value &best ) {
+      _noimpr_it = 0;
+      return true;
+    }
+
+    long int  iterationLimit() const {
+      return _it_lim;
+    }
+
+    void  iterationLimit( const long int itl ) {
+      _it_lim = itl;
+    }
+
+    long int  noImprovementIterationLimit() const {
+      return _noimpr_it_lim;
+    }
+
+    void  noImprovementIterationLimit( const long int noimpritl ) {
+      _noimpr_it_lim = noimpritl;
+    }
+
+  private:
+    long int  _it_lim, _noimpr_it_lim;
+    long int  _it, _noimpr_it;
+  };
+
+  /// \brief HeightPolicy stops the search when a given height is reached or
+  /// exceeds
+  template< typename TS >
+  struct HeightPolicy {
+    typedef typename TS::Value  Value;
+
+    HeightPolicy() : _height_lim(), _found(false) {}
+    HeightPolicy( const Value &hl ) : _height_lim(hl), _found(false) {}
+
+    void  target( TS *ts ) {}
+
+    void  reset() {
+      _found = false;
+    }
+
+    bool  onStep() {
+      return !_found;
+    }
+
+    bool  onStick() {
+      return false;
+    }
+
+    bool  onImprove( const Value &best ) {
+      typename TS::Better  better;
+      _found = better(best, _height_lim) || (best == _height_lim);
+      return !_found;
+    }
+
+    Value  heightLimi() const {
+      return _height_lim;
+    }
+
+    void  heightLimi( const Value &hl ) {
+      _height_lim = hl;
+    }
+
+  private:
+    Value  _height_lim;
+    bool  _found;
+  };
+
+  /// \brief TimePolicy limits the time for searching.
+  template< typename TS >
+  struct TimePolicy {
+    TimePolicy() : _time_lim(60.0), _timeisup(false) {}
+    TimePolicy( const double tl ) : _time_lim(tl), _timeisup(false) {}
+
+    void  target( TS *ts ) {}
+
+    void  reset() {
+      _timeisup = false;
+      _t.reset();
+    }
+
+    bool  onStep() {
+      update();
+      return !_timeisup;
+    }
+
+    bool  onStick() {
+      return false;
+    }
+
+    bool  onImprove( const typename TS::Value &best ) {
+      update();
+      return !_timeisup;
+    }
+
+    double timeLimit() const {
+      return _time_lim;
+    }
+
+    void  setTimeLimit( const double tl ) {
+      _time_lim = tl;
+      update();
+    }
+
+  private:
+    lemon::Timer  _t;
+    double  _time_lim;
+    bool  _timeisup;
+
+    inline void  update() {
+      _timeisup = _t.realTime() > _time_lim;
+    }
+  };
+
+
+
+  /// \brief TabuSearch main class
+  ///
+  /// This class offers the implementation of tabu-search algorithm. The
+  /// tabu-serach is a local-search. It starts from a specified point of the
+  /// problem's graph representation, and in every step it goes to the localy
+  /// best next Node except those in tabu set. The maximum size of this tabu
+  /// set defines how many Node will be remembered. The best Node ever found
+  /// will also stored, so we wont lose it, even is the search continues.
+  /// The class can be used on any kind of Graph and with any kind of Value
+  /// with a total-settlement on it.
+  ///
+  /// \param _Graph The graph type the algorithm runs on.
+  /// \param _Value The values' type associated to the nodes.
+  /// \param _Policy Controlls the search. Determinates when to stop, or how
+  /// manage stuck search. Default value is \ref IterationPolicy .
+  /// \param _Traits Collection of needed types. Default value is
+  /// \ref TabuSearchDefaultTraits .
+  ///
+  /// \author Szabadkai Mark
+#ifdef DOXYGEN
+  template< typename GRAPH, typename VALUE, template<typename> class POLICY, typename TRAITS >
+#else
+  template< typename GRAPH, typename VALUE,
+            template<typename> class POLICY = IterationPolicy,
+            typename TRAITS = TabuSearchDefaultTraits<GRAPH, VALUE> >
+#endif
+  class TabuSearch
+  {
+  public:
+
+    /// \brief Thrown by setting the size of the tabu-set and the given size
+    /// is less than 2.
+    class BadParameterError : public lemon::LogicError {
+    public:
+      virtual const char* exceptionName() const {
+        return "lemon::TabuSearch::BadParameterError";
+      }
+    };
+
+    ///Public types
+    typedef  TabuSearch<GRAPH,VALUE,POLICY,TRAITS>  SelfType;
+
+    typedef  typename TRAITS::Graph  Graph;
+    typedef  typename TRAITS::Node  Node;
+    typedef  typename TRAITS::Value  Value;
+    typedef  typename TRAITS::HeightMap  HeightMap;
+    typedef  typename TRAITS::Better  Better;
+    typedef  typename std::deque< Node >::const_iterator  TabuIterator;
+
+    typedef  POLICY<SelfType>  Policy;
+
+  protected:
+    typedef  typename TRAITS::EdgeIt  EdgeIt;
+
+    const Graph  &gr;
+    const HeightMap  &height;
+    /// The tabu set. Teh current node is the first
+    std::deque< Node >  tabu;
+    /// Maximal tabu size
+    unsigned int  mts;
+    /// The best Node found
+    Node  b;
+
+    Better  better;
+    Policy  pol;
+
+  public:
+    /// \brief Constructor
+    ///
+    /// \param graph the graph the algorithm will run on.
+    /// \param hm the height map used by the algorithm.
+    /// \param tabusz the maximal size of the tabu set. Default value is 3
+    /// \param p the Policy controlling the search.
+    TabuSearch( const Graph &graph, const HeightMap &hm, 
+                const int tabusz = 3, Policy p = Policy() )
+      : gr(graph), height(hm), mts(tabusz), pol(p)
+    {
+      pol.target(this);
+    }
+
+    /// \brief Destructor
+    ~TabuSearch() {
+      pol.target(NULL);
+    }
+
+    /// Set/Get the size of the tabu set
+    void  tabuSize( const unsigned int size )
+    {
+      if( size < 2 )
+      throw BadParameterError( "Tabu size must be at least 2!" );
+      mts = size;
+      while( mts < tabu.size() )
+      tabu.pop_back();
+    }
+
+    unsigned int  tabuSize() const {
+      return mts;
+    }
+
+    /// Set/Get Policy
+    void  policy( Policy p ) {
+      pol.target(NULL);
+      pol = p;
+      pol.target(this);
+    }
+		
+    Policy& policy()  {
+      return pol;
+    }
+
+    /// \name Execution control
+    /// The simplest way to execute the algorithm is to use the member
+    /// functions called \c run( 'startnode' ).
+    ///@{
+
+    /// \brief Initializes the internal data.
+    ///
+    /// \param startn The start node where the search begins.
+    void  init( const Node startn ) {
+      tabu.clear();
+      tabu.push_front( startn );
+      b = startn;
+      pol.reset();
+    }
+
+    /// \brief Does one iteration
+    ///
+    /// If the Policy allows it searches for the best next node, then steps
+    /// onto it.
+    /// \return %False if one Policy condition wants to stop the search.
+    bool  step()
+    {
+      ///Request premmision from ControllPolicy
+      if( !pol.onStep() )
+      return false;
+	
+      ///Find the best next potential node
+      Node n; bool found = false;
+      for( EdgeIt e(gr,tabu[0]); e != INVALID; ++e )
+      {
+        Node m = (gr.source(e) == tabu[0]) ? gr.target(e) : gr.source(e);
+        bool wrong = false;
+        for( int i = 1; i != (signed int)tabu.size(); ++i )
+          if( m == tabu[i] ) {
+            wrong = true;
+            break;
+          }
+        if( wrong )
+          continue;
+
+        if( !found ) {
+          n = m;
+          found = true;
+        } else
+          if( better(height[m], height[n]) ) {
+            n = m;
+          }
+      }
+
+      ///Handle stuck search
+      if( !found ) {
+        return pol.onStick();
+      }
+
+      ///Move on...
+      tabu.push_front(n);
+      while( mts < tabu.size() ) {
+        tabu.pop_back();
+      }
+      if( better(height[n], height[b]) ) {
+        b = n;
+        if( !pol.onImprove(height[b]) )
+        return false;
+      }
+
+      return true;
+    }
+
+    /// \brief Runs a search while the Policy stops it.
+    ///
+    /// \param startn The start node where the search begins.
+    inline void  run( const Node startn ) {
+      std::cin.unsetf( std::ios_base::skipws );
+      char c;
+      init( startn );
+      while( step() )
+      std::cin >> c;
+      std::cin.setf( std::ios_base::skipws );
+    }
+
+    ///@}
+
+    /// \name Query Functions
+    /// The result of the TabuSearch algorithm can be obtained using these
+    /// functions.\n
+    ///@{
+
+    /// \brief The node, the search is standing on.
+    inline Node  current() const {
+      return tabu[0];
+    }
+
+    /// \brief The best node found until now.
+    inline Node  best() const {
+      return b;
+    }
+
+    /// \brief Beginning to iterate on the current tabu set.
+    inline TabuIterator  tabu_begin() const {
+      return tabu.begin();
+    }
+
+    /// \brief Ending to iterate on the current tabu set.
+    inline TabuIterator  tabu_end() const {
+      return tabu.end();
+    }
+
+    ///@}
+  };
+}
+#endif



More information about the Lemon-commits mailing list