1 //
2 //=======================================================================
3 // Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
4 // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 //=======================================================================
10 //
11 #ifndef BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP
12 #define BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP
13 
14 /*
15   Breadth First Search Algorithm (Cormen, Leiserson, and Rivest p. 470)
16 */
17 #include <boost/config.hpp>
18 #include <vector>
19 #include <boost/pending/queue.hpp>
20 #include <boost/graph/graph_traits.hpp>
21 #include <boost/graph/graph_concepts.hpp>
22 #include <boost/graph/visitors.hpp>
23 #include <boost/graph/named_function_params.hpp>
24 #include <boost/graph/overloading.hpp>
25 #include <boost/graph/graph_concepts.hpp>
26 #include <boost/graph/two_bit_color_map.hpp>
27 #include <boost/graph/detail/mpi_include.hpp>
28 #include <boost/concept/assert.hpp>
29 
30 #include BOOST_GRAPH_MPI_INCLUDE(<boost/graph/distributed/concepts.hpp>)
31 
32 namespace boost {
33 
34   template <class Visitor, class Graph>
35   struct BFSVisitorConcept {
constraintsboost::BFSVisitorConcept36     void constraints() {
37       BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
38       vis.initialize_vertex(u, g);
39       vis.discover_vertex(u, g);
40       vis.examine_vertex(u, g);
41       vis.examine_edge(e, g);
42       vis.tree_edge(e, g);
43       vis.non_tree_edge(e, g);
44       vis.gray_target(e, g);
45       vis.black_target(e, g);
46       vis.finish_vertex(u, g);
47     }
48     Visitor vis;
49     Graph g;
50     typename graph_traits<Graph>::vertex_descriptor u;
51     typename graph_traits<Graph>::edge_descriptor e;
52   };
53 
54 
55   // Multiple-source version
56   template <class IncidenceGraph, class Buffer, class BFSVisitor,
57             class ColorMap, class SourceIterator>
breadth_first_visit(const IncidenceGraph & g,SourceIterator sources_begin,SourceIterator sources_end,Buffer & Q,BFSVisitor vis,ColorMap color)58   void breadth_first_visit
59     (const IncidenceGraph& g,
60      SourceIterator sources_begin, SourceIterator sources_end,
61      Buffer& Q, BFSVisitor vis, ColorMap color)
62   {
63     BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<IncidenceGraph> ));
64     typedef graph_traits<IncidenceGraph> GTraits;
65     typedef typename GTraits::vertex_descriptor Vertex;
66     BOOST_CONCEPT_ASSERT(( BFSVisitorConcept<BFSVisitor, IncidenceGraph> ));
67     BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, Vertex> ));
68     typedef typename property_traits<ColorMap>::value_type ColorValue;
69     typedef color_traits<ColorValue> Color;
70     typename GTraits::out_edge_iterator ei, ei_end;
71 
72     for (; sources_begin != sources_end; ++sources_begin) {
73       Vertex s = *sources_begin;
74       put(color, s, Color::gray());           vis.discover_vertex(s, g);
75       Q.push(s);
76     }
77     while (! Q.empty()) {
78       Vertex u = Q.top(); Q.pop();            vis.examine_vertex(u, g);
79       for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
80         Vertex v = target(*ei, g);            vis.examine_edge(*ei, g);
81         ColorValue v_color = get(color, v);
82         if (v_color == Color::white()) {      vis.tree_edge(*ei, g);
83           put(color, v, Color::gray());       vis.discover_vertex(v, g);
84           Q.push(v);
85         } else {                              vis.non_tree_edge(*ei, g);
86           if (v_color == Color::gray())       vis.gray_target(*ei, g);
87           else                                vis.black_target(*ei, g);
88         }
89       } // end for
90       put(color, u, Color::black());          vis.finish_vertex(u, g);
91     } // end while
92   } // breadth_first_visit
93 
94   // Single-source version
95   template <class IncidenceGraph, class Buffer, class BFSVisitor,
96             class ColorMap>
breadth_first_visit(const IncidenceGraph & g,typename graph_traits<IncidenceGraph>::vertex_descriptor s,Buffer & Q,BFSVisitor vis,ColorMap color)97   void breadth_first_visit
98     (const IncidenceGraph& g,
99      typename graph_traits<IncidenceGraph>::vertex_descriptor s,
100      Buffer& Q, BFSVisitor vis, ColorMap color)
101   {
102     typename graph_traits<IncidenceGraph>::vertex_descriptor sources[1] = {s};
103     breadth_first_visit(g, sources, sources + 1, Q, vis, color);
104   }
105 
106 
107   template <class VertexListGraph, class SourceIterator,
108             class Buffer, class BFSVisitor,
109             class ColorMap>
breadth_first_search(const VertexListGraph & g,SourceIterator sources_begin,SourceIterator sources_end,Buffer & Q,BFSVisitor vis,ColorMap color)110   void breadth_first_search
111     (const VertexListGraph& g,
112      SourceIterator sources_begin, SourceIterator sources_end,
113      Buffer& Q, BFSVisitor vis, ColorMap color)
114   {
115     // Initialization
116     typedef typename property_traits<ColorMap>::value_type ColorValue;
117     typedef color_traits<ColorValue> Color;
118     typename boost::graph_traits<VertexListGraph>::vertex_iterator i, i_end;
119     for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i) {
120       vis.initialize_vertex(*i, g);
121       put(color, *i, Color::white());
122     }
123     breadth_first_visit(g, sources_begin, sources_end, Q, vis, color);
124   }
125 
126   template <class VertexListGraph, class Buffer, class BFSVisitor,
127             class ColorMap>
breadth_first_search(const VertexListGraph & g,typename graph_traits<VertexListGraph>::vertex_descriptor s,Buffer & Q,BFSVisitor vis,ColorMap color)128   void breadth_first_search
129     (const VertexListGraph& g,
130      typename graph_traits<VertexListGraph>::vertex_descriptor s,
131      Buffer& Q, BFSVisitor vis, ColorMap color)
132   {
133     typename graph_traits<VertexListGraph>::vertex_descriptor sources[1] = {s};
134     breadth_first_search(g, sources, sources + 1, Q, vis, color);
135   }
136 
137   namespace graph { struct bfs_visitor_event_not_overridden {}; }
138 
139 
140   template <class Visitors = null_visitor>
141   class bfs_visitor {
142   public:
bfs_visitor()143     bfs_visitor() { }
bfs_visitor(Visitors vis)144     bfs_visitor(Visitors vis) : m_vis(vis) { }
145 
146     template <class Vertex, class Graph>
147     graph::bfs_visitor_event_not_overridden
initialize_vertex(Vertex u,Graph & g)148     initialize_vertex(Vertex u, Graph& g)
149     {
150       invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
151       return graph::bfs_visitor_event_not_overridden();
152     }
153 
154     template <class Vertex, class Graph>
155     graph::bfs_visitor_event_not_overridden
discover_vertex(Vertex u,Graph & g)156     discover_vertex(Vertex u, Graph& g)
157     {
158       invoke_visitors(m_vis, u, g, ::boost::on_discover_vertex());
159       return graph::bfs_visitor_event_not_overridden();
160     }
161 
162     template <class Vertex, class Graph>
163     graph::bfs_visitor_event_not_overridden
examine_vertex(Vertex u,Graph & g)164     examine_vertex(Vertex u, Graph& g)
165     {
166       invoke_visitors(m_vis, u, g, ::boost::on_examine_vertex());
167       return graph::bfs_visitor_event_not_overridden();
168     }
169 
170     template <class Edge, class Graph>
171     graph::bfs_visitor_event_not_overridden
examine_edge(Edge e,Graph & g)172     examine_edge(Edge e, Graph& g)
173     {
174       invoke_visitors(m_vis, e, g, ::boost::on_examine_edge());
175       return graph::bfs_visitor_event_not_overridden();
176     }
177 
178     template <class Edge, class Graph>
179     graph::bfs_visitor_event_not_overridden
tree_edge(Edge e,Graph & g)180     tree_edge(Edge e, Graph& g)
181     {
182       invoke_visitors(m_vis, e, g, ::boost::on_tree_edge());
183       return graph::bfs_visitor_event_not_overridden();
184     }
185 
186     template <class Edge, class Graph>
187     graph::bfs_visitor_event_not_overridden
non_tree_edge(Edge e,Graph & g)188     non_tree_edge(Edge e, Graph& g)
189     {
190       invoke_visitors(m_vis, e, g, ::boost::on_non_tree_edge());
191       return graph::bfs_visitor_event_not_overridden();
192     }
193 
194     template <class Edge, class Graph>
195     graph::bfs_visitor_event_not_overridden
gray_target(Edge e,Graph & g)196     gray_target(Edge e, Graph& g)
197     {
198       invoke_visitors(m_vis, e, g, ::boost::on_gray_target());
199       return graph::bfs_visitor_event_not_overridden();
200     }
201 
202     template <class Edge, class Graph>
203     graph::bfs_visitor_event_not_overridden
black_target(Edge e,Graph & g)204     black_target(Edge e, Graph& g)
205     {
206       invoke_visitors(m_vis, e, g, ::boost::on_black_target());
207       return graph::bfs_visitor_event_not_overridden();
208     }
209 
210     template <class Vertex, class Graph>
211     graph::bfs_visitor_event_not_overridden
finish_vertex(Vertex u,Graph & g)212     finish_vertex(Vertex u, Graph& g)
213     {
214       invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
215       return graph::bfs_visitor_event_not_overridden();
216     }
217 
218     BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,bfs)
219     BOOST_GRAPH_EVENT_STUB(on_discover_vertex,bfs)
220     BOOST_GRAPH_EVENT_STUB(on_examine_vertex,bfs)
221     BOOST_GRAPH_EVENT_STUB(on_examine_edge,bfs)
222     BOOST_GRAPH_EVENT_STUB(on_tree_edge,bfs)
223     BOOST_GRAPH_EVENT_STUB(on_non_tree_edge,bfs)
224     BOOST_GRAPH_EVENT_STUB(on_gray_target,bfs)
225     BOOST_GRAPH_EVENT_STUB(on_black_target,bfs)
226     BOOST_GRAPH_EVENT_STUB(on_finish_vertex,bfs)
227 
228   protected:
229     Visitors m_vis;
230   };
231   template <class Visitors>
232   bfs_visitor<Visitors>
make_bfs_visitor(Visitors vis)233   make_bfs_visitor(Visitors vis) {
234     return bfs_visitor<Visitors>(vis);
235   }
236   typedef bfs_visitor<> default_bfs_visitor;
237 
238 
239   namespace detail {
240 
241     template <class VertexListGraph, class ColorMap, class BFSVisitor,
242       class P, class T, class R>
bfs_helper(VertexListGraph & g,typename graph_traits<VertexListGraph>::vertex_descriptor s,ColorMap color,BFSVisitor vis,const bgl_named_params<P,T,R> & params,boost::mpl::false_)243     void bfs_helper
244       (VertexListGraph& g,
245        typename graph_traits<VertexListGraph>::vertex_descriptor s,
246        ColorMap color,
247        BFSVisitor vis,
248        const bgl_named_params<P, T, R>& params,
249        boost::mpl::false_)
250     {
251       typedef graph_traits<VertexListGraph> Traits;
252       // Buffer default
253       typedef typename Traits::vertex_descriptor Vertex;
254       typedef boost::queue<Vertex> queue_t;
255       queue_t Q;
256       breadth_first_search
257         (g, s,
258          choose_param(get_param(params, buffer_param_t()), boost::ref(Q)).get(),
259          vis, color);
260     }
261 
262 #ifdef BOOST_GRAPH_USE_MPI
263     template <class DistributedGraph, class ColorMap, class BFSVisitor,
264               class P, class T, class R>
265     void bfs_helper
266       (DistributedGraph& g,
267        typename graph_traits<DistributedGraph>::vertex_descriptor s,
268        ColorMap color,
269        BFSVisitor vis,
270        const bgl_named_params<P, T, R>& params,
271        boost::mpl::true_);
272 #endif // BOOST_GRAPH_USE_MPI
273 
274     //-------------------------------------------------------------------------
275     // Choose between default color and color parameters. Using
276     // function dispatching so that we don't require vertex index if
277     // the color default is not being used.
278 
279     template <class ColorMap>
280     struct bfs_dispatch {
281       template <class VertexListGraph, class P, class T, class R>
applyboost::detail::bfs_dispatch282       static void apply
283       (VertexListGraph& g,
284        typename graph_traits<VertexListGraph>::vertex_descriptor s,
285        const bgl_named_params<P, T, R>& params,
286        ColorMap color)
287       {
288         bfs_helper
289           (g, s, color,
290            choose_param(get_param(params, graph_visitor),
291                         make_bfs_visitor(null_visitor())),
292            params,
293            boost::mpl::bool_<
294              boost::is_base_and_derived<
295                distributed_graph_tag,
296                typename graph_traits<VertexListGraph>::traversal_category>::value>());
297       }
298     };
299 
300     template <>
301     struct bfs_dispatch<param_not_found> {
302       template <class VertexListGraph, class P, class T, class R>
applyboost::detail::bfs_dispatch303       static void apply
304       (VertexListGraph& g,
305        typename graph_traits<VertexListGraph>::vertex_descriptor s,
306        const bgl_named_params<P, T, R>& params,
307        param_not_found)
308       {
309         null_visitor null_vis;
310 
311         bfs_helper
312           (g, s,
313            make_two_bit_color_map
314            (num_vertices(g),
315             choose_const_pmap(get_param(params, vertex_index),
316                               g, vertex_index)),
317            choose_param(get_param(params, graph_visitor),
318                         make_bfs_visitor(null_vis)),
319            params,
320            boost::mpl::bool_<
321              boost::is_base_and_derived<
322                distributed_graph_tag,
323                typename graph_traits<VertexListGraph>::traversal_category>::value>());
324       }
325     };
326 
327   } // namespace detail
328 
329 #if 1
330   // Named Parameter Variant
331   template <class VertexListGraph, class P, class T, class R>
breadth_first_search(const VertexListGraph & g,typename graph_traits<VertexListGraph>::vertex_descriptor s,const bgl_named_params<P,T,R> & params)332   void breadth_first_search
333     (const VertexListGraph& g,
334      typename graph_traits<VertexListGraph>::vertex_descriptor s,
335      const bgl_named_params<P, T, R>& params)
336   {
337     // The graph is passed by *const* reference so that graph adaptors
338     // (temporaries) can be passed into this function. However, the
339     // graph is not really const since we may write to property maps
340     // of the graph.
341     VertexListGraph& ng = const_cast<VertexListGraph&>(g);
342     typedef typename get_param_type< vertex_color_t, bgl_named_params<P,T,R> >::type C;
343     detail::bfs_dispatch<C>::apply(ng, s, params,
344                                    get_param(params, vertex_color));
345   }
346 #endif
347 
348 
349   // This version does not initialize colors, user has to.
350 
351   template <class IncidenceGraph, class P, class T, class R>
breadth_first_visit(const IncidenceGraph & g,typename graph_traits<IncidenceGraph>::vertex_descriptor s,const bgl_named_params<P,T,R> & params)352   void breadth_first_visit
353     (const IncidenceGraph& g,
354      typename graph_traits<IncidenceGraph>::vertex_descriptor s,
355      const bgl_named_params<P, T, R>& params)
356   {
357     // The graph is passed by *const* reference so that graph adaptors
358     // (temporaries) can be passed into this function. However, the
359     // graph is not really const since we may write to property maps
360     // of the graph.
361     IncidenceGraph& ng = const_cast<IncidenceGraph&>(g);
362 
363     typedef graph_traits<IncidenceGraph> Traits;
364     // Buffer default
365     typedef typename Traits::vertex_descriptor vertex_descriptor;
366     typedef boost::queue<vertex_descriptor> queue_t;
367     queue_t Q;
368 
369     breadth_first_visit
370       (ng, s,
371        choose_param(get_param(params, buffer_param_t()), boost::ref(Q)).get(),
372        choose_param(get_param(params, graph_visitor),
373                     make_bfs_visitor(null_visitor())),
374        choose_pmap(get_param(params, vertex_color), ng, vertex_color)
375        );
376   }
377 
378   namespace graph {
379     namespace detail {
380       template <typename Graph, typename Source>
381       struct breadth_first_search_impl {
382         typedef void result_type;
383         template <typename ArgPack>
operator ()boost::graph::detail::breadth_first_search_impl384         void operator()(const Graph& g, const Source& source, const ArgPack& arg_pack) {
385           using namespace boost::graph::keywords;
386           typename boost::graph_traits<Graph>::vertex_descriptor sources[1] = {source};
387           boost::queue<typename boost::graph_traits<Graph>::vertex_descriptor> Q;
388           boost::breadth_first_search(g,
389                                       &sources[0],
390                                       &sources[1],
391                                       boost::unwrap_ref(arg_pack[_buffer | boost::ref(Q)]),
392                                       arg_pack[_visitor | make_bfs_visitor(null_visitor())],
393                                       boost::detail::make_color_map_from_arg_pack(g, arg_pack));
394         }
395       };
396     }
397     BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(breadth_first_search, 2, 4)
398   }
399 
400 #if 0
401   // Named Parameter Variant
402   BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(breadth_first_search, 2)
403 #endif
404 
405 } // namespace boost
406 
407 #include BOOST_GRAPH_MPI_INCLUDE(<boost/graph/distributed/breadth_first_search.hpp>)
408 
409 #endif // BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP
410 
411