adjlist_redist_test.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright (C) 2005, 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/lexical_cast.hpp>
  11. #include <boost/serialization/vector.hpp>
  12. #include <boost/graph/distributed/adjacency_list.hpp>
  13. #include <boost/graph/distributed/mpi_process_group.hpp>
  14. #include <boost/random/linear_congruential.hpp>
  15. #include <iostream>
  16. #include <boost/property_map/property_map_iterator.hpp>
  17. #include <boost/graph/distributed/dehne_gotz_min_spanning_tree.hpp>
  18. #include <boost/graph/distributed/vertex_list_adaptor.hpp>
  19. #include <boost/graph/erdos_renyi_generator.hpp>
  20. #include <boost/graph/distributed/graphviz.hpp>
  21. #include <sstream>
  22. #include <string>
  23. #include <boost/graph/iteration_macros.hpp>
  24. #include <boost/test/minimal.hpp>
  25. #ifdef BOOST_NO_EXCEPTIONS
  26. void
  27. boost::throw_exception(std::exception const& ex)
  28. {
  29. std::cout << ex.what() << std::endl;
  30. abort();
  31. }
  32. #endif
  33. using namespace boost;
  34. using boost::graph::distributed::mpi_process_group;
  35. /****************************************************************************
  36. * Edge weight generator iterator *
  37. ****************************************************************************/
  38. template<typename F>
  39. class generator_iterator
  40. {
  41. public:
  42. typedef std::input_iterator_tag iterator_category;
  43. typedef typename F::result_type value_type;
  44. typedef const value_type& reference;
  45. typedef const value_type* pointer;
  46. typedef void difference_type;
  47. explicit generator_iterator(const F& f = F()) : f(f) { value = this->f(); }
  48. reference operator*() const { return value; }
  49. pointer operator->() const { return &value; }
  50. generator_iterator& operator++()
  51. {
  52. value = f();
  53. return *this;
  54. }
  55. generator_iterator operator++(int)
  56. {
  57. generator_iterator temp(*this);
  58. ++(*this);
  59. return temp;
  60. }
  61. bool operator==(const generator_iterator& other) const
  62. { return f == other.f; }
  63. bool operator!=(const generator_iterator& other) const
  64. { return !(*this == other); }
  65. private:
  66. F f;
  67. value_type value;
  68. };
  69. template<typename F>
  70. inline generator_iterator<F> make_generator_iterator(const F& f)
  71. { return generator_iterator<F>(f); }
  72. typedef minstd_rand RandomGenerator;
  73. template<typename Graph>
  74. double get_mst_weight (const Graph& g)
  75. {
  76. typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
  77. typename property_map<Graph, edge_weight_t>::const_type weight
  78. = get(edge_weight, g);
  79. // Boruvka then merge test
  80. std::vector<edge_descriptor> results;
  81. graph::boruvka_then_merge(make_vertex_list_adaptor(g), weight,
  82. std::back_inserter(results));
  83. if (process_id(g.process_group()) == 0)
  84. return accumulate(make_property_map_iterator(weight, results.begin()),
  85. make_property_map_iterator(weight, results.end()),
  86. 0.0);
  87. else
  88. return 0.0;
  89. }
  90. template<typename Graph>
  91. void test_redistribution(int n, double p, int iterations, bool debug_output)
  92. {
  93. RandomGenerator gen;
  94. Graph g(erdos_renyi_iterator<RandomGenerator, Graph>(gen, n, p),
  95. erdos_renyi_iterator<RandomGenerator, Graph>(),
  96. make_generator_iterator(uniform_01<RandomGenerator>(gen)),
  97. n);
  98. int iter = 0;
  99. mpi_process_group pg = g.process_group();
  100. // Set the names of the vertices to be the global index in the
  101. // initial distribution. Then when we are debugging we'll be able to
  102. // see how vertices have moved.
  103. {
  104. typedef typename property_map<Graph, vertex_index_t>::type VertexIndexMap;
  105. typedef typename property_map<Graph, vertex_global_t>::type VertexGlobalMap;
  106. typename property_map<Graph, vertex_name_t>::type name_map
  107. = get(vertex_name, g);
  108. parallel::global_index_map<VertexIndexMap, VertexGlobalMap>
  109. global_index(g.process_group(), num_vertices(g),
  110. get(vertex_index, g), get(vertex_global, g));
  111. BGL_FORALL_VERTICES_T(v, g, Graph)
  112. put(name_map, v, get(global_index, v));
  113. }
  114. if (debug_output)
  115. write_graphviz("redist-0.dot", g,
  116. make_label_writer(get(vertex_name, g)),
  117. make_label_writer(get(edge_weight, g)));
  118. double mst_weight = get_mst_weight(g);
  119. if (process_id(pg) == 0)
  120. std::cout << "MST weight = " << mst_weight << std::endl;
  121. RandomGenerator nonsync_gen(process_id(pg) + gen());
  122. while (++iter <= iterations) {
  123. typename property_map<Graph, vertex_rank_t>::type to_processor_map =
  124. get(vertex_rank, g);
  125. // Randomly assign a new distribution
  126. typename graph_traits<Graph>::vertex_iterator vi, vi_end;
  127. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  128. put(to_processor_map, *vi, gen() % num_processes(pg));
  129. if (process_id(pg) == 0)
  130. std::cout << "Redistributing...";
  131. // Perform the actual redistribution
  132. g.redistribute(to_processor_map);
  133. if (process_id(pg) == 0)
  134. std::cout << " done." << std::endl;
  135. if (debug_output) {
  136. std::ostringstream out;
  137. out << "redist-" << iter << ".dot";
  138. write_graphviz(out.str().c_str(), g,
  139. make_label_writer(get(vertex_name, g)),
  140. make_label_writer(get(edge_weight, g)));
  141. }
  142. // Check that the MST weight is unchanged
  143. double new_mst_weight = get_mst_weight(g);
  144. if (process_id(pg) == 0) {
  145. std::cout << "MST weight = " << new_mst_weight << std::endl;
  146. if (std::fabs(new_mst_weight - mst_weight) > 0.0001)
  147. communicator(pg).abort(-1); }
  148. }
  149. }
  150. int test_main(int argc, char** argv)
  151. {
  152. int n = 1000;
  153. double p = 3e-3;
  154. int iterations = 5;
  155. bool debug_output = false;
  156. boost::mpi::environment env(argc, argv);
  157. if (argc > 1) n = lexical_cast<int>(argv[1]);
  158. if (argc > 2) p = lexical_cast<double>(argv[2]);
  159. if (argc > 3) iterations = lexical_cast<int>(argv[3]);
  160. if (argc > 4) debug_output = true;
  161. typedef adjacency_list<listS,
  162. distributedS<mpi_process_group, vecS>,
  163. undirectedS,
  164. // Vertex properties
  165. property<vertex_name_t, std::size_t,
  166. property<vertex_rank_t, int> >,
  167. // Edge properties
  168. property<edge_weight_t, double> > UnstableUDGraph;
  169. typedef adjacency_list<listS,
  170. distributedS<mpi_process_group, listS>,
  171. undirectedS,
  172. // Vertex properties
  173. property<vertex_name_t, std::size_t,
  174. property<vertex_rank_t, int,
  175. property<vertex_index_t, std::size_t> > >,
  176. // Edge properties
  177. property<edge_weight_t, double> > StableUDGraph;
  178. test_redistribution<UnstableUDGraph>(n, p, iterations, debug_output);
  179. test_redistribution<StableUDGraph>(n, p, iterations, debug_output);
  180. return 0;
  181. }