bfs.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. //=======================================================================
  2. // Copyright 2001 University of Notre Dame.
  3. // Author: Andrew Janiszewski, Jeremy G. Siek
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //=======================================================================
  9. #include <boost/test/minimal.hpp>
  10. #include <boost/graph/adjacency_list.hpp>
  11. #include <boost/graph/random.hpp>
  12. #include <boost/graph/graph_utility.hpp>
  13. #include <boost/graph/graph_archetypes.hpp>
  14. #include <boost/graph/breadth_first_search.hpp>
  15. #include <boost/random/mersenne_twister.hpp>
  16. #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
  17. using namespace boost;
  18. #endif
  19. template <typename DistanceMap, typename ParentMap,
  20. typename Graph, typename ColorMap>
  21. class bfs_testing_visitor
  22. {
  23. typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
  24. typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
  25. typedef typename boost::color_traits<
  26. typename boost::property_traits<ColorMap>::value_type
  27. > Color;
  28. public:
  29. bfs_testing_visitor(Vertex s, DistanceMap d, ParentMap p, ColorMap c)
  30. : current_distance(0), distance(d), parent(p), color(c), src(s) { }
  31. void initialize_vertex(const Vertex& u, const Graph& ) const {
  32. BOOST_CHECK(get(color, u) == Color::white());
  33. }
  34. void examine_vertex(const Vertex& u, const Graph& ) const {
  35. current_vertex = u;
  36. // Ensure that the distances monotonically increase.
  37. BOOST_CHECK( distance[u] == current_distance
  38. || distance[u] == current_distance + 1 );
  39. if (distance[u] == current_distance + 1) // new level
  40. ++current_distance;
  41. }
  42. void discover_vertex(const Vertex& u, const Graph& ) const {
  43. BOOST_CHECK( get(color, u) == Color::gray() );
  44. if (u == src) {
  45. current_vertex = src;
  46. } else {
  47. BOOST_CHECK( parent[u] == current_vertex );
  48. BOOST_CHECK( distance[u] == current_distance + 1 );
  49. BOOST_CHECK( distance[u] == distance[parent[u]] + 1 );
  50. }
  51. }
  52. void examine_edge(const Edge& e, const Graph& g) const {
  53. BOOST_CHECK( source(e, g) == current_vertex );
  54. }
  55. void tree_edge(const Edge& e, const Graph& g) const {
  56. BOOST_CHECK( get(color, target(e, g)) == Color::white() );
  57. Vertex u = source(e, g), v = target(e, g);
  58. BOOST_CHECK( distance[u] == current_distance );
  59. parent[v] = u;
  60. distance[v] = distance[u] + 1;
  61. }
  62. void non_tree_edge(const Edge& e, const Graph& g) const {
  63. BOOST_CHECK( color[target(e, g)] != Color::white() );
  64. if (boost::is_directed(g))
  65. // cross or back edge
  66. BOOST_CHECK(distance[target(e, g)] <= distance[source(e, g)] + 1);
  67. else {
  68. // cross edge (or going backwards on a tree edge)
  69. BOOST_CHECK(distance[target(e, g)] == distance[source(e, g)]
  70. || distance[target(e, g)] == distance[source(e, g)] + 1
  71. || distance[target(e, g)] == distance[source(e, g)] - 1
  72. );
  73. }
  74. }
  75. void gray_target(const Edge& e, const Graph& g) const {
  76. BOOST_CHECK( color[target(e, g)] == Color::gray() );
  77. }
  78. void black_target(const Edge& e, const Graph& g) const {
  79. BOOST_CHECK( color[target(e, g)] == Color::black() );
  80. // All vertices adjacent to a black vertex must already be discovered
  81. typename boost::graph_traits<Graph>::adjacency_iterator ai, ai_end;
  82. for (boost::tie(ai, ai_end) = adjacent_vertices(target(e, g), g);
  83. ai != ai_end; ++ai)
  84. BOOST_CHECK( color[*ai] != Color::white() );
  85. }
  86. void finish_vertex(const Vertex& u, const Graph& ) const {
  87. BOOST_CHECK( color[u] == Color::black() );
  88. }
  89. private:
  90. mutable Vertex current_vertex;
  91. mutable typename boost::property_traits<DistanceMap>::value_type
  92. current_distance;
  93. DistanceMap distance;
  94. ParentMap parent;
  95. ColorMap color;
  96. Vertex src;
  97. };
  98. template <class Graph>
  99. struct bfs_test
  100. {
  101. typedef boost::graph_traits<Graph> Traits;
  102. typedef typename Traits::vertices_size_type
  103. vertices_size_type;
  104. static void go(vertices_size_type max_V) {
  105. typedef typename Traits::vertex_descriptor vertex_descriptor;
  106. typedef boost::color_traits<boost::default_color_type> Color;
  107. vertices_size_type i;
  108. typename Traits::edges_size_type j;
  109. typename Traits::vertex_iterator ui, ui_end;
  110. boost::mt19937 gen;
  111. for (i = 0; i < max_V; ++i)
  112. for (j = 0; j < i*i; ++j) {
  113. Graph g;
  114. boost::generate_random_graph(g, i, j, gen);
  115. // declare the "start" variable
  116. vertex_descriptor start = boost::random_vertex(g, gen);
  117. // vertex properties
  118. std::vector<int> distance(i, (std::numeric_limits<int>::max)());
  119. distance[start] = 0;
  120. std::vector<vertex_descriptor> parent(i);
  121. for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui)
  122. parent[*ui] = *ui;
  123. std::vector<boost::default_color_type> color(i);
  124. // Get vertex index map
  125. typedef typename boost::property_map<Graph, boost::vertex_index_t>::const_type idx_type;
  126. idx_type idx = get(boost::vertex_index, g);
  127. // Make property maps from vectors
  128. typedef
  129. boost::iterator_property_map<std::vector<int>::iterator, idx_type>
  130. distance_pm_type;
  131. distance_pm_type distance_pm(distance.begin(), idx);
  132. typedef
  133. boost::iterator_property_map<typename std::vector<vertex_descriptor>::iterator, idx_type>
  134. parent_pm_type;
  135. parent_pm_type parent_pm(parent.begin(), idx);
  136. typedef
  137. boost::iterator_property_map<std::vector<boost::default_color_type>::iterator, idx_type>
  138. color_pm_type;
  139. color_pm_type color_pm(color.begin(), idx);
  140. // Create the testing visitor.
  141. bfs_testing_visitor<distance_pm_type, parent_pm_type, Graph,
  142. color_pm_type>
  143. vis(start, distance_pm, parent_pm, color_pm);
  144. boost::breadth_first_search(g, start,
  145. visitor(vis).
  146. color_map(color_pm));
  147. // All white vertices should be unreachable from the source.
  148. for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui)
  149. if (color[*ui] == Color::white()) {
  150. std::vector<boost::default_color_type> color2(i, Color::white());
  151. BOOST_CHECK(!boost::is_reachable(start, *ui, g, color_pm_type(color2.begin(), idx)));
  152. }
  153. // The shortest path to a child should be one longer than
  154. // shortest path to the parent.
  155. for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui)
  156. if (parent[*ui] != *ui) // *ui not the root of the bfs tree
  157. BOOST_CHECK(distance[*ui] == distance[parent[*ui]] + 1);
  158. }
  159. }
  160. };
  161. int test_main(int argc, char* argv[])
  162. {
  163. using namespace boost;
  164. int max_V = 7;
  165. if (argc > 1)
  166. max_V = atoi(argv[1]);
  167. bfs_test< adjacency_list<vecS, vecS, directedS> >::go(max_V);
  168. bfs_test< adjacency_list<vecS, vecS, undirectedS> >::go(max_V);
  169. return 0;
  170. }