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 //=======================================================================
10 #include <boost/config.hpp>
13 // Without disabling this we get hard errors about initialialized pointers:
14 #pragma warning(disable:4703)
17 #include <boost/graph/max_cardinality_matching.hpp>
19 #include <iostream> // for std::cout
20 #include <boost/property_map/vector_property_map.hpp>
21 #include <boost/graph/adjacency_list.hpp>
22 #include <boost/graph/adjacency_matrix.hpp>
23 #include <boost/graph/random.hpp>
25 #include <boost/random.hpp>
26 #include <boost/test/minimal.hpp>
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
&) {}
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(boost::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 boost::tie(vi
,vi_end
) = vertices(g
);
77 for(boost::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 boost::tie(ui
,ui_end
) = vertices(g
);
105 for(int i
= 0; i
< n
; ++i
)
113 while (vi
!= halfway
)
121 boost::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
;
142 const std::size_t double_num_v
= num_v
* 2;
144 bool all_tests_passed
= true;
146 //form the complete graph on 2*n vertices; the maximum cardinality matching, greedy matching,
147 //and extra greedy matching should all be the same - a matching of size n.
149 Graph
g(double_num_v
);
150 complete_graph(g
,double_num_v
);
152 vertex_index_installer
<Graph
>::install(g
);
154 mate_t
edmonds_mate(double_num_v
);
155 mate_t
greedy_mate(double_num_v
);
156 mate_t
extra_greedy_mate(double_num_v
);
158 //find a maximum cardinality matching using edmonds' blossom-shrinking algorithm, starting
159 //with an empty matching.
160 bool edmonds_result
=
161 matching
< Graph
, mate_t
, vertex_index_map_t
,
162 edmonds_augmenting_path_finder
, empty_matching
, maximum_cardinality_matching_verifier
>
163 (g
,edmonds_mate
, get(vertex_index
,g
));
165 BOOST_CHECK (edmonds_result
);
168 std::cout
<< "Verifier reporting a problem finding a perfect matching on" << std::endl
169 << "the complete graph using " << graph_name
<< std::endl
;
170 all_tests_passed
= false;
173 //find a greedy matching
175 matching
<Graph
, mate_t
, vertex_index_map_t
,
176 no_augmenting_path_finder
, greedy_matching
, maximum_cardinality_matching_verifier
>
177 (g
,greedy_mate
, get(vertex_index
,g
));
179 BOOST_CHECK (greedy_result
);
182 std::cout
<< "Verifier reporting a problem finding a greedy matching on" << std::endl
183 << "the complete graph using " << graph_name
<< std::endl
;
184 all_tests_passed
= false;
187 //find an extra greedy matching
188 bool extra_greedy_result
=
189 matching
<Graph
, mate_t
, vertex_index_map_t
,
190 no_augmenting_path_finder
, extra_greedy_matching
, maximum_cardinality_matching_verifier
>
191 (g
,extra_greedy_mate
,get(vertex_index
,g
));
193 BOOST_CHECK (extra_greedy_result
);
194 if (!extra_greedy_result
)
196 std::cout
<< "Verifier reporting a problem finding an extra greedy matching on" << std::endl
197 << "the complete graph using " << graph_name
<< std::endl
;
198 all_tests_passed
= false;
201 //as a sanity check, make sure that each of the matchings returned is a valid matching and has
204 bool edmonds_sanity_check
=
205 is_a_matching(g
,edmonds_mate
) && matching_size(g
,edmonds_mate
) == num_v
;
207 BOOST_CHECK (edmonds_sanity_check
);
208 if (edmonds_result
&& !edmonds_sanity_check
)
210 std::cout
<< "Verifier okayed edmonds' algorithm on the complete graph, but" << std::endl
211 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
212 << "actually a maximum cardinality matching." << std::endl
;
213 all_tests_passed
= false;
216 bool greedy_sanity_check
=
217 is_a_matching(g
,greedy_mate
) && matching_size(g
,greedy_mate
) == num_v
;
219 BOOST_CHECK (greedy_sanity_check
);
220 if (greedy_result
&& !greedy_sanity_check
)
222 std::cout
<< "Verifier okayed greedy algorithm on the complete graph, but" << std::endl
223 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
224 << "actually a maximum cardinality matching." << std::endl
;
225 all_tests_passed
= false;
228 bool extra_greedy_sanity_check
=
229 is_a_matching(g
,extra_greedy_mate
) && matching_size(g
,extra_greedy_mate
) == num_v
;
231 BOOST_CHECK (extra_greedy_sanity_check
);
232 if (extra_greedy_result
&& !extra_greedy_sanity_check
)
234 std::cout
<< "Verifier okayed extra greedy algorithm on the complete graph, but" << std::endl
235 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
236 << "actually a maximum cardinality matching." << std::endl
;
237 all_tests_passed
= false;
240 //Now remove an edge from the edmonds_mate matching.
241 vertex_iterator_t vi
,vi_end
;
242 for(boost::tie(vi
,vi_end
) = vertices(g
); vi
!= vi_end
; ++vi
)
243 if (edmonds_mate
[*vi
] != graph_traits
<Graph
>::null_vertex())
246 edmonds_mate
[edmonds_mate
[*vi
]] = graph_traits
<Graph
>::null_vertex();
247 edmonds_mate
[*vi
] = graph_traits
<Graph
>::null_vertex();
249 //...and run the matching verifier - it should tell us that the matching isn't
250 //a maximum matching.
251 bool modified_edmonds_verification_result
=
252 maximum_cardinality_matching_verifier
<Graph
,mate_t
,vertex_index_map_t
>::verify_matching(g
,edmonds_mate
,get(vertex_index
,g
));
254 BOOST_CHECK (!modified_edmonds_verification_result
);
255 if (modified_edmonds_verification_result
)
257 std::cout
<< "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl
;
258 all_tests_passed
= false;
261 Graph
h(double_num_v
);
262 gabows_graph(h
,num_v
);
264 vertex_index_installer
<Graph
>::install(h
);
266 //gabow's graph always has a perfect matching. it's also a good example of why
267 //one should initialize with the extra_greedy_matching in most cases.
269 mate_t
gabow_mate(double_num_v
);
271 bool gabows_graph_result
= checked_edmonds_maximum_cardinality_matching(h
,gabow_mate
);
273 BOOST_CHECK (gabows_graph_result
);
274 if (!gabows_graph_result
)
276 std::cout
<< "Problem on Gabow's Graph with " << graph_name
<< ":" << std::endl
277 << " Verifier reporting a maximum cardinality matching not found." << std::endl
;
278 all_tests_passed
= false;
281 BOOST_CHECK (matching_size(h
,gabow_mate
) == num_v
);
282 if (gabows_graph_result
&& matching_size(h
,gabow_mate
) != num_v
)
284 std::cout
<< "Problem on Gabow's Graph with " << graph_name
<< ":" << std::endl
285 << " Verifier reported a maximum cardinality matching found," << std::endl
286 << " but matching size is " << matching_size(h
,gabow_mate
)
287 << " when it should be " << num_v
<< std::endl
;
288 all_tests_passed
= false;
291 Graph
j(double_num_v
);
292 vertex_index_installer
<Graph
>::install(j
);
294 typedef boost::mt19937 base_generator_type
;
295 base_generator_type
generator(static_cast<unsigned int>(std::time(0)));
296 boost::uniform_int
<> distribution(0, double_num_v
-1);
297 boost::variate_generator
<base_generator_type
&, boost::uniform_int
<> > rand_num(generator
, distribution
);
299 std::size_t num_edges
= 0;
302 while (num_edges
< 4*double_num_v
)
304 vertex_descriptor_t u
= random_vertex(j
,rand_num
);
305 vertex_descriptor_t v
= random_vertex(j
,rand_num
);
308 boost::tie(tuples::ignore
, success
) = add_edge(u
, v
, j
);
314 mate_t
random_mate(double_num_v
);
315 bool random_graph_result
= checked_edmonds_maximum_cardinality_matching(j
,random_mate
);
317 BOOST_CHECK(random_graph_result
);
318 if (!random_graph_result
)
320 std::cout
<< "Matching in random graph not maximum for " << graph_name
<< std::endl
;
321 all_tests_passed
= false;
324 //Now remove an edge from the random_mate matching.
325 for(boost::tie(vi
,vi_end
) = vertices(j
); vi
!= vi_end
; ++vi
)
326 if (random_mate
[*vi
] != graph_traits
<Graph
>::null_vertex())
329 random_mate
[random_mate
[*vi
]] = graph_traits
<Graph
>::null_vertex();
330 random_mate
[*vi
] = graph_traits
<Graph
>::null_vertex();
332 //...and run the matching verifier - it should tell us that the matching isn't
333 //a maximum matching.
334 bool modified_random_verification_result
=
335 maximum_cardinality_matching_verifier
<Graph
,mate_t
,vertex_index_map_t
>::verify_matching(j
,random_mate
,get(vertex_index
,j
));
337 BOOST_CHECK(!modified_random_verification_result
);
338 if (modified_random_verification_result
)
340 std::cout
<< "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl
;
341 all_tests_passed
= false;
344 BOOST_CHECK(all_tests_passed
);
345 if (all_tests_passed
)
347 std::cout
<< graph_name
<< " passed all tests for n = " << num_v
<< '.' << std::endl
;
355 int test_main(int, char*[])
358 matching_test
<undirected_graph
>(10, "adjacency_list (using vectors)");
359 matching_test
<undirected_list_graph
>(10, "adjacency_list (using lists)");
360 matching_test
<undirected_adjacency_matrix_graph
>(10, "adjacency_matrix");
362 matching_test
<undirected_graph
>(20, "adjacency_list (using vectors)");
363 matching_test
<undirected_list_graph
>(20, "adjacency_list (using lists)");
364 matching_test
<undirected_adjacency_matrix_graph
>(20, "adjacency_matrix");
366 matching_test
<undirected_graph
>(21, "adjacency_list (using vectors)");
367 matching_test
<undirected_list_graph
>(21, "adjacency_list (using lists)");
368 matching_test
<undirected_adjacency_matrix_graph
>(21, "adjacency_matrix");
371 matching_test
<undirected_graph
>(50, "adjacency_list (using vectors)");
372 matching_test
<undirected_list_graph
>(50, "adjacency_list (using lists)");
373 matching_test
<undirected_adjacency_matrix_graph
>(50, "adjacency_matrix");
375 matching_test
<undirected_graph
>(51, "adjacency_list (using vectors)");
376 matching_test
<undirected_list_graph
>(51, "adjacency_list (using lists)");
377 matching_test
<undirected_adjacency_matrix_graph
>(51, "adjacency_matrix");