Update contrib.
1 //=======================================================================
2 // Copyright (c) 2005 Aaron Windsor
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)
8 //=======================================================================
11 * © Portions copyright (c) 2006-2007 Nokia Corporation. All rights reserved.
14 #include <boost/graph/max_cardinality_matching.hpp>
16 #include <iostream> // for std::cout
17 #include <boost/vector_property_map.hpp>
18 #include <boost/graph/adjacency_list.hpp>
19 #include <boost/graph/adjacency_matrix.hpp>
20 #include <boost/graph/random.hpp>
22 #include <boost/random.hpp>
23 #include <boost/test/minimal.hpp>
25 #include "std_log_result.h"
26 #define LOG_FILENAME_LINE __FILE__, __LINE__
28 using namespace boost;
30 typedef adjacency_list<vecS,
33 property<vertex_index_t, int> > undirected_graph;
35 typedef adjacency_list<listS,
38 property<vertex_index_t, int> > undirected_list_graph;
40 typedef adjacency_matrix<undirectedS,
41 property<vertex_index_t,int> > undirected_adjacency_matrix_graph;
44 template <typename Graph>
45 struct vertex_index_installer
47 static void install(Graph& g) {}
52 struct vertex_index_installer<undirected_list_graph>
54 static void install(undirected_list_graph& g)
56 typedef graph_traits<undirected_list_graph>::vertex_iterator vertex_iterator_t;
57 typedef graph_traits<undirected_list_graph>::vertices_size_type v_size_t;
59 vertex_iterator_t vi, vi_end;
61 for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi, ++i)
62 put(vertex_index, g, *vi, i);
68 template <typename Graph>
69 void complete_graph(Graph& g, int n)
71 //creates the complete graph on n vertices
72 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
75 vertex_iterator_t vi, vi_end, wi;
76 tie(vi,vi_end) = vertices(g);
77 for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
81 for(; wi != vi_end; ++wi)
88 template <typename Graph>
89 void gabows_graph(Graph& g, int n)
91 //creates a graph with 2n vertices, consisting of the complete graph
92 //on n vertices plus n vertices of degree one, each adjacent to one
93 //vertex in the complete graph. without any initial matching, this
94 //graph forces edmonds' algorithm into worst-case behavior.
96 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
100 vertex_iterator_t vi, vi_end, ui, ui_end, halfway;
102 tie(ui,ui_end) = vertices(g);
105 for(int i = 0; i < n; ++i)
113 while (vi != halfway)
121 tie(ui,ui_end) = vertices(g);
123 while(halfway != ui_end)
125 add_edge(*ui, *halfway, g);
134 template <typename Graph>
135 void matching_test(std::size_t num_v, const std::string& graph_name)
137 typedef typename property_map<Graph,vertex_index_t>::type vertex_index_map_t;
138 typedef vector_property_map< typename graph_traits<Graph>::vertex_descriptor, vertex_index_map_t > mate_t;
139 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
140 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor_t;
141 typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
143 const std::size_t double_num_v = num_v * 2;
145 bool all_tests_passed = true;
147 //form the complete graph on 2*n vertices; the maximum cardinality matching, greedy matching,
148 //and extra greedy matching should all be the same - a matching of size n.
150 Graph g(double_num_v);
151 complete_graph(g,double_num_v);
153 vertex_index_installer<Graph>::install(g);
155 mate_t edmonds_mate(double_num_v);
156 mate_t greedy_mate(double_num_v);
157 mate_t extra_greedy_mate(double_num_v);
159 //find a maximum cardinality matching using edmonds' blossom-shrinking algorithm, starting
160 //with an empty matching.
161 bool edmonds_result =
162 matching < Graph, mate_t, vertex_index_map_t,
163 edmonds_augmenting_path_finder, empty_matching, maximum_cardinality_matching_verifier>
164 (g,edmonds_mate, get(vertex_index,g));
166 BOOST_CHECK (edmonds_result);
169 std::cout << "Verifier reporting a problem finding a perfect matching on" << std::endl
170 << "the complete graph using " << graph_name << std::endl;
171 all_tests_passed = false;
174 //find a greedy matching
176 matching<Graph, mate_t, vertex_index_map_t,
177 no_augmenting_path_finder, greedy_matching, maximum_cardinality_matching_verifier>
178 (g,greedy_mate, get(vertex_index,g));
180 BOOST_CHECK (greedy_result);
183 std::cout << "Verifier reporting a problem finding a greedy matching on" << std::endl
184 << "the complete graph using " << graph_name << std::endl;
185 all_tests_passed = false;
188 //find an extra greedy matching
189 bool extra_greedy_result =
190 matching<Graph, mate_t, vertex_index_map_t,
191 no_augmenting_path_finder, extra_greedy_matching, maximum_cardinality_matching_verifier>
192 (g,extra_greedy_mate,get(vertex_index,g));
194 BOOST_CHECK (extra_greedy_result);
195 if (!extra_greedy_result)
197 std::cout << "Verifier reporting a problem finding an extra greedy matching on" << std::endl
198 << "the complete graph using " << graph_name << std::endl;
199 all_tests_passed = false;
202 //as a sanity check, make sure that each of the matchings returned is a valid matching and has
205 bool edmonds_sanity_check =
206 is_a_matching(g,edmonds_mate) && matching_size(g,edmonds_mate) == num_v;
208 BOOST_CHECK (edmonds_sanity_check);
209 if (edmonds_result && !edmonds_sanity_check)
211 std::cout << "Verifier okayed edmonds' algorithm on the complete graph, but" << std::endl
212 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
213 << "actually a maximum cardinality matching." << std::endl;
214 all_tests_passed = false;
217 bool greedy_sanity_check =
218 is_a_matching(g,greedy_mate) && matching_size(g,greedy_mate) == num_v;
220 BOOST_CHECK (greedy_sanity_check);
221 if (greedy_result && !greedy_sanity_check)
223 std::cout << "Verifier okayed greedy algorithm on the complete graph, but" << std::endl
224 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
225 << "actually a maximum cardinality matching." << std::endl;
226 all_tests_passed = false;
229 bool extra_greedy_sanity_check =
230 is_a_matching(g,extra_greedy_mate) && matching_size(g,extra_greedy_mate) == num_v;
232 BOOST_CHECK (extra_greedy_sanity_check);
233 if (extra_greedy_result && !extra_greedy_sanity_check)
235 std::cout << "Verifier okayed extra greedy algorithm on the complete graph, but" << std::endl
236 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
237 << "actually a maximum cardinality matching." << std::endl;
238 all_tests_passed = false;
241 //Now remove an edge from the edmonds_mate matching.
242 vertex_iterator_t vi,vi_end;
243 for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
244 if (edmonds_mate[*vi] != graph_traits<Graph>::null_vertex())
247 edmonds_mate[edmonds_mate[*vi]] = graph_traits<Graph>::null_vertex();
248 edmonds_mate[*vi] = graph_traits<Graph>::null_vertex();
250 //...and run the matching verifier - it should tell us that the matching isn't
251 //a maximum matching.
252 bool modified_edmonds_verification_result =
253 maximum_cardinality_matching_verifier<Graph,mate_t,vertex_index_map_t>::verify_matching(g,edmonds_mate,get(vertex_index,g));
255 BOOST_CHECK (!modified_edmonds_verification_result);
256 if (modified_edmonds_verification_result)
258 std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl;
259 all_tests_passed = false;
262 Graph h(double_num_v);
263 gabows_graph(h,num_v);
265 vertex_index_installer<Graph>::install(h);
267 //gabow's graph always has a perfect matching. it's also a good example of why
268 //one should initialize with the extra_greedy_matching in most cases.
270 mate_t gabow_mate(double_num_v);
272 bool gabows_graph_result = checked_edmonds_maximum_cardinality_matching(h,gabow_mate);
274 BOOST_CHECK (gabows_graph_result);
275 if (!gabows_graph_result)
277 std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl
278 << " Verifier reporting a maximum cardinality matching not found." << std::endl;
279 all_tests_passed = false;
282 BOOST_CHECK (matching_size(h,gabow_mate) == num_v);
283 if (gabows_graph_result && matching_size(h,gabow_mate) != num_v)
285 std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl
286 << " Verifier reported a maximum cardinality matching found," << std::endl
287 << " but matching size is " << matching_size(h,gabow_mate)
288 << " when it should be " << num_v << std::endl;
289 all_tests_passed = false;
292 Graph j(double_num_v);
293 vertex_index_installer<Graph>::install(j);
295 typedef boost::mt19937 base_generator_type;
296 base_generator_type generator(static_cast<unsigned int>(std::time(0)));
297 boost::uniform_int<> distribution(0, double_num_v-1);
298 boost::variate_generator<base_generator_type&, boost::uniform_int<> > rand_num(generator, distribution);
300 std::size_t num_edges = 0;
303 while (num_edges < 4*double_num_v)
305 vertex_descriptor_t u = random_vertex(j,rand_num);
306 vertex_descriptor_t v = random_vertex(j,rand_num);
309 tie(tuples::ignore, success) = add_edge(u, v, j);
315 mate_t random_mate(double_num_v);
316 bool random_graph_result = checked_edmonds_maximum_cardinality_matching(j,random_mate);
318 BOOST_CHECK(random_graph_result);
319 if (!random_graph_result)
321 std::cout << "Matching in random graph not maximum for " << graph_name << std::endl;
322 all_tests_passed = false;
325 //Now remove an edge from the random_mate matching.
326 for(tie(vi,vi_end) = vertices(j); vi != vi_end; ++vi)
327 if (random_mate[*vi] != graph_traits<Graph>::null_vertex())
330 random_mate[random_mate[*vi]] = graph_traits<Graph>::null_vertex();
331 random_mate[*vi] = graph_traits<Graph>::null_vertex();
333 //...and run the matching verifier - it should tell us that the matching isn't
334 //a maximum matching.
335 bool modified_random_verification_result =
336 maximum_cardinality_matching_verifier<Graph,mate_t,vertex_index_map_t>::verify_matching(j,random_mate,get(vertex_index,j));
338 BOOST_CHECK(!modified_random_verification_result);
339 if (modified_random_verification_result)
341 std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl;
342 all_tests_passed = false;
345 BOOST_CHECK(all_tests_passed);
346 if (all_tests_passed)
348 std::cout << graph_name << " passed all tests for n = " << num_v << '.' << std::endl;
356 int test_main(int argc, char* argv[])
359 matching_test<undirected_graph>(10, "adjacency_list (using vectors)");
360 matching_test<undirected_list_graph>(10, "adjacency_list (using lists)");
361 matching_test<undirected_adjacency_matrix_graph>(10, "adjacency_matrix");
363 matching_test<undirected_graph>(50, "adjacency_list (using vectors)");
364 matching_test<undirected_list_graph>(50, "adjacency_list (using lists)");
365 matching_test<undirected_adjacency_matrix_graph>(50, "adjacency_matrix");
367 matching_test<undirected_graph>(51, "adjacency_list (using vectors)");
368 matching_test<undirected_list_graph>(51, "adjacency_list (using lists)");
369 matching_test<undirected_adjacency_matrix_graph>(51, "adjacency_matrix");
372 std_log(LOG_FILENAME_LINE,"[End Test Case ]");
374 testResultXml("matching_test");