1 #ifndef DEPTHFIRSTSEARCH_H
2 #define DEPTHFIRSTSEARCH_H 1
3
4 #include "Graph/DefaultColorMap.h"
5 #include <vector>
6 #include <boost/graph/breadth_first_search.hpp>
7
8 using boost::function_requires;
9 using boost::graph_traits;
10 using boost::property_traits;
11 using boost::color_traits;
12
13 /** return code from BFS visitor callbacks */
14 enum BFSVisitorResult { BFS_SUCCESS = 0, BFS_SKIP_ELEMENT, BFS_ABORT_SEARCH };
15
16 /**
17 * Default BFS visitor that does nothing. Used as a placeholder when
18 * no special visitor behaviour is needed.
19 */
20 template <class G>
21 class DefaultBFSVisitor
22 {
23 public:
24
25 typedef typename boost::graph_traits<G>::vertex_descriptor V;
26 typedef typename boost::graph_traits<G>::edge_descriptor E;
27
discover_vertex(const V &,const G &)28 BFSVisitorResult discover_vertex(const V&, const G&) { return BFS_SUCCESS; }
examine_vertex(const V &,const G &)29 BFSVisitorResult examine_vertex(const V&, const G&) { return BFS_SUCCESS; }
finish_vertex(const V &,const G &)30 BFSVisitorResult finish_vertex(const V&, const G&) { return BFS_SUCCESS; }
examine_edge(const E &,const G &)31 BFSVisitorResult examine_edge(const E&, const G&) { return BFS_SUCCESS; }
tree_edge(const E &,const G &)32 BFSVisitorResult tree_edge(const E&, const G&) { return BFS_SUCCESS; }
non_tree_edge(const E &,const G &)33 BFSVisitorResult non_tree_edge(const E&, const G&) { return BFS_SUCCESS; }
gray_target(const E &,const G &)34 BFSVisitorResult gray_target(const E&, const G&) { return BFS_SUCCESS; }
black_target(const E &,const G &)35 BFSVisitorResult black_target(const E&, const G&) { return BFS_SUCCESS; }
post_processing()36 void post_processing() {}
37 };
38
39 template <class Graph, class Queue, class ColorMap, class Visitor>
bfsVisitEdge(const typename boost::graph_traits<Graph>::edge_descriptor & e,bool isOutEdge,const Graph & g,Queue & queue,ColorMap & colorMap,Visitor & visitor)40 static inline BFSVisitorResult bfsVisitEdge(
41 const typename boost::graph_traits<Graph>::edge_descriptor& e,
42 bool isOutEdge, const Graph& g, Queue& queue, ColorMap& colorMap,
43 Visitor& visitor)
44 {
45 typedef typename boost::graph_traits<Graph>::vertex_descriptor V;
46
47 typedef typename property_traits<ColorMap>::value_type ColorValue;
48 typedef color_traits<ColorValue> Color;
49
50 BFSVisitorResult result = BFS_SUCCESS;
51
52 /* note: boost edges always go from source to target */
53 const V& v = isOutEdge ? target(e, g) : source(e, g);
54
55 result = visitor.examine_edge(e, g);
56 if (result != BFS_SUCCESS)
57 return result;
58
59 ColorValue color = get(colorMap, v);
60 if (color == Color::white()) {
61
62 result = visitor.tree_edge(e, g);
63 if (result != BFS_SUCCESS)
64 return result;
65
66 result = visitor.discover_vertex(v, g);
67 if (result != BFS_SUCCESS)
68 return result;
69
70 put(colorMap, v, Color::gray());
71 queue.push(v);
72
73 } else {
74
75 result = visitor.non_tree_edge(e, g);
76 if (result != BFS_SUCCESS)
77 return result;
78
79 if (color == Color::gray()) {
80 result = visitor.gray_target(e, g);
81 } else {
82 result = visitor.black_target(e, g);
83 }
84
85 }
86
87 return result;
88 }
89
90 /**
91 * An implementation of BFS that allows multiple start nodes and permits
92 * terminating the search early. Visitors can terminate the search by
93 * returning the BFS_ABORT_SEARCH result code from their callback routines.
94 */
95 template <class Graph, class VertexSet, class ColorMap, class Visitor>
breadthFirstSearchImpl(const VertexSet & startVertices,const Graph & g,bool undirected,ColorMap & colorMap,Visitor & visitor)96 static inline void breadthFirstSearchImpl(
97 const VertexSet& startVertices, const Graph& g, bool undirected,
98 ColorMap& colorMap, Visitor& visitor)
99 {
100 typedef typename boost::graph_traits<Graph>::vertex_descriptor V;
101 typedef typename boost::graph_traits<Graph>::edge_descriptor E;
102 typedef typename boost::graph_traits<Graph>::in_edge_iterator IEIt;
103 typedef typename boost::graph_traits<Graph>::out_edge_iterator OEIt;
104
105 typedef typename VertexSet::const_iterator VertexListConstIt;
106
107 typedef typename property_traits<ColorMap>::value_type ColorValue;
108 typedef color_traits<ColorValue> Color;
109
110 /* breadth-first search queue */
111 boost::queue<V> queue;
112
113 BFSVisitorResult result;
114 IEIt iei, iei_end;
115 OEIt oei, oei_end;
116
117 /* push start vertices onto search queue */
118
119 for (VertexListConstIt it = startVertices.begin(); it != startVertices.end(); ++it) {
120 ColorValue color = get(colorMap, *it);
121 if (color == Color::white()) {
122 result = visitor.discover_vertex(*it, g);
123 if (result == BFS_SKIP_ELEMENT)
124 continue;
125 else if (result == BFS_ABORT_SEARCH)
126 return;
127 put(colorMap, *it, Color::gray());
128 }
129 /*
130 * note: vertex may already be black if user is reusing colorMap across
131 * multiple searches
132 */
133 if (color != Color::black()) {
134 queue.push(*it);
135 }
136 }
137
138 /* do breadth first search */
139
140 while (!queue.empty()) {
141
142 V u = queue.top();
143 queue.pop();
144 result = visitor.examine_vertex(u, g);
145 if (result == BFS_SKIP_ELEMENT)
146 continue;
147 else if (result == BFS_ABORT_SEARCH)
148 return;
149
150 for (boost::tie(oei, oei_end) = out_edges(u, g); oei != oei_end; ++oei) {
151 const E& e = *oei;
152 result = bfsVisitEdge(e, true, g, queue, colorMap, visitor);
153 if (result == BFS_ABORT_SEARCH)
154 return;
155 }
156
157 if (undirected) {
158 for (boost::tie(iei, iei_end) = in_edges(u, g); iei != iei_end; ++iei) {
159 const E& e = *iei;
160 result = bfsVisitEdge(e, false, g, queue, colorMap, visitor);
161 if (result == BFS_ABORT_SEARCH)
162 return;
163 }
164 }
165
166 put(colorMap, u, Color::black());
167 result = visitor.finish_vertex(u, g);
168 if (result == BFS_ABORT_SEARCH)
169 return;
170 }
171
172 visitor.post_processing();
173 }
174
175 template <class Graph>
breadthFirstSearch(const Graph & g,bool undirected,const typename graph_traits<Graph>::vertex_descriptor & root)176 void breadthFirstSearch(const Graph& g, bool undirected,
177 const typename graph_traits<Graph>::vertex_descriptor& root)
178 {
179 typedef typename graph_traits<Graph>::vertex_descriptor V;
180 std::vector<V> startVertices(1, root);
181 DefaultColorMap<Graph> colorMap;
182 DefaultBFSVisitor<Graph> visitor;
183 breadthFirstSearchImpl(startVertices, g, undirected, colorMap, visitor);
184 }
185
186 template <class Graph>
breadthFirstSearch(const Graph & g,const typename graph_traits<Graph>::vertex_descriptor & root)187 void breadthFirstSearch(const Graph& g,
188 const typename graph_traits<Graph>::vertex_descriptor& root)
189 {
190 breadthFirstSearch(g, false, root);
191 }
192
193 template <class Graph, class Visitor>
breadthFirstSearch(const typename boost::graph_traits<Graph>::vertex_descriptor & root,const Graph & g,bool undirected,Visitor & visitor)194 void breadthFirstSearch(
195 const typename boost::graph_traits<Graph>::vertex_descriptor& root,
196 const Graph& g, bool undirected, Visitor& visitor)
197 {
198 typedef typename graph_traits<Graph>::vertex_descriptor V;
199 std::vector<V> startVertices(1, root);
200 DefaultColorMap<Graph> colorMap;
201 breadthFirstSearchImpl(startVertices, g, undirected, colorMap, visitor);
202 }
203
204 template <class Graph, class Visitor>
breadthFirstSearch(const typename boost::graph_traits<Graph>::vertex_descriptor & root,const Graph & g,Visitor & visitor)205 void breadthFirstSearch(
206 const typename boost::graph_traits<Graph>::vertex_descriptor& root,
207 const Graph& g, Visitor& visitor)
208 {
209 breadthFirstSearch(root, g, false, visitor);
210 }
211
212 template <class Graph, class ColorMap, class Visitor>
breadthFirstSearch(const typename boost::graph_traits<Graph>::vertex_descriptor & root,const Graph & g,ColorMap & colorMap,Visitor & visitor)213 void breadthFirstSearch(
214 const typename boost::graph_traits<Graph>::vertex_descriptor& root,
215 const Graph& g, ColorMap& colorMap, Visitor& visitor)
216 {
217 typedef typename graph_traits<Graph>::vertex_descriptor V;
218 std::vector<V> startVertices(1, root);
219 breadthFirstSearchImpl(startVertices, g, false, colorMap, visitor);
220 }
221
222 template <class Graph, class VertexSet, class Visitor>
breadthFirstSearchMulti(const VertexSet & startVertices,const Graph & g,Visitor & visitor)223 void breadthFirstSearchMulti(
224 const VertexSet& startVertices,
225 const Graph& g, Visitor& visitor)
226 {
227 DefaultColorMap<Graph> colorMap;
228 breadthFirstSearchImpl(startVertices, g, false, colorMap, visitor);
229 }
230
231 template <class Graph, class VertexSet, class Visitor>
breadthFirstSearchMulti(const VertexSet & startVertices,const Graph & g,bool undirected,Visitor & visitor)232 void breadthFirstSearchMulti(
233 const VertexSet& startVertices,
234 const Graph& g, bool undirected, Visitor& visitor)
235 {
236 DefaultColorMap<Graph> colorMap;
237 breadthFirstSearchImpl(startVertices, g, undirected, colorMap, visitor);
238 }
239
240 template <class IncidenceGraph, class BFSVisitor, class ColorMap>
breadthFirstSearch(const IncidenceGraph & g,typename graph_traits<IncidenceGraph>::vertex_descriptor root,BFSVisitor & visitor)241 void breadthFirstSearch(const IncidenceGraph& g,
242 typename graph_traits<IncidenceGraph>::vertex_descriptor root,
243 BFSVisitor& visitor)
244 {
245 typedef typename graph_traits<IncidenceGraph>::vertex_descriptor V;
246 DefaultColorMap<IncidenceGraph> colorMap;
247 boost::queue<V> q;
248 breadthFirstSearch(g, root, q, visitor, colorMap);
249 }
250
251 #endif
252