stoer_wagner_test.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Copyright Daniel Trebbien 2010.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or the copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
  6. # define _CRT_SECURE_NO_WARNINGS
  7. #endif
  8. #include <fstream>
  9. #include <iostream>
  10. #include <map>
  11. #include <vector>
  12. #include <string>
  13. #include <boost/graph/adjacency_list.hpp>
  14. #include <boost/graph/connected_components.hpp>
  15. #include <boost/graph/exception.hpp>
  16. #include <boost/graph/graph_traits.hpp>
  17. #include <boost/graph/read_dimacs.hpp>
  18. #include <boost/graph/stoer_wagner_min_cut.hpp>
  19. #include <boost/graph/property_maps/constant_property_map.hpp>
  20. #include <boost/property_map/property_map.hpp>
  21. #include <boost/test/unit_test.hpp>
  22. #include <boost/tuple/tuple.hpp>
  23. typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, boost::property<boost::edge_weight_t, int> > undirected_graph;
  24. typedef boost::property_map<undirected_graph, boost::edge_weight_t>::type weight_map_type;
  25. typedef boost::property_traits<weight_map_type>::value_type weight_type;
  26. typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> undirected_unweighted_graph;
  27. std::string test_dir;
  28. boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) {
  29. if (argc != 2) {
  30. std::cerr << "Usage: " << argv[0] << " path-to-libs-graph-test" << std::endl;
  31. throw boost::unit_test::framework::setup_error("Invalid command line arguments");
  32. }
  33. test_dir = argv[1];
  34. return 0;
  35. }
  36. struct edge_t
  37. {
  38. unsigned long first;
  39. unsigned long second;
  40. };
  41. // the example from Stoer & Wagner (1997)
  42. BOOST_AUTO_TEST_CASE(test0)
  43. {
  44. edge_t edges[] = {{0, 1}, {1, 2}, {2, 3},
  45. {0, 4}, {1, 4}, {1, 5}, {2, 6}, {3, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}};
  46. weight_type ws[] = {2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3};
  47. undirected_graph g(edges, edges + 12, ws, 8, 12);
  48. weight_map_type weights = get(boost::edge_weight, g);
  49. std::map<int, bool> parity;
  50. boost::associative_property_map<std::map<int, bool> > parities(parity);
  51. int w = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities));
  52. BOOST_CHECK_EQUAL(w, 4);
  53. const bool parity0 = get(parities, 0);
  54. BOOST_CHECK_EQUAL(parity0, get(parities, 1));
  55. BOOST_CHECK_EQUAL(parity0, get(parities, 4));
  56. BOOST_CHECK_EQUAL(parity0, get(parities, 5));
  57. const bool parity2 = get(parities, 2);
  58. BOOST_CHECK_NE(parity0, parity2);
  59. BOOST_CHECK_EQUAL(parity2, get(parities, 3));
  60. BOOST_CHECK_EQUAL(parity2, get(parities, 6));
  61. BOOST_CHECK_EQUAL(parity2, get(parities, 7));
  62. }
  63. BOOST_AUTO_TEST_CASE(test1)
  64. {
  65. { // if only one vertex, can't run `boost::stoer_wagner_min_cut`
  66. undirected_graph g;
  67. add_vertex(g);
  68. BOOST_CHECK_THROW(boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)), boost::bad_graph);
  69. }{ // three vertices with one multi-edge
  70. typedef boost::graph_traits<undirected_graph>::vertex_descriptor vertex_descriptor;
  71. edge_t edges[] = {{0, 1}, {1, 2}, {1, 2}, {2, 0}};
  72. weight_type ws[] = {3, 1, 1, 1};
  73. undirected_graph g(edges, edges + 4, ws, 3, 4);
  74. weight_map_type weights = get(boost::edge_weight, g);
  75. std::map<int, bool> parity;
  76. boost::associative_property_map<std::map<int, bool> > parities(parity);
  77. std::map<vertex_descriptor, vertex_descriptor> assignment;
  78. boost::associative_property_map<std::map<vertex_descriptor, vertex_descriptor> > assignments(assignment);
  79. int w = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities).vertex_assignment_map(assignments));
  80. BOOST_CHECK_EQUAL(w, 3);
  81. const bool parity2 = get(parities, 2),
  82. parity0 = get(parities, 0);
  83. BOOST_CHECK_NE(parity2, parity0);
  84. BOOST_CHECK_EQUAL(parity0, get(parities, 1));
  85. }
  86. }
  87. // example by Daniel Trebbien
  88. BOOST_AUTO_TEST_CASE(test2)
  89. {
  90. edge_t edges[] = {{5, 2}, {0, 6}, {5, 6},
  91. {3, 1}, {0, 1}, {6, 3}, {4, 6}, {2, 4}, {5, 3}};
  92. weight_type ws[] = {1, 3, 4, 6, 4, 1, 2, 5, 2};
  93. undirected_graph g(edges, edges + 9, ws, 7, 9);
  94. std::map<int, bool> parity;
  95. boost::associative_property_map<std::map<int, bool> > parities(parity);
  96. int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::parity_map(parities));
  97. BOOST_CHECK_EQUAL(w, 3);
  98. const bool parity2 = get(parities, 2);
  99. BOOST_CHECK_EQUAL(parity2, get(parities, 4));
  100. const bool parity5 = get(parities, 5);
  101. BOOST_CHECK_NE(parity2, parity5);
  102. BOOST_CHECK_EQUAL(parity5, get(parities, 3));
  103. BOOST_CHECK_EQUAL(parity5, get(parities, 6));
  104. BOOST_CHECK_EQUAL(parity5, get(parities, 1));
  105. BOOST_CHECK_EQUAL(parity5, get(parities, 0));
  106. }
  107. // example by Daniel Trebbien
  108. BOOST_AUTO_TEST_CASE(test3)
  109. {
  110. edge_t edges[] = {{3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7},
  111. {0, 5}, {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}};
  112. weight_type ws[] = {0, 3, 1, 3, 1, 2, 6, 1, 8, 1, 1, 80, 2, 1, 1, 4};
  113. undirected_graph g(edges, edges + 16, ws, 8, 16);
  114. weight_map_type weights = get(boost::edge_weight, g);
  115. std::map<int, bool> parity;
  116. boost::associative_property_map<std::map<int, bool> > parities(parity);
  117. int w = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities));
  118. BOOST_CHECK_EQUAL(w, 7);
  119. const bool parity1 = get(parities, 1);
  120. BOOST_CHECK_EQUAL(parity1, get(parities, 5));
  121. const bool parity0 = get(parities, 0);
  122. BOOST_CHECK_NE(parity1, parity0);
  123. BOOST_CHECK_EQUAL(parity0, get(parities, 2));
  124. BOOST_CHECK_EQUAL(parity0, get(parities, 3));
  125. BOOST_CHECK_EQUAL(parity0, get(parities, 4));
  126. BOOST_CHECK_EQUAL(parity0, get(parities, 6));
  127. BOOST_CHECK_EQUAL(parity0, get(parities, 7));
  128. }
  129. BOOST_AUTO_TEST_CASE(test4)
  130. {
  131. typedef boost::graph_traits<undirected_unweighted_graph>::vertex_descriptor vertex_descriptor;
  132. typedef boost::graph_traits<undirected_unweighted_graph>::edge_descriptor edge_descriptor;
  133. edge_t edges[] = {{0, 1}, {1, 2}, {2, 3},
  134. {0, 4}, {1, 4}, {1, 5}, {2, 6}, {3, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7},
  135. {0, 4}, {6, 7}};
  136. undirected_unweighted_graph g(edges, edges + 14, 8);
  137. std::map<vertex_descriptor, bool> parity;
  138. boost::associative_property_map<std::map<vertex_descriptor, bool> > parities(parity);
  139. std::map<vertex_descriptor, vertex_descriptor> assignment;
  140. boost::associative_property_map<std::map<vertex_descriptor, vertex_descriptor> > assignments(assignment);
  141. int w = boost::stoer_wagner_min_cut(g, boost::make_constant_property<edge_descriptor>(weight_type(1)), boost::vertex_assignment_map(assignments).parity_map(parities));
  142. BOOST_CHECK_EQUAL(w, 2);
  143. const bool parity0 = get(parities, 0);
  144. BOOST_CHECK_EQUAL(parity0, get(parities, 1));
  145. BOOST_CHECK_EQUAL(parity0, get(parities, 4));
  146. BOOST_CHECK_EQUAL(parity0, get(parities, 5));
  147. const bool parity2 = get(parities, 2);
  148. BOOST_CHECK_NE(parity0, parity2);
  149. BOOST_CHECK_EQUAL(parity2, get(parities, 3));
  150. BOOST_CHECK_EQUAL(parity2, get(parities, 6));
  151. BOOST_CHECK_EQUAL(parity2, get(parities, 7));
  152. }
  153. // The input for the `test_prgen` family of tests comes from a program, named
  154. // `prgen`, that comes with a package of min-cut solvers by Chandra Chekuri,
  155. // Andrew Goldberg, David Karger, Matthew Levine, and Cliff Stein. `prgen` was
  156. // used to generate input graphs and the solvers were used to verify the return
  157. // value of `boost::stoer_wagner_min_cut` on the input graphs.
  158. //
  159. // http://www.columbia.edu/~cs2035/code.html
  160. //
  161. // Note that it is somewhat more difficult to verify the parities because
  162. // "`prgen` graphs" often have several min-cuts. This is why only the cut
  163. // weight of the min-cut is verified.
  164. // 3 min-cuts
  165. BOOST_AUTO_TEST_CASE(test_prgen_20_70_2)
  166. {
  167. typedef boost::graph_traits<undirected_graph>::vertex_descriptor vertex_descriptor;
  168. std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_20_70_2.net").c_str());
  169. undirected_graph g;
  170. boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs);
  171. std::map<vertex_descriptor, std::size_t> component;
  172. boost::associative_property_map<std::map<vertex_descriptor, std::size_t> > components(component);
  173. BOOST_CHECK_EQUAL(boost::connected_components(g, components), 1U); // verify the connectedness assumption
  174. typedef boost::shared_array_property_map<weight_type, boost::property_map<undirected_graph, boost::vertex_index_t>::const_type> distances_type;
  175. distances_type distances = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), get(boost::vertex_index, g));
  176. typedef std::vector<vertex_descriptor>::size_type index_in_heap_type;
  177. typedef boost::shared_array_property_map<index_in_heap_type, boost::property_map<undirected_graph, boost::vertex_index_t>::const_type> indicesInHeap_type;
  178. indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map(num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g));
  179. boost::d_ary_heap_indirect<vertex_descriptor, 22, indicesInHeap_type, distances_type, std::greater<weight_type> > pq(distances, indicesInHeap);
  180. int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::max_priority_queue(pq));
  181. BOOST_CHECK_EQUAL(w, 3407);
  182. }
  183. // 7 min-cuts
  184. BOOST_AUTO_TEST_CASE(test_prgen_50_40_2)
  185. {
  186. typedef boost::graph_traits<undirected_graph>::vertex_descriptor vertex_descriptor;
  187. std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_50_40_2.net").c_str());
  188. undirected_graph g;
  189. boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs);
  190. std::map<vertex_descriptor, std::size_t> component;
  191. boost::associative_property_map<std::map<vertex_descriptor, std::size_t> > components(component);
  192. BOOST_CHECK_EQUAL(boost::connected_components(g, components), 1U); // verify the connectedness assumption
  193. int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g));
  194. BOOST_CHECK_EQUAL(w, 10056);
  195. }
  196. // 6 min-cuts
  197. BOOST_AUTO_TEST_CASE(test_prgen_50_70_2)
  198. {
  199. typedef boost::graph_traits<undirected_graph>::vertex_descriptor vertex_descriptor;
  200. std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_50_70_2.net").c_str());
  201. undirected_graph g;
  202. boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs);
  203. std::map<vertex_descriptor, std::size_t> component;
  204. boost::associative_property_map<std::map<vertex_descriptor, std::size_t> > components(component);
  205. BOOST_CHECK_EQUAL(boost::connected_components(g, components), 1U); // verify the connectedness assumption
  206. int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g));
  207. BOOST_CHECK_EQUAL(w, 21755);
  208. }