src/work/marci/bfs_iterator.h
author marci
Mon, 10 May 2004 16:31:48 +0000
changeset 597 a6e2b02f496a
parent 560 5adcef1d7bcc
permissions -rw-r--r--
bfs, dfs docs
marci@301
     1
// -*- c++ -*-
marci@301
     2
#ifndef HUGO_BFS_ITERATOR_H
marci@301
     3
#define HUGO_BFS_ITERATOR_H
marci@301
     4
marci@301
     5
#include <queue>
marci@301
     6
#include <stack>
marci@301
     7
#include <utility>
marci@301
     8
marci@560
     9
#include <hugo/invalid.h>
marci@560
    10
marci@301
    11
namespace hugo {
marci@301
    12
marci@597
    13
  /// Bfs searches for the nodes wich are not marked in 
marci@597
    14
  /// \c reached_map
marci@597
    15
  /// Reached have to work as read-write bool Node-map.
marci@303
    16
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@303
    17
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@360
    18
  class BfsIterator {
marci@303
    19
  protected:
marci@303
    20
    typedef typename Graph::Node Node;
marci@303
    21
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@303
    22
    const Graph* graph;
marci@301
    23
    std::queue<Node> bfs_queue;
marci@301
    24
    ReachedMap& reached;
marci@301
    25
    bool b_node_newly_reached;
marci@301
    26
    OutEdgeIt actual_edge;
marci@301
    27
    bool own_reached_map;
marci@301
    28
  public:
marci@597
    29
    /// In that constructor \c _reached have to be a reference 
marci@597
    30
    /// for a bool Node-map. The algorithm will search in a bfs order for 
marci@597
    31
    /// the nodes which are \c false initially
marci@360
    32
    BfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@303
    33
      graph(&_graph), reached(_reached), 
marci@301
    34
      own_reached_map(false) { }
marci@597
    35
    /// The same as above, but the map storing the reached nodes 
marci@597
    36
    /// is constructed dynamically to everywhere false.
marci@360
    37
    BfsIterator(const Graph& _graph) : 
marci@303
    38
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@301
    39
      own_reached_map(true) { }
marci@597
    40
    /// The storing the reached nodes have to be destroyed if 
marci@597
    41
    /// it was constructed dynamically
marci@360
    42
    ~BfsIterator() { if (own_reached_map) delete &reached; }
marci@597
    43
    /// This method markes \c s reached.
marci@597
    44
    /// If the queue is empty, then \c s is pushed in the bfs queue 
marci@597
    45
    /// and the first out-edge is processed.
marci@597
    46
    /// If the queue is not empty, then \c s is simply pushed.
marci@301
    47
    void pushAndSetReached(Node s) { 
marci@301
    48
      reached.set(s, true);
marci@301
    49
      if (bfs_queue.empty()) {
marci@301
    50
	bfs_queue.push(s);
marci@303
    51
	graph->first(actual_edge, s);
marci@303
    52
	if (graph->valid(actual_edge)) { 
marci@303
    53
	  Node w=graph->bNode(actual_edge);
marci@303
    54
	  if (!reached[w]) {
marci@301
    55
	    bfs_queue.push(w);
marci@301
    56
	    reached.set(w, true);
marci@301
    57
	    b_node_newly_reached=true;
marci@301
    58
	  } else {
marci@301
    59
	    b_node_newly_reached=false;
marci@301
    60
	  }
marci@301
    61
	} 
marci@301
    62
      } else {
marci@301
    63
	bfs_queue.push(s);
marci@301
    64
      }
marci@301
    65
    }
marci@448
    66
    /// As \c BfsIterator<Graph, ReachedMap> works as an edge-iterator, 
marci@448
    67
    /// its \c operator++() iterates on the edges in a bfs order.
marci@360
    68
    BfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@301
    69
    operator++() { 
marci@303
    70
      if (graph->valid(actual_edge)) { 
marci@303
    71
	graph->next(actual_edge);
marci@303
    72
	if (graph->valid(actual_edge)) {
marci@303
    73
	  Node w=graph->bNode(actual_edge);
marci@303
    74
	  if (!reached[w]) {
marci@301
    75
	    bfs_queue.push(w);
marci@301
    76
	    reached.set(w, true);
marci@301
    77
	    b_node_newly_reached=true;
marci@301
    78
	  } else {
marci@301
    79
	    b_node_newly_reached=false;
marci@301
    80
	  }
marci@301
    81
	}
marci@301
    82
      } else {
marci@301
    83
	bfs_queue.pop(); 
marci@301
    84
	if (!bfs_queue.empty()) {
marci@303
    85
	  graph->first(actual_edge, bfs_queue.front());
marci@303
    86
	  if (graph->valid(actual_edge)) {
marci@303
    87
	    Node w=graph->bNode(actual_edge);
marci@303
    88
	    if (!reached[w]) {
marci@301
    89
	      bfs_queue.push(w);
marci@301
    90
	      reached.set(w, true);
marci@301
    91
	      b_node_newly_reached=true;
marci@301
    92
	    } else {
marci@301
    93
	      b_node_newly_reached=false;
marci@301
    94
	    }
marci@301
    95
	  }
marci@301
    96
	}
marci@301
    97
      }
marci@301
    98
      return *this;
marci@301
    99
    }
marci@597
   100
    ///
marci@301
   101
    bool finished() const { return bfs_queue.empty(); }
marci@448
   102
    /// The conversion operator makes for converting the bfs-iterator 
marci@448
   103
    /// to an \c out-edge-iterator.
marci@597
   104
    ///\bug Edge have to be in HUGO 0.2
marci@409
   105
    operator OutEdgeIt() const { return actual_edge; }
marci@597
   106
    ///
marci@301
   107
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@597
   108
    ///
marci@303
   109
    bool isANodeExamined() const { return !(graph->valid(actual_edge)); }
marci@597
   110
    ///
marci@301
   111
    Node aNode() const { return bfs_queue.front(); }
marci@597
   112
    ///
marci@303
   113
    Node bNode() const { return graph->bNode(actual_edge); }
marci@597
   114
    ///
marci@301
   115
    const ReachedMap& getReachedMap() const { return reached; }
marci@597
   116
    ///
marci@301
   117
    const std::queue<Node>& getBfsQueue() const { return bfs_queue; }
marci@301
   118
  };  
marci@301
   119
marci@597
   120
  /// Bfs searches for the nodes wich are not marked in 
marci@448
   121
  /// \c reached_map
marci@597
   122
  /// Reached have to work as a read-write bool Node-map, 
marci@597
   123
  /// Pred is a write Edge Node-map and
marci@597
   124
  /// Dist is a read-write int Node-map, have to be. 
marci@597
   125
  ///\todo In fact onsly simple operations requirement are needed for 
marci@597
   126
  /// Dist::Value.
marci@409
   127
  template <typename Graph, 
marci@409
   128
	    typename ReachedMap=typename Graph::template NodeMap<bool>, 
marci@409
   129
	    typename PredMap
marci@409
   130
	    =typename Graph::template NodeMap<typename Graph::Edge>, 
marci@409
   131
	    typename DistMap=typename Graph::template NodeMap<int> > 
marci@409
   132
  class Bfs : public BfsIterator<Graph, ReachedMap> {
marci@409
   133
    typedef BfsIterator<Graph, ReachedMap> Parent;
marci@409
   134
  protected:
marci@409
   135
    typedef typename Parent::Node Node;
marci@409
   136
    PredMap& pred;
marci@409
   137
    DistMap& dist;
marci@409
   138
  public:
marci@597
   139
    /// The algorithm will search in a bfs order for 
marci@597
   140
    /// the nodes which are \c false initially. 
marci@597
   141
    /// The constructor makes no initial changes on the maps.
marci@409
   142
    Bfs<Graph, ReachedMap, PredMap, DistMap>(const Graph& _graph, ReachedMap& _reached, PredMap& _pred, DistMap& _dist) : BfsIterator<Graph, ReachedMap>(_graph, _reached), pred(&_pred), dist(&_dist) { }
marci@597
   143
    /// \c s is marked to be reached and pushed in the bfs queue.
marci@448
   144
    /// If the queue is empty, then the first out-edge is processed.
marci@597
   145
    /// If \c s was not marked previously, then 
marci@597
   146
    /// in addition its pred is set to be \c INVALID, and dist to \c 0. 
marci@597
   147
    /// if \c s was marked previuosly, then it is simply pushed.
marci@409
   148
    void push(Node s) { 
marci@409
   149
      if (this->reached[s]) {
marci@409
   150
	Parent::pushAndSetReached(s);
marci@409
   151
      } else {
marci@409
   152
	Parent::pushAndSetReached(s);
marci@409
   153
	pred.set(s, INVALID);
marci@409
   154
	dist.set(s, 0);
marci@409
   155
      }
marci@409
   156
    }
marci@597
   157
    /// A bfs is processed from \c s.
marci@409
   158
    void run(Node s) {
marci@409
   159
      push(s);
marci@409
   160
      while (!this->finished()) this->operator++();
marci@409
   161
    }
marci@597
   162
    /// Beside the bfs iteration, \c pred and \dist are saved in a 
marci@597
   163
    /// newly reached node. 
marci@409
   164
    Bfs<Graph, ReachedMap, PredMap, DistMap> operator++() {
marci@409
   165
      Parent::operator++();
marci@415
   166
      if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) 
marci@415
   167
      {
marci@415
   168
	pred.set(this->bNode(), this->actual_edge);
marci@415
   169
	dist.set(this->bNode(), dist[this->aNode()]);
marci@409
   170
      }
marci@409
   171
      return *this;
marci@409
   172
    }
marci@597
   173
    ///
marci@409
   174
    const PredMap& getPredMap() const { return pred; }
marci@597
   175
    ///
marci@409
   176
    const DistMap& getDistMap() const { return dist; }
marci@409
   177
  };
marci@409
   178
marci@597
   179
  /// Dfs searches for the nodes wich are not marked in 
marci@597
   180
  /// \c reached_map
marci@597
   181
  /// Reached have to be a read-write bool Node-map.
marci@303
   182
  template <typename Graph, /*typename OutEdgeIt,*/ 
marci@303
   183
	    typename ReachedMap/*=typename Graph::NodeMap<bool>*/ >
marci@360
   184
  class DfsIterator {
marci@303
   185
  protected:
marci@303
   186
    typedef typename Graph::Node Node;
marci@303
   187
    typedef typename Graph::OutEdgeIt OutEdgeIt;
marci@303
   188
    const Graph* graph;
marci@301
   189
    std::stack<OutEdgeIt> dfs_stack;
marci@301
   190
    bool b_node_newly_reached;
marci@301
   191
    OutEdgeIt actual_edge;
marci@301
   192
    Node actual_node;
marci@301
   193
    ReachedMap& reached;
marci@301
   194
    bool own_reached_map;
marci@301
   195
  public:
marci@597
   196
    /// In that constructor \c _reached have to be a reference 
marci@597
   197
    /// for a bool Node-map. The algorithm will search in a dfs order for 
marci@597
   198
    /// the nodes which are \c false initially
marci@360
   199
    DfsIterator(const Graph& _graph, ReachedMap& _reached) : 
marci@303
   200
      graph(&_graph), reached(_reached), 
marci@301
   201
      own_reached_map(false) { }
marci@597
   202
    /// The same as above, but the map of reached nodes is 
marci@597
   203
    /// constructed dynamically 
marci@597
   204
    /// to everywhere false.
marci@360
   205
    DfsIterator(const Graph& _graph) : 
marci@303
   206
      graph(&_graph), reached(*(new ReachedMap(*graph /*, false*/))), 
marci@301
   207
      own_reached_map(true) { }
marci@360
   208
    ~DfsIterator() { if (own_reached_map) delete &reached; }
marci@597
   209
    /// This method markes s reached and first out-edge is processed.
marci@301
   210
    void pushAndSetReached(Node s) { 
marci@301
   211
      actual_node=s;
marci@301
   212
      reached.set(s, true);
marci@301
   213
      OutEdgeIt e;
marci@303
   214
      graph->first(e, s);
marci@301
   215
      dfs_stack.push(e); 
marci@301
   216
    }
marci@597
   217
    /// As \c DfsIterator<Graph, ReachedMap> works as an edge-iterator, 
marci@597
   218
    /// its \c operator++() iterates on the edges in a dfs order.
marci@360
   219
    DfsIterator<Graph, /*OutEdgeIt,*/ ReachedMap>& 
marci@301
   220
    operator++() { 
marci@301
   221
      actual_edge=dfs_stack.top();
marci@301
   222
      //actual_node=G.aNode(actual_edge);
marci@303
   223
      if (graph->valid(actual_edge)/*.valid()*/) { 
marci@303
   224
	Node w=graph->bNode(actual_edge);
marci@301
   225
	actual_node=w;
marci@303
   226
	if (!reached[w]) {
marci@301
   227
	  OutEdgeIt e;
marci@303
   228
	  graph->first(e, w);
marci@301
   229
	  dfs_stack.push(e);
marci@301
   230
	  reached.set(w, true);
marci@301
   231
	  b_node_newly_reached=true;
marci@301
   232
	} else {
marci@303
   233
	  actual_node=graph->aNode(actual_edge);
marci@303
   234
	  graph->next(dfs_stack.top());
marci@301
   235
	  b_node_newly_reached=false;
marci@301
   236
	}
marci@301
   237
      } else {
marci@301
   238
	//actual_node=G.aNode(dfs_stack.top());
marci@301
   239
	dfs_stack.pop();
marci@301
   240
      }
marci@301
   241
      return *this;
marci@301
   242
    }
marci@597
   243
    ///
marci@301
   244
    bool finished() const { return dfs_stack.empty(); }
marci@597
   245
    ///
marci@409
   246
    operator OutEdgeIt() const { return actual_edge; }
marci@597
   247
    ///
marci@301
   248
    bool isBNodeNewlyReached() const { return b_node_newly_reached; }
marci@597
   249
    ///
marci@303
   250
    bool isANodeExamined() const { return !(graph->valid(actual_edge)); }
marci@597
   251
    ///
marci@301
   252
    Node aNode() const { return actual_node; /*FIXME*/}
marci@597
   253
    ///
marci@389
   254
    Node bNode() const { return graph->bNode(actual_edge); }
marci@597
   255
    ///
marci@301
   256
    const ReachedMap& getReachedMap() const { return reached; }
marci@597
   257
    ///
marci@301
   258
    const std::stack<OutEdgeIt>& getDfsStack() const { return dfs_stack; }
marci@301
   259
  };
marci@301
   260
marci@597
   261
  /// Dfs searches for the nodes wich are not marked in 
marci@448
   262
  /// \c reached_map
marci@597
   263
  /// Reached is a read-write bool Node-map, 
marci@597
   264
  /// Pred is a write Node-map, have to be.
marci@448
   265
  template <typename Graph, 
marci@448
   266
	    typename ReachedMap=typename Graph::template NodeMap<bool>, 
marci@448
   267
	    typename PredMap
marci@448
   268
	    =typename Graph::template NodeMap<typename Graph::Edge> > 
marci@448
   269
  class Dfs : public DfsIterator<Graph, ReachedMap> {
marci@448
   270
    typedef DfsIterator<Graph, ReachedMap> Parent;
marci@448
   271
  protected:
marci@448
   272
    typedef typename Parent::Node Node;
marci@448
   273
    PredMap& pred;
marci@448
   274
  public:
marci@597
   275
    /// The algorithm will search in a dfs order for 
marci@597
   276
    /// the nodes which are \c false initially. 
marci@597
   277
    /// The constructor makes no initial changes on the maps.
marci@448
   278
    Dfs<Graph, ReachedMap, PredMap>(const Graph& _graph, ReachedMap& _reached, PredMap& _pred) : DfsIterator<Graph, ReachedMap>(_graph, _reached), pred(&_pred) { }
marci@597
   279
    /// \c s is marked to be reached and pushed in the bfs queue.
marci@448
   280
    /// If the queue is empty, then the first out-edge is processed.
marci@597
   281
    /// If \c s was not marked previously, then 
marci@597
   282
    /// in addition its pred is set to be \c INVALID. 
marci@597
   283
    /// if \c s was marked previuosly, then it is simply pushed.
marci@448
   284
    void push(Node s) { 
marci@448
   285
      if (this->reached[s]) {
marci@448
   286
	Parent::pushAndSetReached(s);
marci@448
   287
      } else {
marci@448
   288
	Parent::pushAndSetReached(s);
marci@448
   289
	pred.set(s, INVALID);
marci@448
   290
      }
marci@448
   291
    }
marci@597
   292
    /// A bfs is processed from \c s.
marci@448
   293
    void run(Node s) {
marci@448
   294
      push(s);
marci@448
   295
      while (!this->finished()) this->operator++();
marci@448
   296
    }
marci@597
   297
    /// Beside the dfs iteration, \c pred is saved in a 
marci@597
   298
    /// newly reached node. 
marci@448
   299
    Dfs<Graph, ReachedMap, PredMap> operator++() {
marci@448
   300
      Parent::operator++();
marci@448
   301
      if (this->graph->valid(this->actual_edge) && this->b_node_newly_reached) 
marci@448
   302
      {
marci@448
   303
	pred.set(this->bNode(), this->actual_edge);
marci@448
   304
      }
marci@448
   305
      return *this;
marci@448
   306
    }
marci@597
   307
    ///
marci@448
   308
    const PredMap& getPredMap() const { return pred; }
marci@448
   309
  };
marci@448
   310
marci@448
   311
marci@301
   312
} // namespace hugo
marci@301
   313
marci@301
   314
#endif //HUGO_BFS_ITERATOR_H