diff -r 4a2236cc98a0 -r 42cce226b87b lemon/bfs.h --- a/lemon/bfs.h Tue Nov 21 17:28:08 2006 +0000 +++ b/lemon/bfs.h Tue Nov 21 18:22:08 2006 +0000 @@ -587,9 +587,9 @@ while ( !emptyQueue() ) processNextNode(); } - ///Executes the algorithm until \c dest is reached. + ///Executes the algorithm until \c dest is the next node to processed. - ///Executes the algorithm until \c dest is reached. + ///Executes the algorithm until \c dest is the next node to processed. /// ///\pre init() must be called and at least one node should be added ///with addSource() before using this function. @@ -614,8 +614,9 @@ ///\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) node map. The algorithm - ///will stop when it reaches a node \c v with nm[v]==true. + ///\param nm must be a bool (or convertible) node map. The + ///algorithm will stop when for the next processable node \c v is + ///nm[v] true. ///\todo query the reached target template void start(const NM &nm) @@ -633,11 +634,11 @@ ///- The shortest path tree. ///- The distance of each node from the root. /// - ///\note d.run(s) is just a shortcut of the following code. + ///\note b.run(s) is just a shortcut of the following code. ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(); + /// b.init(); + /// b.addSource(s); + /// b.start(); ///\endcode void run(Node s) { init(); @@ -651,12 +652,12 @@ /// ///\return The length of the shortest s---t path if there exists one, ///0 otherwise. - ///\note Apart from the return value, d.run(s) is + ///\note Apart from the return value, b.run(s) is ///just a shortcut of the following code. ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(t); + /// b.init(); + /// b.addSource(s); + /// b.start(t); ///\endcode int run(Node s,Node t) { init(); @@ -671,7 +672,7 @@ ///The result of the %BFS algorithm can be obtained using these ///functions.\n ///Before the use of these functions, - ///either run() or start() must be called. + ///either run() or start() must be calleb. ///@{ @@ -943,7 +944,7 @@ ///The type of the map that stores the dists of the nodes. typedef typename TR::DistMap DistMap; -public: + public: /// Constructor. BfsWizard() : TR() {} @@ -1104,6 +1105,495 @@ return BfsWizard >(g,s); } +#ifdef DOXYGEN + /// \brief Visitor class for bfs. + /// + /// It gives a simple interface for a functional interface for bfs + /// traversal. The traversal on a linear data structure. + template + struct BfsVisitor { + 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 bfs 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 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 bfs. + /// + /// It is called for the source node of the bfs. + void start(const Node& node) {} + /// \brief Called when the node processed. + /// + /// It is Called when the node processed. + void process(const Node& node) {} + }; +#else + template + struct BfsVisitor { + typedef _Graph Graph; + typedef typename Graph::Edge Edge; + typedef typename Graph::Node Node; + void discover(const Edge&) {} + void reach(const Node&) {} + void examine(const Edge&) {} + void start(const Node&) {} + void process(const Node&) {} + + template + struct Constraints { + void constraints() { + Edge edge; + Node node; + visitor.discover(edge); + visitor.reach(node); + visitor.examine(edge); + visitor.start(node); + visitor.process(node); + } + _Visitor& visitor; + }; + }; +#endif + + /// \brief Default traits class of BfsVisit class. + /// + /// Default traits class of BfsVisit class. + /// \param _Graph Graph type. + template + struct BfsVisitDefaultTraits { + + /// \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 concepts::WriteMap "WriteMap" concept. + /// \todo named parameter to set this type, function to read and write. + typedef typename Graph::template NodeMap ReachedMap; + + /// \brief Instantiates a ReachedMap. + /// + /// This function instantiates a \ref ReachedMap. + /// \param graph is the graph, to which + /// we would like to define the \ref ReachedMap. + static ReachedMap *createReachedMap(const Graph &graph) { + return new ReachedMap(graph); + } + + }; + + /// %BFS Visit algorithm class. + + /// \ingroup flowalgs + /// This class provides an efficient implementation of the %BFS algorithm + /// with visitor interface. + /// + /// The %BfsVisit class provides an alternative interface to the Bfs + /// class. It works with callback mechanism, the BfsVisit object calls + /// on every bfs 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 Bfs, it + /// is only passed to \ref BfsDefaultTraits. + /// \param _Visitor The Visitor object for the algorithm. The + /// \ref BfsVisitor "BfsVisitor<_Graph>" is an empty Visitor which + /// does not observe the Bfs events. If you want to observe the bfs + /// 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 BfsVisitDefaultTraits "BfsVisitDefaultTraits<_Graph>". + /// See \ref BfsVisitDefaultTraits for the documentation of + /// a Bfs visit traits class. + /// + /// \author Jacint Szabo, Alpar Juttner and Balazs Dezso +#ifdef DOXYGEN + template +#else + template , + typename _Traits = BfsDefaultTraits<_Graph> > +#endif + class BfsVisit { + 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* what() const throw() + { + return "lemon::BfsVisit::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 _list; + int _list_front, _list_back; + + /// \brief Creates the maps if necessary. + /// + /// Creates the maps if necessary. + void create_maps() { + if(!_reached) { + local_reached = true; + _reached = Traits::createReachedMap(*_graph); + } + } + + protected: + + BfsVisit() {} + + public: + + typedef BfsVisit Create; + + /// \name Named template parameters + + ///@{ + template + 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 + struct DefReachedMap : public BfsVisit< Graph, Visitor, + DefReachedMapTraits > { + typedef BfsVisit< Graph, Visitor, DefReachedMapTraits > Create; + }; + ///@} + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// + /// \param graph the graph the algorithm will run on. + /// \param visitor The visitor of the algorithm. + /// + BfsVisit(const Graph& graph, Visitor& visitor) + : _graph(&graph), _visitor(&visitor), + _reached(0), local_reached(false) {} + + /// \brief Destructor. + /// + /// Destructor. + ~BfsVisit() { + 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 (*this) + BfsVisit &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 adda source node + /// 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(); + _list.resize(countNodes(*_graph)); + _list_front = _list_back = -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); + _list[++_list_back] = s; + } + } + + /// \brief Processes the next node. + /// + /// Processes the next node. + /// + /// \return The processed node. + /// + /// \pre The queue must not be empty! + Node processNextNode() { + Node n = _list[++_list_front]; + _visitor->process(n); + Edge e; + for (_graph->firstOut(e, n); e != INVALID; _graph->nextOut(e)) { + Node m = _graph->target(e); + if (!(*_reached)[m]) { + _visitor->discover(e); + _visitor->reach(m); + _reached->set(m, true); + _list[++_list_back] = m; + } else { + _visitor->examine(e); + } + } + return n; + } + + /// \brief Processes the next node. + /// + /// Processes the next node. And checks that the given target node + /// is reached. If the target node is reachable from the processed + /// node then the reached parameter will be set true. The reached + /// parameter should be initially false. + /// + /// \param target The target node. + /// \retval reached Indicates that the target node is reached. + /// \return The processed node. + /// + /// \warning The queue must not be empty! + Node processNextNode(Node target, bool& reached) { + Node n = _list[++_list_front]; + _visitor->process(n); + Edge e; + for (_graph->firstOut(e, n); e != INVALID; _graph->nextOut(e)) { + Node m = _graph->target(e); + if (!(*_reached)[m]) { + _visitor->discover(e); + _visitor->reach(m); + _reached->set(m, true); + _list[++_list_back] = m; + reached = reached || (target == m); + } else { + _visitor->examine(e); + } + } + return n; + } + + /// \brief Processes the next node. + /// + /// Processes the next node. And checks that at least one of + /// reached node has true value in the \c nm nodemap. If one node + /// with true value is reachable from the processed node then the + /// reached parameter will be set true. The reached parameter + /// should be initially false. + /// + /// \param target The nodemaps of possible targets. + /// \retval reached Indicates that one of the target nodes is reached. + /// \return The processed node. + /// + /// \warning The queue must not be empty! + template + Node processNextNode(const NM& nm, bool& reached) { + Node n = _list[++_list_front]; + _visitor->process(n); + Edge e; + for (_graph->firstOut(e, n); e != INVALID; _graph->nextOut(e)) { + Node m = _graph->target(e); + if (!(*_reached)[m]) { + _visitor->discover(e); + _visitor->reach(m); + _reached->set(m, true); + _list[++_list_back] = m; + reached = reached || nm[m]; + } else { + _visitor->examine(e); + } + } + return n; + } + + /// \brief Next node to be processed. + /// + /// Next node to be processed. + /// + /// \return The next node to be processed or INVALID if the stack is + /// empty. + Node nextNode() { + return _list_front != _list_back ? _list[_list_front + 1] : 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 + bool emptyQueue() { return _list_front == _list_back; } + + /// \brief Returns the number of the nodes to be processed. + /// + /// Returns the number of the nodes to be processed in the queue. + int queueSize() { return _list_back - _list_front; } + + /// \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() ) processNextNode(); + } + + /// \brief Executes the algorithm until \c dest will be next processed. + /// + /// Executes the algorithm until \c dest will be next processed. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + void start(Node dest) { + bool reached = false; + while (!emptyQueue() && !reached) { + processNextNode(dest, reached); + } + } + + /// \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) node map. The + ///algorithm will stop when it reaches a node \c v with + ///nm[v] true. + template + void start(const NM &nm) { + bool reached = false; + while (!emptyQueue() && !reached) { + processNextNode(nm, reached); + } + } + + /// \brief Runs %BFSVisit algorithm from node \c s. + /// + /// This method runs the %BFS algorithm from a root node \c s. + /// \note b.run(s) is just a shortcut of the following code. + ///\code + /// b.init(); + /// b.addSource(s); + /// b.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Runs %BFSVisit algorithm to visit all nodes in the graph. + /// + /// This method runs the %BFS algorithm in order to + /// compute the %BFS path to each node. The algorithm computes + /// - The %BFS tree. + /// - The distance of each node from the root in the %BFS tree. + /// + ///\note b.run() is just a shortcut of the following code. + ///\code + /// b.init(); + /// for (NodeIt it(graph); it != INVALID; ++it) { + /// if (!b.reached(it)) { + /// b.addSource(it); + /// b.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt it(*_graph); it != INVALID; ++it) { + if (!reached(it)) { + addSource(it); + start(); + } + } + } + ///@} + + /// \name Query Functions + /// The result of the %BFS 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