distributed_connected_components_test.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // Copyright (C) 2004-2006 The Trustees of Indiana University.
  2. // Use, modification and distribution is subject to the Boost Software
  3. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // Authors: Douglas Gregor
  6. // Andrew Lumsdaine
  7. #include <boost/graph/use_mpi.hpp>
  8. #include <boost/config.hpp>
  9. #include <boost/throw_exception.hpp>
  10. #include <boost/serialization/vector.hpp>
  11. #include <boost/graph/distributed/adjacency_list.hpp>
  12. #include <boost/graph/connected_components.hpp>
  13. #include <boost/graph/distributed/connected_components_parallel_search.hpp>
  14. #include <boost/graph/random.hpp>
  15. #include <boost/property_map/parallel/distributed_property_map.hpp>
  16. #include <boost/graph/distributed/mpi_process_group.hpp>
  17. #include <boost/graph/parallel/distribution.hpp>
  18. #include <boost/graph/erdos_renyi_generator.hpp>
  19. #include <boost/graph/distributed/graphviz.hpp>
  20. #include <iostream>
  21. #include <cstdlib>
  22. #include <iomanip>
  23. #include <boost/random.hpp>
  24. #include <boost/test/minimal.hpp>
  25. #include <boost/graph/distributed/compressed_sparse_row_graph.hpp>
  26. #include <boost/graph/rmat_graph_generator.hpp>
  27. #ifdef BOOST_NO_EXCEPTIONS
  28. void
  29. boost::throw_exception(std::exception const& ex)
  30. {
  31. std::cout << ex.what() << std::endl;
  32. abort();
  33. }
  34. #endif
  35. using namespace boost;
  36. using boost::graph::distributed::mpi_process_group;
  37. typedef double time_type;
  38. inline time_type get_time()
  39. {
  40. return MPI_Wtime();
  41. }
  42. std::string print_time(time_type t)
  43. {
  44. std::ostringstream out;
  45. out << std::setiosflags(std::ios::fixed) << std::setprecision(2) << t;
  46. return out.str();
  47. }
  48. template<typename T>
  49. class map_lt
  50. {
  51. public:
  52. bool operator()() const { return false; }
  53. bool operator()(T x, T y) const { return (owner(x) < owner(y) || (owner(x) == owner(y) && local(x) < local(y))); }
  54. };
  55. void
  56. test_distributed_connected_components(int n, double _p, bool verify, bool emit_dot_file, int seed, bool parallel_search)
  57. {
  58. // typedef adjacency_list<listS,
  59. // distributedS<mpi_process_group, vecS>,
  60. // undirectedS> Graph;
  61. typedef compressed_sparse_row_graph<directedS, no_property, no_property, no_property,
  62. distributedS<mpi_process_group> > Graph;
  63. minstd_rand gen;
  64. gen.seed(seed);
  65. mpi_process_group pg;
  66. parallel::variant_distribution<mpi_process_group> distrib
  67. = parallel::block(pg, n);
  68. minstd_rand dist_gen;
  69. #if 0
  70. if (false) {
  71. distrib = parallel::random_distribution(pg, dist_gen, n);
  72. } else if (true) {
  73. distrib = parallel::oned_block_cyclic(pg, 13);
  74. }
  75. #endif
  76. // Graph g(erdos_renyi_iterator<minstd_rand, Graph>(gen, n, _p/2),
  77. // erdos_renyi_iterator<minstd_rand, Graph>(),
  78. // n, pg, distrib);
  79. int m = int(n * n * _p/2);
  80. double a = 0.57, b = 0.19, c = 0.19, d = 0.05;
  81. // Last boolean parameter makes R-MAT bidirectional
  82. Graph g(sorted_unique_rmat_iterator<minstd_rand, Graph>(gen, n, m, a, b, c, d, true),
  83. sorted_unique_rmat_iterator<minstd_rand, Graph>(),
  84. n, pg, distrib);
  85. synchronize(g);
  86. std::vector<int> local_components_vec(num_vertices(g));
  87. typedef iterator_property_map<std::vector<int>::iterator, property_map<Graph, vertex_index_t>::type> ComponentMap;
  88. ComponentMap component(local_components_vec.begin(), get(vertex_index, g));
  89. int num_components = 0;
  90. time_type start = get_time();
  91. if (parallel_search) {
  92. num_components = connected_components_ps(g, component);
  93. } else {
  94. num_components = connected_components(g, component);
  95. }
  96. time_type end = get_time();
  97. if (process_id(g.process_group()) == 0)
  98. std::cerr << "Connected Components time = " << print_time(end - start) << " seconds.\n"
  99. << num_components << " components identified\n";
  100. if ( verify )
  101. {
  102. if ( process_id(g.process_group()) == 0 )
  103. {
  104. component.set_max_ghost_cells(0);
  105. for (int i = 0; i < n; ++i)
  106. get(component, vertex(i, g));
  107. synchronize(component);
  108. // Check against the sequential version
  109. typedef adjacency_list<listS,
  110. vecS,
  111. undirectedS,
  112. // Vertex properties
  113. no_property,
  114. // Edge properties
  115. no_property > Graph2;
  116. gen.seed(seed);
  117. // Graph2 g2(erdos_renyi_iterator<minstd_rand, Graph>(gen, n, _p/2),
  118. // erdos_renyi_iterator<minstd_rand, Graph>(),
  119. // n);
  120. Graph2 g2( sorted_unique_rmat_iterator<minstd_rand, Graph>(gen, n, m, a, b, c, d, true),
  121. sorted_unique_rmat_iterator<minstd_rand, Graph>(),
  122. n);
  123. std::vector<int> component2 (n);
  124. int tmp;
  125. tmp = connected_components(g2, make_iterator_property_map(component2.begin(), get(vertex_index, g2)));
  126. std::cerr << "Verifier found " << tmp << " components" << std::endl;
  127. // Make sure components and component2 match
  128. std::map<int, int> c2c;
  129. int i;
  130. // This fails if there are more components in 'component' than
  131. // 'component2' because multiple components in 'component' may
  132. // legitimately map to the same component number in 'component2'.
  133. // We can either test the mapping in the opposite direction or
  134. // just assert that the numbers of components found by both
  135. // algorithms is the same
  136. for ( i = 0; i < n; i++ )
  137. if ( c2c.find( get(component, vertex(i, g)) ) == c2c.end() )
  138. c2c[get(component, vertex(i, g))] = component2[i];
  139. else
  140. if ( c2c[get(component, vertex(i, g))] != component2[i] )
  141. break;
  142. if ( i < n || num_components != tmp) {
  143. printf("Unable to verify CC result...\n");
  144. } else
  145. printf("Passed verification... %i connected components\n",
  146. (int)c2c.size());
  147. }
  148. else
  149. {
  150. synchronize(component);
  151. }
  152. if ( emit_dot_file )
  153. write_graphviz("cc.dot", g, paint_by_number(component));
  154. }
  155. }
  156. int test_main(int argc, char* argv[])
  157. {
  158. mpi::environment env(argc, argv);
  159. if ( argc < 6 ) {
  160. test_distributed_connected_components(10000, 0.001, true, false, 1, false);
  161. test_distributed_connected_components(10000, 0.001, true, false, 1, true);
  162. }
  163. else
  164. test_distributed_connected_components
  165. (atoi(argv[1]), atof(argv[2]),
  166. argv[3]==std::string("true"), argv[4]==std::string("true"),
  167. argc == 6? 1 : atoi(argv[6]),
  168. argv[5]==std::string("true"));
  169. return 0;
  170. }