Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/graph/test/matching_test.cpp @ 47

Last change on this file since 47 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

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