distributed_adjacency_list_test.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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: 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/graph/distributed/adjacency_list.hpp>
  11. #include <boost/graph/distributed/mpi_process_group.hpp>
  12. #include <boost/graph/distributed/local_subgraph.hpp>
  13. #include <boost/graph/parallel/distribution.hpp>
  14. #include <iostream>
  15. #include <cassert>
  16. #include <boost/test/minimal.hpp>
  17. #ifdef BOOST_NO_EXCEPTIONS
  18. void
  19. boost::throw_exception(std::exception const& ex)
  20. {
  21. std::cout << ex.what() << std::endl;
  22. abort();
  23. }
  24. #endif
  25. using namespace boost;
  26. using boost::graph::distributed::mpi_process_group;
  27. template<typename Graph>
  28. struct never
  29. {
  30. typedef typename graph_traits<Graph>::edge_descriptor argument_type;
  31. typedef bool result_type;
  32. result_type operator()(argument_type) { return false; }
  33. };
  34. int test_main(int argc, char** argv)
  35. {
  36. boost::mpi::environment env(argc, argv);
  37. mpi_process_group pg;
  38. parallel::block dist(pg, 20);
  39. typedef adjacency_list<listS, distributedS<mpi_process_group, vecS>,
  40. bidirectionalS> Graph1;
  41. typedef adjacency_list<listS, distributedS<mpi_process_group, vecS>,
  42. directedS> Graph2;
  43. typedef adjacency_list<listS, distributedS<mpi_process_group, vecS>,
  44. undirectedS> Graph3;
  45. if (num_processes(pg) > 20) return -1;
  46. if (process_id(pg) == 0) std::cout << "Graph 1------------------\n";
  47. std::cout << "Processor #" << process_id(pg) << ": "
  48. << dist.block_size(20) << " vertices." << std::endl;
  49. {
  50. Graph1 g1(20);
  51. // if (process_id(pg) == num_processes(pg)() - 1)
  52. // add_vertex(g1);
  53. graph_traits<Graph1>::vertex_iterator v, v_end;
  54. int counter = 0;
  55. for (boost::tie(v, v_end) = vertices(g1); v != v_end; ++v) {
  56. std::cout << "Processor #" << process_id(pg) << ": vertex " << ++counter
  57. << std::endl;
  58. out_edges(*v, g1);
  59. out_degree(*v, g1);
  60. in_edges(*v, g1);
  61. in_degree(*v, g1);
  62. graph_traits<Graph1>::vertex_descriptor other = *v;
  63. other.owner = (other.owner + 1) % num_processes(pg);
  64. other.local = 0;
  65. add_edge(*v, other, g1);
  66. std::cout << "Adding edge from processor " << process_id(pg)
  67. << " to processor " << other.owner << std::endl;
  68. }
  69. synchronize(g1);
  70. assert((std::size_t)std::distance(edges(g1).first, edges(g1).second) == num_vertices(g1));
  71. if (num_vertices(g1) >= 2) {
  72. graph_traits<Graph1>::vertex_iterator vi = vertices(g1).first;
  73. graph_traits<Graph1>::vertex_descriptor u = *vi++;
  74. graph_traits<Graph1>::vertex_descriptor v = *vi++;
  75. add_edge(u, v, g1);
  76. assert(out_degree(u, g1) == 2);
  77. assert(in_degree(v, g1) == 1);
  78. }
  79. int prior_processor = (process_id(pg) + num_processes(pg) - 1)
  80. % num_processes(pg);
  81. const int n = 20;
  82. std::size_t vertices_in_prior = (n / num_processes(pg))
  83. + (n % num_processes(pg) > prior_processor? 1 : 0);
  84. graph_traits<Graph1>::vertex_descriptor u = *vertices(g1).first;
  85. if (in_degree(u, g1) != vertices_in_prior) {
  86. std::cout << "Processor #" << process_id(pg) << ": " << in_degree(u, g1)
  87. << " vs. " << vertices_in_prior << std::endl;
  88. }
  89. assert(in_degree(u, g1) == vertices_in_prior);
  90. std::cout << "Processor #" << process_id(pg) << ": " << num_edges(g1)
  91. << " edges.\n";
  92. local_subgraph<Graph1> local_g1(g1);
  93. edges(local_g1);
  94. vertices(local_g1);
  95. if (num_vertices(local_g1) > 0) {
  96. out_edges(*vertices(local_g1).first, local_g1);
  97. in_edges(*vertices(local_g1).first, local_g1);
  98. adjacent_vertices(*vertices(local_g1).first, local_g1);
  99. if (false) {
  100. remove_out_edge_if(*vertices(g1).first, never<Graph1>(), g1);
  101. remove_in_edge_if(*vertices(g1).first, never<Graph1>(), g1);
  102. clear_out_edges(*vertices(g1).first, g1);
  103. clear_in_edges(*vertices(g1).first, g1);
  104. clear_vertex(*vertices(g1).first, g1);
  105. remove_vertex(*vertices(g1).first, g1);
  106. }
  107. }
  108. remove_edge_if(never<Graph1>(), g1);
  109. }
  110. if (process_id(pg) == 0) std::cout << "Graph 2------------------\n";
  111. {
  112. Graph2 g2(20);
  113. if (process_id(pg) == num_processes(pg) - 1)
  114. add_vertex(g2);
  115. graph_traits<Graph2>::vertex_iterator v, v_end;
  116. int counter = 0;
  117. for (boost::tie(v, v_end) = vertices(g2); v != v_end; ++v) {
  118. std::cout << "Processor #" << process_id(pg) << ": vertex " << ++counter
  119. << std::endl;
  120. out_edges(*v, g2);
  121. }
  122. synchronize(g2);
  123. if (num_vertices(g2) >= 2) {
  124. graph_traits<Graph2>::vertex_iterator vi = vertices(g2).first;
  125. graph_traits<Graph2>::vertex_descriptor u = *vi++;
  126. graph_traits<Graph2>::vertex_descriptor v = *vi++;
  127. add_edge(u, v, g2);
  128. assert(out_degree(u, g2) == 1);
  129. assert(*adjacent_vertices(u, g2).first == v);
  130. std::cout << "Processor #" << process_id(pg) << ": " << num_edges(g2)
  131. << " edges.\n";
  132. assert(std::distance(edges(g2).first, edges(g2).second) == 1);
  133. }
  134. synchronize(g2);
  135. local_subgraph<Graph2> local_g2(g2);
  136. edges(local_g2);
  137. vertices(local_g2);
  138. if (num_vertices(local_g2) > 0) {
  139. out_edges(*vertices(local_g2).first, local_g2);
  140. adjacent_vertices(*vertices(local_g2).first, local_g2);
  141. remove_out_edge_if(*vertices(g2).first, never<Graph2>(), g2);
  142. clear_out_edges(*vertices(g2).first, g2);
  143. remove_vertex(*vertices(g2).first, g2);
  144. }
  145. remove_edge_if(never<Graph2>(), g2);
  146. }
  147. if (process_id(pg) == 0) std::cout << "Graph 3------------------\n";
  148. {
  149. Graph3 g3(20);
  150. // if (process_id(pg) == num_processes(pg) - 1)
  151. // add_vertex(g3);
  152. graph_traits<Graph3>::vertex_iterator v, v_end;
  153. int counter = 0;
  154. for (boost::tie(v, v_end) = vertices(g3); v != v_end; ++v) {
  155. std::cout << "Processor #" << process_id(pg) << ": vertex " << ++counter
  156. << std::endl;
  157. out_edges(*v, g3);
  158. out_degree(*v, g3);
  159. in_edges(*v, g3);
  160. in_degree(*v, g3);
  161. }
  162. graph_traits<Graph3>::vertices_size_type added_edges = 0;
  163. if (num_vertices(g3) >= 2) {
  164. graph_traits<Graph3>::vertex_iterator vi = vertices(g3).first;
  165. graph_traits<Graph3>::vertex_descriptor u = *vi++;
  166. graph_traits<Graph3>::vertex_descriptor v = *vi++;
  167. add_edge(u, v, g3); ++added_edges;
  168. assert(out_degree(u, g3) == 1);
  169. assert(in_degree(u, g3) == 1);
  170. graph_traits<Graph3>::edge_descriptor e = *out_edges(u, g3).first;
  171. assert(source(e, g3) == u);
  172. assert(target(e, g3) == v);
  173. e = *in_edges(u, g3).first;
  174. assert(source(e, g3) == v);
  175. assert(target(e, g3) == u);
  176. assert(out_degree(v, g3) == 1);
  177. assert(in_degree(v, g3) == 1);
  178. e = *out_edges(v, g3).first;
  179. assert(source(e, g3) == v);
  180. assert(target(e, g3) == u);
  181. e = *in_edges(v, g3).first;
  182. assert(source(e, g3) == u);
  183. assert(target(e, g3) == v);
  184. assert(*adjacent_vertices(u, g3).first == v);
  185. assert(*adjacent_vertices(v, g3).first == u);
  186. std::cout << "Processor #" << process_id(pg) << ": " << num_edges(g3)
  187. << " edges.\n";
  188. }
  189. // Add some remote edges
  190. for (boost::tie(v, v_end) = vertices(g3); v != v_end; ++v) {
  191. graph_traits<Graph1>::vertex_descriptor other = *v;
  192. other.owner = (other.owner + 1) % num_processes(pg);
  193. other.local = 0;
  194. add_edge(*v, other, g3); ++added_edges;
  195. std::cout << "Adding edge from processor " << process_id(pg)
  196. << " to processor " << other.owner << std::endl;
  197. }
  198. synchronize(g3);
  199. assert(std::distance(edges(g3).first, edges(g3).second) == (ptrdiff_t)added_edges);
  200. assert(num_edges(g3) == added_edges);
  201. // Verify the remote edges
  202. if (num_vertices(g3) >= 2) {
  203. graph_traits<Graph3>::vertex_iterator vi = vertices(g3).first;
  204. graph_traits<Graph3>::vertex_descriptor u = *vi++;
  205. int prior_processor = (process_id(pg) + num_processes(pg) - 1)
  206. % num_processes(pg);
  207. const int n = 20;
  208. graph_traits<Graph3>::vertices_size_type vertices_in_prior = (n / num_processes(pg))
  209. + (n % num_processes(pg) > prior_processor? 1 : 0);
  210. if (in_degree(u, g3) != vertices_in_prior + 2) {
  211. std::cerr << "#" << process_id(pg) << ": " << in_degree(u, g3)
  212. << " != " << vertices_in_prior + 2 << std::endl;
  213. }
  214. assert(in_degree(u, g3) == vertices_in_prior + 2);
  215. assert(out_degree(u, g3) == vertices_in_prior + 2);
  216. }
  217. local_subgraph<Graph3> local_g3(g3);
  218. edges(local_g3);
  219. vertices(local_g3);
  220. if (num_vertices(local_g3) > 0) {
  221. out_edges(*vertices(local_g3).first, local_g3);
  222. in_edges(*vertices(local_g3).first, local_g3);
  223. adjacent_vertices(*vertices(local_g3).first, local_g3);
  224. remove_out_edge_if(*vertices(g3).first, never<Graph3>(), g3);
  225. remove_in_edge_if(*vertices(g3).first, never<Graph3>(), g3);
  226. if (false) {
  227. // Removing an edge from two processes concurrently is not yet
  228. // supported.
  229. clear_vertex(*vertices(g3).first, g3);
  230. remove_vertex(*vertices(g3).first, g3);
  231. }
  232. }
  233. remove_edge_if(never<Graph3>(), g3);
  234. }
  235. return 0;
  236. }