matching_test.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. //=======================================================================
  2. // Copyright (c) 2005 Aaron Windsor
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. //=======================================================================
  9. #include <boost/config.hpp>
  10. #ifdef BOOST_MSVC
  11. // Without disabling this we get hard errors about initialialized pointers:
  12. #pragma warning(disable:4703)
  13. #endif
  14. #include <boost/graph/max_cardinality_matching.hpp>
  15. #include <iostream> // for std::cout
  16. #include <boost/property_map/vector_property_map.hpp>
  17. #include <boost/graph/adjacency_list.hpp>
  18. #include <boost/graph/adjacency_matrix.hpp>
  19. #include <boost/graph/random.hpp>
  20. #include <ctime>
  21. #include <boost/random.hpp>
  22. #include <boost/test/minimal.hpp>
  23. using namespace boost;
  24. typedef adjacency_list<vecS,
  25. vecS,
  26. undirectedS,
  27. property<vertex_index_t, int> > undirected_graph;
  28. typedef adjacency_list<listS,
  29. listS,
  30. undirectedS,
  31. property<vertex_index_t, int> > undirected_list_graph;
  32. typedef adjacency_matrix<undirectedS,
  33. property<vertex_index_t,int> > undirected_adjacency_matrix_graph;
  34. template <typename Graph>
  35. struct vertex_index_installer
  36. {
  37. static void install(Graph&) {}
  38. };
  39. template <>
  40. struct vertex_index_installer<undirected_list_graph>
  41. {
  42. static void install(undirected_list_graph& g)
  43. {
  44. typedef graph_traits<undirected_list_graph>::vertex_iterator vertex_iterator_t;
  45. typedef graph_traits<undirected_list_graph>::vertices_size_type v_size_t;
  46. vertex_iterator_t vi, vi_end;
  47. v_size_t i = 0;
  48. for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi, ++i)
  49. put(vertex_index, g, *vi, i);
  50. }
  51. };
  52. template <typename Graph>
  53. void complete_graph(Graph& g, int n)
  54. {
  55. //creates the complete graph on n vertices
  56. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
  57. g = Graph(n);
  58. vertex_iterator_t vi, vi_end, wi;
  59. boost::tie(vi,vi_end) = vertices(g);
  60. for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
  61. {
  62. wi = vi;
  63. ++wi;
  64. for(; wi != vi_end; ++wi)
  65. add_edge(*vi,*wi,g);
  66. }
  67. }
  68. template <typename Graph>
  69. void gabows_graph(Graph& g, int n)
  70. {
  71. //creates a graph with 2n vertices, consisting of the complete graph
  72. //on n vertices plus n vertices of degree one, each adjacent to one
  73. //vertex in the complete graph. without any initial matching, this
  74. //graph forces edmonds' algorithm into worst-case behavior.
  75. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
  76. g = Graph(2* n);
  77. vertex_iterator_t vi, vi_end, ui, ui_end, halfway;
  78. boost::tie(ui,ui_end) = vertices(g);
  79. halfway = ui;
  80. for(int i = 0; i < n; ++i)
  81. ++halfway;
  82. while(ui != halfway)
  83. {
  84. vi = ui;
  85. ++vi;
  86. while (vi != halfway)
  87. {
  88. add_edge(*ui,*vi,g);
  89. ++vi;
  90. }
  91. ++ui;
  92. }
  93. boost::tie(ui,ui_end) = vertices(g);
  94. while(halfway != ui_end)
  95. {
  96. add_edge(*ui, *halfway, g);
  97. ++ui;
  98. ++halfway;
  99. }
  100. }
  101. template <typename Graph>
  102. void matching_test(std::size_t num_v, const std::string& graph_name)
  103. {
  104. typedef typename property_map<Graph,vertex_index_t>::type vertex_index_map_t;
  105. typedef vector_property_map< typename graph_traits<Graph>::vertex_descriptor, vertex_index_map_t > mate_t;
  106. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
  107. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor_t;
  108. const std::size_t double_num_v = num_v * 2;
  109. bool all_tests_passed = true;
  110. //form the complete graph on 2*n vertices; the maximum cardinality matching, greedy matching,
  111. //and extra greedy matching should all be the same - a matching of size n.
  112. Graph g(double_num_v);
  113. complete_graph(g,double_num_v);
  114. vertex_index_installer<Graph>::install(g);
  115. mate_t edmonds_mate(double_num_v);
  116. mate_t greedy_mate(double_num_v);
  117. mate_t extra_greedy_mate(double_num_v);
  118. //find a maximum cardinality matching using edmonds' blossom-shrinking algorithm, starting
  119. //with an empty matching.
  120. bool edmonds_result =
  121. matching < Graph, mate_t, vertex_index_map_t,
  122. edmonds_augmenting_path_finder, empty_matching, maximum_cardinality_matching_verifier>
  123. (g,edmonds_mate, get(vertex_index,g));
  124. BOOST_CHECK (edmonds_result);
  125. if (!edmonds_result)
  126. {
  127. std::cout << "Verifier reporting a problem finding a perfect matching on" << std::endl
  128. << "the complete graph using " << graph_name << std::endl;
  129. all_tests_passed = false;
  130. }
  131. //find a greedy matching
  132. bool greedy_result =
  133. matching<Graph, mate_t, vertex_index_map_t,
  134. no_augmenting_path_finder, greedy_matching, maximum_cardinality_matching_verifier>
  135. (g,greedy_mate, get(vertex_index,g));
  136. BOOST_CHECK (greedy_result);
  137. if (!greedy_result)
  138. {
  139. std::cout << "Verifier reporting a problem finding a greedy matching on" << std::endl
  140. << "the complete graph using " << graph_name << std::endl;
  141. all_tests_passed = false;
  142. }
  143. //find an extra greedy matching
  144. bool extra_greedy_result =
  145. matching<Graph, mate_t, vertex_index_map_t,
  146. no_augmenting_path_finder, extra_greedy_matching, maximum_cardinality_matching_verifier>
  147. (g,extra_greedy_mate,get(vertex_index,g));
  148. BOOST_CHECK (extra_greedy_result);
  149. if (!extra_greedy_result)
  150. {
  151. std::cout << "Verifier reporting a problem finding an extra greedy matching on" << std::endl
  152. << "the complete graph using " << graph_name << std::endl;
  153. all_tests_passed = false;
  154. }
  155. //as a sanity check, make sure that each of the matchings returned is a valid matching and has
  156. //1000 edges.
  157. bool edmonds_sanity_check =
  158. is_a_matching(g,edmonds_mate) && matching_size(g,edmonds_mate) == num_v;
  159. BOOST_CHECK (edmonds_sanity_check);
  160. if (edmonds_result && !edmonds_sanity_check)
  161. {
  162. std::cout << "Verifier okayed edmonds' algorithm on the complete graph, but" << std::endl
  163. << "the matching returned either wasn't a valid matching or wasn't" << std::endl
  164. << "actually a maximum cardinality matching." << std::endl;
  165. all_tests_passed = false;
  166. }
  167. bool greedy_sanity_check =
  168. is_a_matching(g,greedy_mate) && matching_size(g,greedy_mate) == num_v;
  169. BOOST_CHECK (greedy_sanity_check);
  170. if (greedy_result && !greedy_sanity_check)
  171. {
  172. std::cout << "Verifier okayed greedy algorithm on the complete graph, but" << std::endl
  173. << "the matching returned either wasn't a valid matching or wasn't" << std::endl
  174. << "actually a maximum cardinality matching." << std::endl;
  175. all_tests_passed = false;
  176. }
  177. bool extra_greedy_sanity_check =
  178. is_a_matching(g,extra_greedy_mate) && matching_size(g,extra_greedy_mate) == num_v;
  179. BOOST_CHECK (extra_greedy_sanity_check);
  180. if (extra_greedy_result && !extra_greedy_sanity_check)
  181. {
  182. std::cout << "Verifier okayed extra greedy algorithm on the complete graph, but" << std::endl
  183. << "the matching returned either wasn't a valid matching or wasn't" << std::endl
  184. << "actually a maximum cardinality matching." << std::endl;
  185. all_tests_passed = false;
  186. }
  187. //Now remove an edge from the edmonds_mate matching.
  188. vertex_iterator_t vi,vi_end;
  189. for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
  190. if (edmonds_mate[*vi] != graph_traits<Graph>::null_vertex())
  191. break;
  192. edmonds_mate[edmonds_mate[*vi]] = graph_traits<Graph>::null_vertex();
  193. edmonds_mate[*vi] = graph_traits<Graph>::null_vertex();
  194. //...and run the matching verifier - it should tell us that the matching isn't
  195. //a maximum matching.
  196. bool modified_edmonds_verification_result =
  197. maximum_cardinality_matching_verifier<Graph,mate_t,vertex_index_map_t>::verify_matching(g,edmonds_mate,get(vertex_index,g));
  198. BOOST_CHECK (!modified_edmonds_verification_result);
  199. if (modified_edmonds_verification_result)
  200. {
  201. std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl;
  202. all_tests_passed = false;
  203. }
  204. Graph h(double_num_v);
  205. gabows_graph(h,num_v);
  206. vertex_index_installer<Graph>::install(h);
  207. //gabow's graph always has a perfect matching. it's also a good example of why
  208. //one should initialize with the extra_greedy_matching in most cases.
  209. mate_t gabow_mate(double_num_v);
  210. bool gabows_graph_result = checked_edmonds_maximum_cardinality_matching(h,gabow_mate);
  211. BOOST_CHECK (gabows_graph_result);
  212. if (!gabows_graph_result)
  213. {
  214. std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl
  215. << " Verifier reporting a maximum cardinality matching not found." << std::endl;
  216. all_tests_passed = false;
  217. }
  218. BOOST_CHECK (matching_size(h,gabow_mate) == num_v);
  219. if (gabows_graph_result && matching_size(h,gabow_mate) != num_v)
  220. {
  221. std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl
  222. << " Verifier reported a maximum cardinality matching found," << std::endl
  223. << " but matching size is " << matching_size(h,gabow_mate)
  224. << " when it should be " << num_v << std::endl;
  225. all_tests_passed = false;
  226. }
  227. Graph j(double_num_v);
  228. vertex_index_installer<Graph>::install(j);
  229. typedef boost::mt19937 base_generator_type;
  230. base_generator_type generator(static_cast<unsigned int>(std::time(0)));
  231. boost::uniform_int<> distribution(0, double_num_v-1);
  232. boost::variate_generator<base_generator_type&, boost::uniform_int<> > rand_num(generator, distribution);
  233. std::size_t num_edges = 0;
  234. bool success;
  235. while (num_edges < 4*double_num_v)
  236. {
  237. vertex_descriptor_t u = random_vertex(j,rand_num);
  238. vertex_descriptor_t v = random_vertex(j,rand_num);
  239. if (u != v)
  240. {
  241. boost::tie(tuples::ignore, success) = add_edge(u, v, j);
  242. if (success)
  243. num_edges++;
  244. }
  245. }
  246. mate_t random_mate(double_num_v);
  247. bool random_graph_result = checked_edmonds_maximum_cardinality_matching(j,random_mate);
  248. BOOST_CHECK(random_graph_result);
  249. if (!random_graph_result)
  250. {
  251. std::cout << "Matching in random graph not maximum for " << graph_name << std::endl;
  252. all_tests_passed = false;
  253. }
  254. //Now remove an edge from the random_mate matching.
  255. for(boost::tie(vi,vi_end) = vertices(j); vi != vi_end; ++vi)
  256. if (random_mate[*vi] != graph_traits<Graph>::null_vertex())
  257. break;
  258. random_mate[random_mate[*vi]] = graph_traits<Graph>::null_vertex();
  259. random_mate[*vi] = graph_traits<Graph>::null_vertex();
  260. //...and run the matching verifier - it should tell us that the matching isn't
  261. //a maximum matching.
  262. bool modified_random_verification_result =
  263. maximum_cardinality_matching_verifier<Graph,mate_t,vertex_index_map_t>::verify_matching(j,random_mate,get(vertex_index,j));
  264. BOOST_CHECK(!modified_random_verification_result);
  265. if (modified_random_verification_result)
  266. {
  267. std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl;
  268. all_tests_passed = false;
  269. }
  270. BOOST_CHECK(all_tests_passed);
  271. if (all_tests_passed)
  272. {
  273. std::cout << graph_name << " passed all tests for n = " << num_v << '.' << std::endl;
  274. }
  275. }
  276. int test_main(int, char*[])
  277. {
  278. matching_test<undirected_graph>(10, "adjacency_list (using vectors)");
  279. matching_test<undirected_list_graph>(10, "adjacency_list (using lists)");
  280. matching_test<undirected_adjacency_matrix_graph>(10, "adjacency_matrix");
  281. matching_test<undirected_graph>(20, "adjacency_list (using vectors)");
  282. matching_test<undirected_list_graph>(20, "adjacency_list (using lists)");
  283. matching_test<undirected_adjacency_matrix_graph>(20, "adjacency_matrix");
  284. matching_test<undirected_graph>(21, "adjacency_list (using vectors)");
  285. matching_test<undirected_list_graph>(21, "adjacency_list (using lists)");
  286. matching_test<undirected_adjacency_matrix_graph>(21, "adjacency_matrix");
  287. #if 0
  288. matching_test<undirected_graph>(50, "adjacency_list (using vectors)");
  289. matching_test<undirected_list_graph>(50, "adjacency_list (using lists)");
  290. matching_test<undirected_adjacency_matrix_graph>(50, "adjacency_matrix");
  291. matching_test<undirected_graph>(51, "adjacency_list (using vectors)");
  292. matching_test<undirected_list_graph>(51, "adjacency_list (using lists)");
  293. matching_test<undirected_adjacency_matrix_graph>(51, "adjacency_matrix");
  294. #endif
  295. return 0;
  296. }