distributed_strong_components_test.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright (C) 2004-2008 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: Nick Edmonds
  6. // Douglas Gregor
  7. // Andrew Lumsdaine
  8. // SCC won't work with CSR currently due to the way the reverse graph
  9. // is constructed in the SCC algorithm
  10. #include <boost/graph/use_mpi.hpp>
  11. // #define CSR
  12. #ifdef CSR
  13. # include <boost/graph/distributed/compressed_sparse_row_graph.hpp>
  14. #else
  15. # include <boost/graph/distributed/adjacency_list.hpp>
  16. #endif
  17. #include <boost/config.hpp>
  18. #include <boost/throw_exception.hpp>
  19. #include <boost/graph/strong_components.hpp>
  20. #include <boost/graph/random.hpp>
  21. #include <boost/property_map/parallel/distributed_property_map.hpp>
  22. #include <boost/graph/distributed/mpi_process_group.hpp>
  23. #include <boost/graph/parallel/distribution.hpp>
  24. #include <boost/graph/erdos_renyi_generator.hpp>
  25. #include <boost/test/minimal.hpp>
  26. #include <boost/graph/distributed/graphviz.hpp>
  27. #include <iostream>
  28. #include <cstdlib>
  29. #include <iomanip>
  30. #include <boost/random.hpp>
  31. #include <boost/test/minimal.hpp>
  32. #ifdef BOOST_NO_EXCEPTIONS
  33. void
  34. boost::throw_exception(std::exception const& ex)
  35. {
  36. std::cout << ex.what() << std::endl;
  37. abort();
  38. }
  39. #endif
  40. typedef double time_type;
  41. inline time_type get_time()
  42. {
  43. return MPI_Wtime();
  44. }
  45. std::string print_time(time_type t)
  46. {
  47. std::ostringstream out;
  48. out << std::setiosflags(std::ios::fixed) << std::setprecision(2) << t;
  49. return out.str();
  50. }
  51. using namespace boost;
  52. using boost::graph::distributed::mpi_process_group;
  53. void
  54. test_distributed_strong_components(int n, double _p, bool verify, bool emit_dot_file, int seed)
  55. {
  56. #ifdef CSR
  57. typedef compressed_sparse_row_graph<directedS, no_property, no_property, no_property,
  58. distributedS<mpi_process_group> > Graph;
  59. #else
  60. typedef adjacency_list<listS,
  61. distributedS<mpi_process_group, vecS>,
  62. bidirectionalS > Graph;
  63. #endif
  64. minstd_rand gen;
  65. gen.seed(seed);
  66. mpi_process_group pg;
  67. parallel::variant_distribution<mpi_process_group> distrib
  68. = parallel::block(pg, n);
  69. #ifdef CSR
  70. Graph g(sorted_erdos_renyi_iterator<minstd_rand, Graph>(gen, n, _p/2),
  71. sorted_erdos_renyi_iterator<minstd_rand, Graph>(),
  72. n, pg, distrib);
  73. #else
  74. Graph g(erdos_renyi_iterator<minstd_rand, Graph>(gen, n, _p/2),
  75. erdos_renyi_iterator<minstd_rand, Graph>(),
  76. n, pg, distrib);
  77. #endif
  78. synchronize(g);
  79. std::vector<int> local_components_vec(num_vertices(g));
  80. typedef iterator_property_map<std::vector<int>::iterator, property_map<Graph, vertex_index_t>::type> ComponentMap;
  81. ComponentMap component(local_components_vec.begin(), get(vertex_index, g));
  82. int num_components = 0;
  83. time_type start = get_time();
  84. num_components = strong_components(g, component);
  85. time_type end = get_time();
  86. if (process_id(g.process_group()) == 0)
  87. std::cerr << "Erdos-Reyni graph:\n" << n << " Vertices " << _p << " Edge probability "
  88. << num_processes(pg) << " Processors\n"
  89. << "Strong Components time = " << print_time(end - start) << " seconds.\n"
  90. << num_components << " components identified\n";
  91. if ( verify )
  92. {
  93. if ( process_id(g.process_group()) == 0 )
  94. {
  95. for (int i = 0; i < n; ++i)
  96. get(component, vertex(i, g));
  97. synchronize(component);
  98. // Check against the sequential version
  99. typedef adjacency_list<listS, vecS, directedS> Graph2;
  100. gen.seed(seed);
  101. Graph2 g2(erdos_renyi_iterator<minstd_rand, Graph>(gen, n, _p/2),
  102. erdos_renyi_iterator<minstd_rand, Graph>(),
  103. n);
  104. std::vector<int> component2(n);
  105. int seq_num_components = strong_components(g2, make_iterator_property_map(component2.begin(), get(vertex_index, g2)));
  106. assert(num_components == seq_num_components);
  107. // Make sure components and component2 match
  108. std::map<int, int> c2c;
  109. int i;
  110. for ( i = 0; i < n; i++ )
  111. if ( c2c.find( get(component, vertex(i, g)) ) == c2c.end() )
  112. c2c[get(component, vertex(i, g))] = component2[i];
  113. else
  114. if ( c2c[get(component, vertex(i, g))] != component2[i] )
  115. break;
  116. if ( i < n )
  117. std::cerr << "Unable to verify SCC result...\n";
  118. else
  119. std::cerr << "Passed verification... " << seq_num_components << " strong components\n";
  120. }
  121. else
  122. {
  123. synchronize(component);
  124. }
  125. if ( emit_dot_file )
  126. write_graphviz("scc.dot", g, paint_by_number(component));
  127. }
  128. }
  129. int test_main(int argc, char* argv[])
  130. {
  131. mpi::environment env(argc, argv);
  132. if (argc == 1)
  133. test_distributed_strong_components(10000, 0.0005, true, false, 1);
  134. else if ( argc < 5 )
  135. std::cerr << "usage: test_distributed_strong_components <int num_vertices> <double p> <bool verify?> <bool emit_dotfile?> [seed]\n";
  136. else
  137. test_distributed_strong_components
  138. (atoi(argv[1]), atof(argv[2]),
  139. argv[3]==std::string("true"), argv[4]==std::string("true"),
  140. argc == 5? 1 : atoi(argv[5]));
  141. return 0;
  142. }