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

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


Author: deba
Date: Wed Nov  2 16:22:28 2005
New Revision: 2278

Modified:
   hugo/trunk/lemon/dfs.h

Log:
Visitor interface for the dfs algorithm.



Modified: hugo/trunk/lemon/dfs.h
==============================================================================
--- hugo/trunk/lemon/dfs.h	(original)
+++ hugo/trunk/lemon/dfs.h	Wed Nov  2 16:22:28 2005
@@ -27,8 +27,9 @@
 #include <lemon/error.h>
 #include <lemon/maps.h>
 
-namespace lemon {
+#include <lemon/concept_check.h>
 
+namespace lemon {
 
   
   ///Default traits class of Dfs class.
@@ -123,8 +124,6 @@
   ///a Dfs traits class.
   ///
   ///\author Jacint Szabo and Alpar Juttner
-  ///\todo A compare object would be nice.
-
 #ifdef DOXYGEN
   template <typename GR,
 	    typename TR>
@@ -275,7 +274,7 @@
     ///\ref named-templ-param "Named parameter" for setting ReachedMap type
     ///
     template <class T>
-    struct DefReachedMap {
+    struct DefReachedMap : public Dfs< Graph, DefReachedMapTraits<T> > {
       typedef Dfs< Graph, DefReachedMapTraits<T> > Create;
     };
 
@@ -326,7 +325,6 @@
     Dfs(const Graph& _G) :
       G(&_G),
       _pred(NULL), local_pred(false),
-//       _predNode(NULL), local_predNode(false),
       _dist(NULL), local_dist(false),
       _reached(NULL), local_reached(false),
       _processed(NULL), local_processed(false)
@@ -336,7 +334,6 @@
     ~Dfs() 
     {
       if(local_pred) delete _pred;
-//       if(local_predNode) delete _predNode;
       if(local_dist) delete _dist;
       if(local_reached) delete _reached;
       if(local_processed) delete _processed;
@@ -359,23 +356,6 @@
       return *this;
     }
 
-//     ///Sets the map storing the predecessor nodes.
-
-//     ///Sets the map storing the predecessor nodes.
-//     ///If you don't use this function before calling \ref run(),
-//     ///it will allocate one. The destuctor deallocates this
-//     ///automatically allocated map, of course.
-//     ///\return <tt> (*this) </tt>
-//     Dfs &predNodeMap(PredNodeMap &m) 
-//     {
-//       if(local_predNode) {
-// 	delete _predNode;
-// 	local_predNode=false;
-//       }
-//       _predNode = &m;
-//       return *this;
-//     }
-
     ///Sets the map storing the distances calculated by the algorithm.
 
     ///Sets the map storing the distances calculated by the algorithm.
@@ -468,7 +448,6 @@
 	{
 	  _reached->set(s,true);
 	  _pred->set(s,INVALID);
-	  // _predNode->set(u,INVALID);
 	  OutEdgeIt e(*G,s);
 	  if(e!=INVALID) {
 	    _stack[++_stack_head]=e;
@@ -495,7 +474,6 @@
       if(!(*_reached)[m=G->target(e)]) {
 	_pred->set(m,e);
 	_reached->set(m,true);
-	//	  _pred_node->set(m,G->source(e));
 	++_stack_head;
 	_stack[_stack_head] = OutEdgeIt(*G, m);
 	_dist->set(m,_stack_head);
@@ -504,7 +482,6 @@
 	m=G->source(e);
 	++_stack[_stack_head];
       }
-      //'m' is now the (original) source of the _stack[_stack_head] 
       while(_stack_head>=0 && _stack[_stack_head]==INVALID) {
 	_processed->set(m,true);
 	--_stack_head;
@@ -590,14 +567,14 @@
     ///\param nm must be a bool (or convertible) edge map. The algorithm
     ///will stop when it reaches an edge \c e with <tt>nm[e]==true</tt>.
     ///
-    ///\warning Contrary to \ref Dfs and \ref Dijkstra, \c nm is an edge map,
+    ///\warning Contrary to \ref Dfs and \ref Dijkstra, \c em is an edge map,
     ///not a node map.
-    template<class NM>
-      void start(const NM &nm)
-      {
-	while ( !emptyQueue() && !nm[_stack[_stack_head]] ) processNextEdge();
-      }
-    
+    template<class EM>
+    void start(const EM &em)
+    {
+      while ( !emptyQueue() && !em[_stack[_stack_head]] ) processNextEdge();
+    }
+
     ///Runs %DFS algorithm from node \c s.
     
     ///This method runs the %DFS algorithm from a root node \c s
@@ -725,13 +702,6 @@
     ///must be called before using this function.
     const PredMap &predMap() const { return *_pred;}
  
-//     ///Returns a reference to the map of nodes of %DFS paths.
-
-//     ///Returns a reference to the NodeMap of the last but one nodes of the
-//     ///%DFS tree.
-//     ///\pre \ref run() must be called before using this function.
-//     const PredNodeMap &predNodeMap() const { return *_predNode;}
-
     ///Checks if a node is reachable from the root.
 
     ///Returns \c true if \c v is reachable from the root(s).
@@ -774,23 +744,6 @@
     {
       return new PredMap();
     }
-//     ///\brief The type of the map that stores the last but one
-//     ///nodes of the %DFS paths.
-//     ///
-//     ///The type of the map that stores the last but one
-//     ///nodes of the %DFS paths.
-//     ///It must meet the \ref concept::WriteMap "WriteMap" concept.
-//     ///
-//     typedef NullMap<typename Graph::Node,typename Graph::Node> PredNodeMap;
-//     ///Instantiates a PredNodeMap.
-    
-//     ///This function instantiates a \ref PredNodeMap. 
-//     ///\param G is the graph, to which
-//     ///we would like to define the \ref PredNodeMap
-//     static PredNodeMap *createPredNodeMap(const GR &G)
-//     {
-//       return new PredNodeMap();
-//     }
 
     ///The type of the map that indicates which nodes are processed.
  
@@ -871,8 +824,6 @@
     void *_processed;
     ///Pointer to the map of predecessors edges.
     void *_pred;
-//     ///Pointer to the map of predecessors nodes.
-//     void *_predNode;
     ///Pointer to the map of distances.
     void *_dist;
     ///Pointer to the source node.
@@ -884,7 +835,6 @@
     /// This constructor does not require parameters, therefore it initiates
     /// all of the attributes to default values (0, INVALID).
     DfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0),
-// 			   _predNode(0),
 			   _dist(0), _source(INVALID) {}
 
     /// Constructor.
@@ -896,7 +846,6 @@
     /// \param s is the initial value of  \ref _source
     DfsWizardBase(const GR &g, Node s=INVALID) :
       _g((void *)&g), _reached(0), _processed(0), _pred(0),
-//       _predNode(0),
       _dist(0), _source(s) {}
 
   };
@@ -945,9 +894,6 @@
     ///\brief The type of the map that stores the last
     ///edges of the %DFS paths.
     typedef typename TR::PredMap PredMap;
-//     ///\brief The type of the map that stores the last but one
-//     ///nodes of the %DFS paths.
-//     typedef typename TR::PredNodeMap PredNodeMap;
     ///The type of the map that stores the distances of the nodes.
     typedef typename TR::DistMap DistMap;
 
@@ -978,7 +924,6 @@
       if(Base::_reached) alg.reachedMap(*(ReachedMap*)Base::_reached);
       if(Base::_processed) alg.processedMap(*(ProcessedMap*)Base::_processed);
       if(Base::_pred) alg.predMap(*(PredMap*)Base::_pred);
-//       if(Base::_predNode) alg.predNodeMap(*(PredNodeMap*)Base::_predNode);
       if(Base::_dist) alg.distMap(*(DistMap*)Base::_dist);
       alg.run(Base::_source);
     }
@@ -1055,27 +1000,6 @@
       return DfsWizard<DefProcessedMapBase<T> >(*this);
     }
     
-
-//     template<class T>
-//     struct DefPredNodeMapBase : public Base {
-//       typedef T PredNodeMap;
-//       static PredNodeMap *createPredNodeMap(const Graph &G) { return 0; };
-//       DefPredNodeMapBase(const TR &b) : TR(b) {}
-//     };
-    
-//     ///\brief \ref named-templ-param "Named parameter"
-//     ///function for setting PredNodeMap type
-//     ///
-//     /// \ref named-templ-param "Named parameter"
-//     ///function for setting PredNodeMap type
-//     ///
-//     template<class T>
-//     DfsWizard<DefPredNodeMapBase<T> > predNodeMap(const T &t) 
-//     {
-//       Base::_predNode=(void *)&t;
-//       return DfsWizard<DefPredNodeMapBase<T> >(*this);
-//     }
-   
     template<class T>
     struct DefDistMapBase : public Base {
       typedef T DistMap;
@@ -1132,6 +1056,414 @@
     return DfsWizard<DfsWizardBase<GR> >(g,s);
   }
 
+  /// \brief Visitor class for dfs.
+  ///  
+  /// It gives a simple interface for a functional interface for dfs 
+  /// traversal. The traversal on a linear data structure. 
+  template <typename _Graph>
+  struct DfsVisitor {
+    typedef _Graph Graph;
+    typedef typename Graph::Edge Edge;
+    typedef typename Graph::Node Node;
+    /// \brief Called when the edge reach a node.
+    /// 
+    /// It is called when the dfs find an edge which target is not
+    /// reached yet.
+    void discover(const Edge& edge) {}
+    /// \brief Called when the node reached first time.
+    /// 
+    /// It is Called when the node reached first time.
+    void reach(const Node& node) {}
+    /// \brief Called when we step back on an edge.
+    /// 
+    /// It is called when the dfs should step back on the edge.
+    void backtrack(const Edge& edge) {}
+    /// \brief Called when we step back from the node.
+    /// 
+    /// It is called when we step back from the node.
+    void leave(const Node& node) {}
+    /// \brief Called when the edge examined but target of the edge 
+    /// already discovered.
+    /// 
+    /// It called when the edge examined but the target of the edge 
+    /// already discovered.
+    void examine(const Edge& edge) {}
+    /// \brief Called for the source node of the dfs.
+    /// 
+    /// It is called for the source node of the dfs.
+    void start(const Node&) {}
+    /// \brief Called when we leave the source node of the dfs.
+    /// 
+    /// It is called when we leave the source node of the dfs.
+    void stop(const Node&) {}
+
+    template <typename _Visitor>
+    struct Constraints {
+      void constraints() {
+	Edge edge;
+	Node node;
+	visitor.discover(edge);
+	visitor.reach(node);
+	visitor.backtrack(edge);
+	visitor.leave(node);
+	visitor.examine(edge);
+	visitor.start(node);
+	visitor.stop(edge);
+      }
+      _Visitor& visitor;
+    };
+  };
+
+  /// \brief Default traits class of DfsVisit class.
+  ///
+  /// Default traits class of DfsVisit class.
+  /// \param _Graph Graph type.
+  template<class _Graph>
+  struct DfsVisitDefaultTraits {
+
+    /// \brief The graph type the algorithm runs on. 
+    typedef _Graph Graph;
+
+    /// \brief The type of the map that indicates which nodes are reached.
+    /// 
+    /// The type of the map that indicates which nodes are reached.
+    /// It must meet the \ref concept::WriteMap "WriteMap" concept.
+    /// \todo named parameter to set this type, function to read and write.
+    typedef typename Graph::template NodeMap<bool> ReachedMap;
+
+    /// \brief Instantiates a ReachedMap.
+    ///
+    /// This function instantiates a \ref ReachedMap. 
+    /// \param G is the graph, to which
+    /// we would like to define the \ref ReachedMap.
+    static ReachedMap *createReachedMap(const Graph &graph) {
+      return new ReachedMap(graph);
+    }
+
+  };
+  
+  /// %DFS Visit algorithm class.
+  
+  /// \ingroup flowalgs
+  /// This class provides an efficient implementation of the %DFS algorithm
+  /// with visitor interface.
+  ///
+  /// The %DfsVisit class provides an alternative interface to the Dfs
+  /// class. It works with callback mechanism, the DfsVisit object calls
+  /// on every dfs event the \c Visitor class member functions. 
+  ///
+  /// \param _Graph The graph type the algorithm runs on. The default value is
+  /// \ref ListGraph. The value of _Graph is not used directly by Dfs, it
+  /// is only passed to \ref DfsDefaultTraits.
+  /// \param _Visitor The Visitor object for the algorithm. The 
+  /// \ref DfsVisitor "DfsVisitor<_Graph>" is an empty Visitor which
+  /// does not observe the Dfs events. If you want to observe the dfs
+  /// events you should implement your own Visitor class.
+  /// \param _Traits Traits class to set various data types used by the 
+  /// algorithm. The default traits class is
+  /// \ref DfsVisitDefaultTraits "DfsVisitDefaultTraits<_Graph>".
+  /// See \ref DfsVisitDefaultTraits for the documentation of
+  /// a Dfs visit traits class.
+  ///
+  /// \author Jacint Szabo, Alpar Juttner and Balazs Dezso
+#ifdef DOXYGEN
+  template <typename _Graph, typename _Visitor, typename _Traits>
+#else
+  template <typename _Graph = ListGraph,
+	    typename _Visitor = DfsVisitor<_Graph>,
+	    typename _Traits = DfsDefaultTraits<_Graph> >
+#endif
+  class DfsVisit {
+  public:
+    
+    /// \brief \ref Exception for uninitialized parameters.
+    ///
+    /// This error represents problems in the initialization
+    /// of the parameters of the algorithms.
+    class UninitializedParameter : public lemon::UninitializedParameter {
+    public:
+      virtual const char* exceptionName() const {
+	return "lemon::DfsVisit::UninitializedParameter";
+      }
+    };
+
+    typedef _Traits Traits;
+
+    typedef typename Traits::Graph Graph;
+
+    typedef _Visitor Visitor;
+
+    ///The type of the map indicating which nodes are reached.
+    typedef typename Traits::ReachedMap ReachedMap;
+
+  private:
+
+    typedef typename Graph::Node Node;
+    typedef typename Graph::NodeIt NodeIt;
+    typedef typename Graph::Edge Edge;
+    typedef typename Graph::OutEdgeIt OutEdgeIt;
+
+    /// Pointer to the underlying graph.
+    const Graph *_graph;
+    /// Pointer to the visitor object.
+    Visitor *_visitor;
+    ///Pointer to the map of reached status of the nodes.
+    ReachedMap *_reached;
+    ///Indicates if \ref _reached is locally allocated (\c true) or not.
+    bool local_reached;
+
+    std::vector<typename Graph::Edge> _stack;
+    int _stack_head;
+
+    /// \brief Creates the maps if necessary.
+    ///
+    /// Creates the maps if necessary.
+    void create_maps() {
+      if(!_reached) {
+	local_reached = true;
+	_reached = Traits::createReachedMap(*_graph);
+      }
+    }
+
+  protected:
+
+    DfsVisit() {}
+    
+  public:
+
+    typedef DfsVisit Create;
+
+    /// \name Named template parameters
+
+    ///@{
+    template <class T>
+    struct DefReachedMapTraits : public Traits {
+      typedef T ReachedMap;
+      static ReachedMap *createReachedMap(const Graph &graph) {
+	throw UninitializedParameter();
+      }
+    };
+    /// \brief \ref named-templ-param "Named parameter" for setting 
+    /// ReachedMap type
+    ///
+    /// \ref named-templ-param "Named parameter" for setting ReachedMap type
+    template <class T>
+    struct DefReachedMap : public Dfs< Graph, DefReachedMapTraits<T> > {
+      typedef Dfs< Graph, DefReachedMapTraits<T> > Create;
+    };
+    ///@}
+
+  public:      
+    
+    /// \brief Constructor.
+    ///
+    /// Constructor.
+    ///
+    /// \param graph the graph the algorithm will run on.
+    /// \param visitor The visitor of the algorithm.
+    ///
+    DfsVisit(const Graph& graph, Visitor& visitor) 
+      : _graph(&graph), _visitor(&visitor),
+	_reached(0), local_reached(false) {}
+    
+    /// \brief Destructor.
+    ///
+    /// Destructor.
+    ~DfsVisit() {
+      if(local_reached) delete _reached;
+    }
+
+    /// \brief Sets the map indicating if a node is reached.
+    ///
+    /// Sets the map indicating if a node is reached.
+    /// If you don't use this function before calling \ref run(),
+    /// it will allocate one. The destuctor deallocates this
+    /// automatically allocated map, of course.
+    /// \return <tt> (*this) </tt>
+    DfsVisit &reachedMap(ReachedMap &m) {
+      if(local_reached) {
+	delete _reached;
+	local_reached=false;
+      }
+      _reached = &m;
+      return *this;
+    }
+
+  public:
+    /// \name Execution control
+    /// The simplest way to execute the algorithm is to use
+    /// one of the member functions called \c run(...).
+    /// \n
+    /// If you need more control on the execution,
+    /// first you must call \ref init(), then you can add several source nodes
+    /// with \ref addSource().
+    /// Finally \ref start() will perform the actual path
+    /// computation.
+
+    /// @{
+    /// \brief Initializes the internal data structures.
+    ///
+    /// Initializes the internal data structures.
+    ///
+    void init() {
+      create_maps();
+      _stack.resize(countNodes(*_graph));
+      _stack_head = -1;
+      for (NodeIt u(*_graph) ; u != INVALID ; ++u) {
+	_reached->set(u, false);
+      }
+    }
+    
+    /// \brief Adds a new source node.
+    ///
+    /// Adds a new source node to the set of nodes to be processed.
+    void addSource(Node s) {
+      if(!(*_reached)[s]) {
+	  _reached->set(s,true);
+	  _visitor->start(s);
+	  _visitor->reach(s);
+	  Edge e; 
+	  _graph->firstOut(e, s);
+	  if (e != INVALID) {
+	    _stack[++_stack_head] = e;
+	  } else {
+	    _visitor->leave(s);
+	  }
+	}
+    }
+    
+    /// \brief Processes the next edge.
+    ///
+    /// Processes the next edge.
+    ///
+    /// \return The processed edge.
+    ///
+    /// \pre The stack must not be empty!
+    Edge processNextEdge() { 
+      Edge e = _stack[_stack_head];
+      Node m = _graph->target(e);
+      if(!(*_reached)[m]) {
+	_visitor->discover(e);
+	_visitor->reach(m);
+	_reached->set(m, true);
+	_graph->firstOut(_stack[++_stack_head], m);
+      } else {
+	_visitor->examine(e);
+	m = _graph->source(e);
+	_graph->nextOut(_stack[_stack_head]);
+      }
+      while (_stack_head>=0 && _stack[_stack_head] == INVALID) {
+	_visitor->leave(m);
+	--_stack_head;
+	if (_stack_head >= 0) {
+	  _visitor->backtrack(_stack[_stack_head]);
+	  m = _graph->source(_stack[_stack_head]);
+	  _graph->nextOut(_stack[_stack_head]);
+	} else {
+	  _visitor->stop(m);	  
+	}
+      }
+      return e;
+    }
+
+    /// \brief Next edge to be processed.
+    ///
+    /// Next edge to be processed.
+    ///
+    /// \return The next edge to be processed or INVALID if the stack is
+    /// empty.
+    Edge nextEdge() { 
+      return _stack_head >= 0 ? _stack[_stack_head] : INVALID;
+    }
+
+    /// \brief Returns \c false if there are nodes
+    /// to be processed in the queue
+    ///
+    /// Returns \c false if there are nodes
+    /// to be processed in the queue
+    ///
+    /// \todo This should be called emptyStack() or some "neutral" name.
+    bool emptyQueue() { return _stack_head < 0; }
+
+    /// \brief Returns the number of the nodes to be processed.
+    ///
+    /// Returns the number of the nodes to be processed in the queue.
+    ///
+    ///\todo This should be called stackSize() or some "neutral" name.
+    int queueSize() { return _stack_head + 1; }
+    
+    /// \brief Executes the algorithm.
+    ///
+    /// Executes the algorithm.
+    ///
+    /// \pre init() must be called and at least one node should be added
+    /// with addSource() before using this function.
+    void start() {
+      while ( !emptyQueue() ) processNextEdge();
+    }
+    
+    /// \brief Executes the algorithm until \c dest is reached.
+    ///
+    /// Executes the algorithm until \c dest is reached.
+    ///
+    /// \pre init() must be called and at least one node should be added
+    /// with addSource() before using this function.
+    void start(Node dest) {
+      while ( !emptyQueue() && _graph->target(_stack[_stack_head]) != dest) 
+	processNextEdge();
+    }
+    
+    /// \brief Executes the algorithm until a condition is met.
+    ///
+    /// Executes the algorithm until a condition is met.
+    ///
+    /// \pre init() must be called and at least one node should be added
+    /// with addSource() before using this function.
+    ///
+    /// \param nm must be a bool (or convertible) edge map. The algorithm
+    /// will stop when it reaches an edge \c e with <tt>nm[e]==true</tt>.
+    ///
+    /// \warning Contrary to \ref Dfs and \ref Dijkstra, \c em is an edge map,
+    /// not a node map.
+    template <typename EM>
+    void start(const EM &em) {
+      while (!emptyQueue() && !em[_stack[_stack_head]]) processNextEdge();
+    }
+
+    /// \brief Runs %DFS algorithm from node \c s.
+    ///
+    /// This method runs the %DFS algorithm from a root node \c s.
+    /// \note d.run(s) is just a shortcut of the following code.
+    /// \code
+    ///   d.init();
+    ///   d.addSource(s);
+    ///   d.start();
+    /// \endcode
+    void run(Node s) {
+      init();
+      addSource(s);
+      start();
+    }
+    ///@}
+
+    /// \name Query Functions
+    /// The result of the %DFS algorithm can be obtained using these
+    /// functions.\n
+    /// Before the use of these functions,
+    /// either run() or start() must be called.
+    ///@{
+    /// \brief Checks if a node is reachable from the root.
+    ///
+    /// Returns \c true if \c v is reachable from the root(s).
+    /// \warning The source nodes are inditated as unreachable.
+    /// \pre Either \ref run() or \ref start()
+    /// must be called before using this function.
+    ///
+    bool reached(Node v) { return (*_reached)[v]; }
+    ///@}
+  };
+
+
 } //END OF NAMESPACE LEMON
 
 #endif



More information about the Lemon-commits mailing list