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