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 #ifndef BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP
11 #define BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP
12
13 #include <vector>
14 #include <list>
15 #include <deque>
16 #include <algorithm> // for std::sort and std::stable_sort
17 #include <utility> // for std::pair
18 #include <boost/property_map/property_map.hpp>
19 #include <boost/graph/graph_traits.hpp>
20 #include <boost/graph/visitors.hpp>
21 #include <boost/graph/depth_first_search.hpp>
22 #include <boost/graph/filtered_graph.hpp>
23 #include <boost/pending/disjoint_sets.hpp>
24 #include <boost/assert.hpp>
25
26 namespace boost
27 {
28 namespace graph
29 {
30 namespace detail
31 {
32 enum VERTEX_STATE
33 {
34 V_EVEN,
35 V_ODD,
36 V_UNREACHED
37 };
38 }
39 } // end namespace graph::detail
40
41 template < typename Graph, typename MateMap, typename VertexIndexMap >
matching_size(const Graph & g,MateMap mate,VertexIndexMap vm)42 typename graph_traits< Graph >::vertices_size_type matching_size(
43 const Graph& g, MateMap mate, VertexIndexMap vm)
44 {
45 typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
46 typedef
47 typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
48 typedef typename graph_traits< Graph >::vertices_size_type v_size_t;
49
50 v_size_t size_of_matching = 0;
51 vertex_iterator_t vi, vi_end;
52
53 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
54 {
55 vertex_descriptor_t v = *vi;
56 if (get(mate, v) != graph_traits< Graph >::null_vertex()
57 && get(vm, v) < get(vm, get(mate, v)))
58 ++size_of_matching;
59 }
60 return size_of_matching;
61 }
62
63 template < typename Graph, typename MateMap >
matching_size(const Graph & g,MateMap mate)64 inline typename graph_traits< Graph >::vertices_size_type matching_size(
65 const Graph& g, MateMap mate)
66 {
67 return matching_size(g, mate, get(vertex_index, g));
68 }
69
70 template < typename Graph, typename MateMap, typename VertexIndexMap >
is_a_matching(const Graph & g,MateMap mate,VertexIndexMap)71 bool is_a_matching(const Graph& g, MateMap mate, VertexIndexMap)
72 {
73 typedef
74 typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
75 typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
76
77 vertex_iterator_t vi, vi_end;
78 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
79 {
80 vertex_descriptor_t v = *vi;
81 if (get(mate, v) != graph_traits< Graph >::null_vertex()
82 && v != get(mate, get(mate, v)))
83 return false;
84 }
85 return true;
86 }
87
88 template < typename Graph, typename MateMap >
is_a_matching(const Graph & g,MateMap mate)89 inline bool is_a_matching(const Graph& g, MateMap mate)
90 {
91 return is_a_matching(g, mate, get(vertex_index, g));
92 }
93
94 //***************************************************************************
95 //***************************************************************************
96 // Maximum Cardinality Matching Functors
97 //***************************************************************************
98 //***************************************************************************
99
100 template < typename Graph, typename MateMap,
101 typename VertexIndexMap = dummy_property_map >
102 struct no_augmenting_path_finder
103 {
no_augmenting_path_finderboost::no_augmenting_path_finder104 no_augmenting_path_finder(const Graph&, MateMap, VertexIndexMap) {}
105
augment_matchingboost::no_augmenting_path_finder106 inline bool augment_matching() { return false; }
107
get_current_matchingboost::no_augmenting_path_finder108 template < typename PropertyMap > void get_current_matching(PropertyMap) {}
109 };
110
111 template < typename Graph, typename MateMap, typename VertexIndexMap >
112 class edmonds_augmenting_path_finder
113 {
114 // This implementation of Edmonds' matching algorithm closely
115 // follows Tarjan's description of the algorithm in "Data
116 // Structures and Network Algorithms."
117
118 public:
119 // generates the type of an iterator property map from vertices to type X
120 template < typename X > struct map_vertex_to_
121 {
122 typedef boost::iterator_property_map<
123 typename std::vector< X >::iterator, VertexIndexMap >
124 type;
125 };
126
127 typedef
128 typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
129 typedef typename std::pair< vertex_descriptor_t, vertex_descriptor_t >
130 vertex_pair_t;
131 typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t;
132 typedef typename graph_traits< Graph >::vertices_size_type v_size_t;
133 typedef typename graph_traits< Graph >::edges_size_type e_size_t;
134 typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
135 typedef
136 typename graph_traits< Graph >::out_edge_iterator out_edge_iterator_t;
137 typedef typename std::deque< vertex_descriptor_t > vertex_list_t;
138 typedef typename std::vector< edge_descriptor_t > edge_list_t;
139 typedef typename map_vertex_to_< vertex_descriptor_t >::type
140 vertex_to_vertex_map_t;
141 typedef typename map_vertex_to_< int >::type vertex_to_int_map_t;
142 typedef typename map_vertex_to_< vertex_pair_t >::type
143 vertex_to_vertex_pair_map_t;
144 typedef typename map_vertex_to_< v_size_t >::type vertex_to_vsize_map_t;
145 typedef typename map_vertex_to_< e_size_t >::type vertex_to_esize_map_t;
146
edmonds_augmenting_path_finder(const Graph & arg_g,MateMap arg_mate,VertexIndexMap arg_vm)147 edmonds_augmenting_path_finder(
148 const Graph& arg_g, MateMap arg_mate, VertexIndexMap arg_vm)
149 : g(arg_g)
150 , vm(arg_vm)
151 , n_vertices(num_vertices(arg_g))
152 ,
153
154 mate_vector(n_vertices)
155 , ancestor_of_v_vector(n_vertices)
156 , ancestor_of_w_vector(n_vertices)
157 , vertex_state_vector(n_vertices)
158 , origin_vector(n_vertices)
159 , pred_vector(n_vertices)
160 , bridge_vector(n_vertices)
161 , ds_parent_vector(n_vertices)
162 , ds_rank_vector(n_vertices)
163 ,
164
165 mate(mate_vector.begin(), vm)
166 , ancestor_of_v(ancestor_of_v_vector.begin(), vm)
167 , ancestor_of_w(ancestor_of_w_vector.begin(), vm)
168 , vertex_state(vertex_state_vector.begin(), vm)
169 , origin(origin_vector.begin(), vm)
170 , pred(pred_vector.begin(), vm)
171 , bridge(bridge_vector.begin(), vm)
172 , ds_parent_map(ds_parent_vector.begin(), vm)
173 , ds_rank_map(ds_rank_vector.begin(), vm)
174 ,
175
176 ds(ds_rank_map, ds_parent_map)
177 {
178 vertex_iterator_t vi, vi_end;
179 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
180 mate[*vi] = get(arg_mate, *vi);
181 }
182
augment_matching()183 bool augment_matching()
184 {
185 // As an optimization, some of these values can be saved from one
186 // iteration to the next instead of being re-initialized each
187 // iteration, allowing for "lazy blossom expansion." This is not
188 // currently implemented.
189
190 e_size_t timestamp = 0;
191 even_edges.clear();
192
193 vertex_iterator_t vi, vi_end;
194 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
195 {
196 vertex_descriptor_t u = *vi;
197
198 origin[u] = u;
199 pred[u] = u;
200 ancestor_of_v[u] = 0;
201 ancestor_of_w[u] = 0;
202 ds.make_set(u);
203
204 if (mate[u] == graph_traits< Graph >::null_vertex())
205 {
206 vertex_state[u] = graph::detail::V_EVEN;
207 out_edge_iterator_t ei, ei_end;
208 for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end;
209 ++ei)
210 {
211 if (target(*ei, g) != u)
212 {
213 even_edges.push_back(*ei);
214 }
215 }
216 }
217 else
218 vertex_state[u] = graph::detail::V_UNREACHED;
219 }
220
221 // end initializations
222
223 vertex_descriptor_t v, w, w_free_ancestor, v_free_ancestor;
224 w_free_ancestor = graph_traits< Graph >::null_vertex();
225 v_free_ancestor = graph_traits< Graph >::null_vertex();
226 bool found_alternating_path = false;
227
228 while (!even_edges.empty() && !found_alternating_path)
229 {
230 // since we push even edges onto the back of the list as
231 // they're discovered, taking them off the back will search
232 // for augmenting paths depth-first.
233 edge_descriptor_t current_edge = even_edges.back();
234 even_edges.pop_back();
235
236 v = source(current_edge, g);
237 w = target(current_edge, g);
238
239 vertex_descriptor_t v_prime = origin[ds.find_set(v)];
240 vertex_descriptor_t w_prime = origin[ds.find_set(w)];
241
242 // because of the way we put all of the edges on the queue,
243 // v_prime should be labeled V_EVEN; the following is a
244 // little paranoid but it could happen...
245 if (vertex_state[v_prime] != graph::detail::V_EVEN)
246 {
247 std::swap(v_prime, w_prime);
248 std::swap(v, w);
249 }
250
251 if (vertex_state[w_prime] == graph::detail::V_UNREACHED)
252 {
253 vertex_state[w_prime] = graph::detail::V_ODD;
254 vertex_descriptor_t w_prime_mate = mate[w_prime];
255 vertex_state[w_prime_mate] = graph::detail::V_EVEN;
256 out_edge_iterator_t ei, ei_end;
257 for (boost::tie(ei, ei_end) = out_edges(w_prime_mate, g);
258 ei != ei_end; ++ei)
259 {
260 if (target(*ei, g) != w_prime_mate)
261 {
262 even_edges.push_back(*ei);
263 }
264 }
265 pred[w_prime] = v;
266 }
267
268 // w_prime == v_prime can happen below if we get an edge that has
269 // been shrunk into a blossom
270 else if (vertex_state[w_prime] == graph::detail::V_EVEN
271 && w_prime != v_prime)
272 {
273 vertex_descriptor_t w_up = w_prime;
274 vertex_descriptor_t v_up = v_prime;
275 vertex_descriptor_t nearest_common_ancestor
276 = graph_traits< Graph >::null_vertex();
277 w_free_ancestor = graph_traits< Graph >::null_vertex();
278 v_free_ancestor = graph_traits< Graph >::null_vertex();
279
280 // We now need to distinguish between the case that
281 // w_prime and v_prime share an ancestor under the
282 // "parent" relation, in which case we've found a
283 // blossom and should shrink it, or the case that
284 // w_prime and v_prime both have distinct ancestors that
285 // are free, in which case we've found an alternating
286 // path between those two ancestors.
287
288 ++timestamp;
289
290 while (nearest_common_ancestor
291 == graph_traits< Graph >::null_vertex()
292 && (v_free_ancestor == graph_traits< Graph >::null_vertex()
293 || w_free_ancestor
294 == graph_traits< Graph >::null_vertex()))
295 {
296 ancestor_of_w[w_up] = timestamp;
297 ancestor_of_v[v_up] = timestamp;
298
299 if (w_free_ancestor == graph_traits< Graph >::null_vertex())
300 w_up = parent(w_up);
301 if (v_free_ancestor == graph_traits< Graph >::null_vertex())
302 v_up = parent(v_up);
303
304 if (mate[v_up] == graph_traits< Graph >::null_vertex())
305 v_free_ancestor = v_up;
306 if (mate[w_up] == graph_traits< Graph >::null_vertex())
307 w_free_ancestor = w_up;
308
309 if (ancestor_of_w[v_up] == timestamp)
310 nearest_common_ancestor = v_up;
311 else if (ancestor_of_v[w_up] == timestamp)
312 nearest_common_ancestor = w_up;
313 else if (v_free_ancestor == w_free_ancestor
314 && v_free_ancestor
315 != graph_traits< Graph >::null_vertex())
316 nearest_common_ancestor = v_up;
317 }
318
319 if (nearest_common_ancestor
320 == graph_traits< Graph >::null_vertex())
321 found_alternating_path = true; // to break out of the loop
322 else
323 {
324 // shrink the blossom
325 link_and_set_bridges(
326 w_prime, nearest_common_ancestor, std::make_pair(w, v));
327 link_and_set_bridges(
328 v_prime, nearest_common_ancestor, std::make_pair(v, w));
329 }
330 }
331 }
332
333 if (!found_alternating_path)
334 return false;
335
336 // retrieve the augmenting path and put it in aug_path
337 reversed_retrieve_augmenting_path(v, v_free_ancestor);
338 retrieve_augmenting_path(w, w_free_ancestor);
339
340 // augment the matching along aug_path
341 vertex_descriptor_t a, b;
342 while (!aug_path.empty())
343 {
344 a = aug_path.front();
345 aug_path.pop_front();
346 b = aug_path.front();
347 aug_path.pop_front();
348 mate[a] = b;
349 mate[b] = a;
350 }
351
352 return true;
353 }
354
get_current_matching(PropertyMap pm)355 template < typename PropertyMap > void get_current_matching(PropertyMap pm)
356 {
357 vertex_iterator_t vi, vi_end;
358 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
359 put(pm, *vi, mate[*vi]);
360 }
361
get_vertex_state_map(PropertyMap pm)362 template < typename PropertyMap > void get_vertex_state_map(PropertyMap pm)
363 {
364 vertex_iterator_t vi, vi_end;
365 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
366 put(pm, *vi, vertex_state[origin[ds.find_set(*vi)]]);
367 }
368
369 private:
parent(vertex_descriptor_t x)370 vertex_descriptor_t parent(vertex_descriptor_t x)
371 {
372 if (vertex_state[x] == graph::detail::V_EVEN
373 && mate[x] != graph_traits< Graph >::null_vertex())
374 return mate[x];
375 else if (vertex_state[x] == graph::detail::V_ODD)
376 return origin[ds.find_set(pred[x])];
377 else
378 return x;
379 }
380
link_and_set_bridges(vertex_descriptor_t x,vertex_descriptor_t stop_vertex,vertex_pair_t the_bridge)381 void link_and_set_bridges(vertex_descriptor_t x,
382 vertex_descriptor_t stop_vertex, vertex_pair_t the_bridge)
383 {
384 for (vertex_descriptor_t v = x; v != stop_vertex; v = parent(v))
385 {
386 ds.union_set(v, stop_vertex);
387 origin[ds.find_set(stop_vertex)] = stop_vertex;
388
389 if (vertex_state[v] == graph::detail::V_ODD)
390 {
391 bridge[v] = the_bridge;
392 out_edge_iterator_t oei, oei_end;
393 for (boost::tie(oei, oei_end) = out_edges(v, g); oei != oei_end;
394 ++oei)
395 {
396 if (target(*oei, g) != v)
397 {
398 even_edges.push_back(*oei);
399 }
400 }
401 }
402 }
403 }
404
405 // Since none of the STL containers support both constant-time
406 // concatenation and reversal, the process of expanding an
407 // augmenting path once we know one exists is a little more
408 // complicated than it has to be. If we know the path is from v to
409 // w, then the augmenting path is recursively defined as:
410 //
411 // path(v,w) = [v], if v = w
412 // = concat([v, mate[v]], path(pred[mate[v]], w),
413 // if v != w and vertex_state[v] == graph::detail::V_EVEN
414 // = concat([v], reverse(path(x,mate[v])), path(y,w)),
415 // if v != w, vertex_state[v] == graph::detail::V_ODD, and
416 // bridge[v] = (x,y)
417 //
418 // These next two mutually recursive functions implement this definition.
419
retrieve_augmenting_path(vertex_descriptor_t v,vertex_descriptor_t w)420 void retrieve_augmenting_path(vertex_descriptor_t v, vertex_descriptor_t w)
421 {
422 if (v == w)
423 aug_path.push_back(v);
424 else if (vertex_state[v] == graph::detail::V_EVEN)
425 {
426 aug_path.push_back(v);
427 aug_path.push_back(mate[v]);
428 retrieve_augmenting_path(pred[mate[v]], w);
429 }
430 else // vertex_state[v] == graph::detail::V_ODD
431 {
432 aug_path.push_back(v);
433 reversed_retrieve_augmenting_path(bridge[v].first, mate[v]);
434 retrieve_augmenting_path(bridge[v].second, w);
435 }
436 }
437
reversed_retrieve_augmenting_path(vertex_descriptor_t v,vertex_descriptor_t w)438 void reversed_retrieve_augmenting_path(
439 vertex_descriptor_t v, vertex_descriptor_t w)
440 {
441
442 if (v == w)
443 aug_path.push_back(v);
444 else if (vertex_state[v] == graph::detail::V_EVEN)
445 {
446 reversed_retrieve_augmenting_path(pred[mate[v]], w);
447 aug_path.push_back(mate[v]);
448 aug_path.push_back(v);
449 }
450 else // vertex_state[v] == graph::detail::V_ODD
451 {
452 reversed_retrieve_augmenting_path(bridge[v].second, w);
453 retrieve_augmenting_path(bridge[v].first, mate[v]);
454 aug_path.push_back(v);
455 }
456 }
457
458 // private data members
459
460 const Graph& g;
461 VertexIndexMap vm;
462 v_size_t n_vertices;
463
464 // storage for the property maps below
465 std::vector< vertex_descriptor_t > mate_vector;
466 std::vector< e_size_t > ancestor_of_v_vector;
467 std::vector< e_size_t > ancestor_of_w_vector;
468 std::vector< int > vertex_state_vector;
469 std::vector< vertex_descriptor_t > origin_vector;
470 std::vector< vertex_descriptor_t > pred_vector;
471 std::vector< vertex_pair_t > bridge_vector;
472 std::vector< vertex_descriptor_t > ds_parent_vector;
473 std::vector< v_size_t > ds_rank_vector;
474
475 // iterator property maps
476 vertex_to_vertex_map_t mate;
477 vertex_to_esize_map_t ancestor_of_v;
478 vertex_to_esize_map_t ancestor_of_w;
479 vertex_to_int_map_t vertex_state;
480 vertex_to_vertex_map_t origin;
481 vertex_to_vertex_map_t pred;
482 vertex_to_vertex_pair_map_t bridge;
483 vertex_to_vertex_map_t ds_parent_map;
484 vertex_to_vsize_map_t ds_rank_map;
485
486 vertex_list_t aug_path;
487 edge_list_t even_edges;
488 disjoint_sets< vertex_to_vsize_map_t, vertex_to_vertex_map_t > ds;
489 };
490
491 //***************************************************************************
492 //***************************************************************************
493 // Initial Matching Functors
494 //***************************************************************************
495 //***************************************************************************
496
497 template < typename Graph, typename MateMap > struct greedy_matching
498 {
499 typedef
500 typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
501 typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
502 typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t;
503 typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t;
504
find_matchingboost::greedy_matching505 static void find_matching(const Graph& g, MateMap mate)
506 {
507 vertex_iterator_t vi, vi_end;
508 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
509 put(mate, *vi, graph_traits< Graph >::null_vertex());
510
511 edge_iterator_t ei, ei_end;
512 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
513 {
514 edge_descriptor_t e = *ei;
515 vertex_descriptor_t u = source(e, g);
516 vertex_descriptor_t v = target(e, g);
517
518 if (u != v && get(mate, u) == get(mate, v))
519 // only way equality can hold is if
520 // mate[u] == mate[v] == null_vertex
521 {
522 put(mate, u, v);
523 put(mate, v, u);
524 }
525 }
526 }
527 };
528
529 template < typename Graph, typename MateMap > struct extra_greedy_matching
530 {
531 // The "extra greedy matching" is formed by repeating the
532 // following procedure as many times as possible: Choose the
533 // unmatched vertex v of minimum non-zero degree. Choose the
534 // neighbor w of v which is unmatched and has minimum degree over
535 // all of v's neighbors. Add (u,v) to the matching. Ties for
536 // either choice are broken arbitrarily. This procedure takes time
537 // O(m log n), where m is the number of edges in the graph and n
538 // is the number of vertices.
539
540 typedef
541 typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
542 typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
543 typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t;
544 typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t;
545 typedef std::pair< vertex_descriptor_t, vertex_descriptor_t > vertex_pair_t;
546
547 struct select_first
548 {
select_vertexboost::extra_greedy_matching::select_first549 inline static vertex_descriptor_t select_vertex(const vertex_pair_t p)
550 {
551 return p.first;
552 }
553 };
554
555 struct select_second
556 {
select_vertexboost::extra_greedy_matching::select_second557 inline static vertex_descriptor_t select_vertex(const vertex_pair_t p)
558 {
559 return p.second;
560 }
561 };
562
563 template < class PairSelector > class less_than_by_degree
564 {
565 public:
less_than_by_degree(const Graph & g)566 less_than_by_degree(const Graph& g) : m_g(g) {}
operator ()(const vertex_pair_t x,const vertex_pair_t y)567 bool operator()(const vertex_pair_t x, const vertex_pair_t y)
568 {
569 return out_degree(PairSelector::select_vertex(x), m_g)
570 < out_degree(PairSelector::select_vertex(y), m_g);
571 }
572
573 private:
574 const Graph& m_g;
575 };
576
find_matchingboost::extra_greedy_matching577 static void find_matching(const Graph& g, MateMap mate)
578 {
579 typedef std::vector<
580 std::pair< vertex_descriptor_t, vertex_descriptor_t > >
581 directed_edges_vector_t;
582
583 directed_edges_vector_t edge_list;
584 vertex_iterator_t vi, vi_end;
585 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
586 put(mate, *vi, graph_traits< Graph >::null_vertex());
587
588 edge_iterator_t ei, ei_end;
589 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
590 {
591 edge_descriptor_t e = *ei;
592 vertex_descriptor_t u = source(e, g);
593 vertex_descriptor_t v = target(e, g);
594 if (u == v)
595 continue;
596 edge_list.push_back(std::make_pair(u, v));
597 edge_list.push_back(std::make_pair(v, u));
598 }
599
600 // sort the edges by the degree of the target, then (using a
601 // stable sort) by degree of the source
602 std::sort(edge_list.begin(), edge_list.end(),
603 less_than_by_degree< select_second >(g));
604 std::stable_sort(edge_list.begin(), edge_list.end(),
605 less_than_by_degree< select_first >(g));
606
607 // construct the extra greedy matching
608 for (typename directed_edges_vector_t::const_iterator itr
609 = edge_list.begin();
610 itr != edge_list.end(); ++itr)
611 {
612 if (get(mate, itr->first) == get(mate, itr->second))
613 // only way equality can hold is if mate[itr->first] ==
614 // mate[itr->second] == null_vertex
615 {
616 put(mate, itr->first, itr->second);
617 put(mate, itr->second, itr->first);
618 }
619 }
620 }
621 };
622
623 template < typename Graph, typename MateMap > struct empty_matching
624 {
625 typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
626
find_matchingboost::empty_matching627 static void find_matching(const Graph& g, MateMap mate)
628 {
629 vertex_iterator_t vi, vi_end;
630 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
631 put(mate, *vi, graph_traits< Graph >::null_vertex());
632 }
633 };
634
635 //***************************************************************************
636 //***************************************************************************
637 // Matching Verifiers
638 //***************************************************************************
639 //***************************************************************************
640
641 namespace detail
642 {
643
644 template < typename SizeType >
645 class odd_components_counter : public dfs_visitor<>
646 // This depth-first search visitor will count the number of connected
647 // components with an odd number of vertices. It's used by
648 // maximum_matching_verifier.
649 {
650 public:
odd_components_counter(SizeType & c_count)651 odd_components_counter(SizeType& c_count) : m_count(c_count)
652 {
653 m_count = 0;
654 }
655
start_vertex(Vertex,Graph &)656 template < class Vertex, class Graph > void start_vertex(Vertex, Graph&)
657 {
658 m_parity = false;
659 }
660
661 template < class Vertex, class Graph >
discover_vertex(Vertex,Graph &)662 void discover_vertex(Vertex, Graph&)
663 {
664 m_parity = !m_parity;
665 m_parity ? ++m_count : --m_count;
666 }
667
668 protected:
669 SizeType& m_count;
670
671 private:
672 bool m_parity;
673 };
674
675 } // namespace detail
676
677 template < typename Graph, typename MateMap,
678 typename VertexIndexMap = dummy_property_map >
679 struct no_matching_verifier
680 {
verify_matchingboost::no_matching_verifier681 inline static bool verify_matching(const Graph&, MateMap, VertexIndexMap)
682 {
683 return true;
684 }
685 };
686
687 template < typename Graph, typename MateMap, typename VertexIndexMap >
688 struct maximum_cardinality_matching_verifier
689 {
690
691 template < typename X > struct map_vertex_to_
692 {
693 typedef boost::iterator_property_map<
694 typename std::vector< X >::iterator, VertexIndexMap >
695 type;
696 };
697
698 typedef
699 typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
700 typedef typename graph_traits< Graph >::vertices_size_type v_size_t;
701 typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
702 typedef typename map_vertex_to_< int >::type vertex_to_int_map_t;
703 typedef typename map_vertex_to_< vertex_descriptor_t >::type
704 vertex_to_vertex_map_t;
705
706 template < typename VertexStateMap > struct non_odd_vertex
707 {
708 // this predicate is used to create a filtered graph that
709 // excludes vertices labeled "graph::detail::V_ODD"
non_odd_vertexboost::maximum_cardinality_matching_verifier::non_odd_vertex710 non_odd_vertex() : vertex_state(0) {}
711
non_odd_vertexboost::maximum_cardinality_matching_verifier::non_odd_vertex712 non_odd_vertex(VertexStateMap* arg_vertex_state)
713 : vertex_state(arg_vertex_state)
714 {
715 }
716
operator ()boost::maximum_cardinality_matching_verifier::non_odd_vertex717 template < typename Vertex > bool operator()(const Vertex& v) const
718 {
719 BOOST_ASSERT(vertex_state);
720 return get(*vertex_state, v) != graph::detail::V_ODD;
721 }
722
723 VertexStateMap* vertex_state;
724 };
725
verify_matchingboost::maximum_cardinality_matching_verifier726 static bool verify_matching(const Graph& g, MateMap mate, VertexIndexMap vm)
727 {
728 // For any graph G, let o(G) be the number of connected
729 // components in G of odd size. For a subset S of G's vertex set
730 // V(G), let (G - S) represent the subgraph of G induced by
731 // removing all vertices in S from G. Let M(G) be the size of the
732 // maximum cardinality matching in G. Then the Tutte-Berge
733 // formula guarantees that
734 //
735 // 2 * M(G) = min ( |V(G)| + |U| + o(G - U) )
736 //
737 // where the minimum is taken over all subsets U of
738 // V(G). Edmonds' algorithm finds a set U that achieves the
739 // minimum in the above formula, namely the vertices labeled
740 //"ODD." This function runs one iteration of Edmonds' algorithm
741 // to find U, then verifies that the size of the matching given
742 // by mate satisfies the Tutte-Berge formula.
743
744 // first, make sure it's a valid matching
745 if (!is_a_matching(g, mate, vm))
746 return false;
747
748 // We'll try to augment the matching once. This serves two
749 // purposes: first, if we find some augmenting path, the matching
750 // is obviously non-maximum. Second, running edmonds' algorithm
751 // on a graph with no augmenting path will create the
752 // Edmonds-Gallai decomposition that we need as a certificate of
753 // maximality - we can get it by looking at the vertex_state map
754 // that results.
755 edmonds_augmenting_path_finder< Graph, MateMap, VertexIndexMap >
756 augmentor(g, mate, vm);
757 if (augmentor.augment_matching())
758 return false;
759
760 std::vector< int > vertex_state_vector(num_vertices(g));
761 vertex_to_int_map_t vertex_state(vertex_state_vector.begin(), vm);
762 augmentor.get_vertex_state_map(vertex_state);
763
764 // count the number of graph::detail::V_ODD vertices
765 v_size_t num_odd_vertices = 0;
766 vertex_iterator_t vi, vi_end;
767 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
768 if (vertex_state[*vi] == graph::detail::V_ODD)
769 ++num_odd_vertices;
770
771 // count the number of connected components with odd cardinality
772 // in the graph without graph::detail::V_ODD vertices
773 non_odd_vertex< vertex_to_int_map_t > filter(&vertex_state);
774 filtered_graph< Graph, keep_all, non_odd_vertex< vertex_to_int_map_t > >
775 fg(g, keep_all(), filter);
776
777 v_size_t num_odd_components;
778 detail::odd_components_counter< v_size_t > occ(num_odd_components);
779 depth_first_search(fg, visitor(occ).vertex_index_map(vm));
780
781 if (2 * matching_size(g, mate, vm)
782 == num_vertices(g) + num_odd_vertices - num_odd_components)
783 return true;
784 else
785 return false;
786 }
787 };
788
789 template < typename Graph, typename MateMap, typename VertexIndexMap,
790 template < typename, typename, typename > class AugmentingPathFinder,
791 template < typename, typename > class InitialMatchingFinder,
792 template < typename, typename, typename > class MatchingVerifier >
matching(const Graph & g,MateMap mate,VertexIndexMap vm)793 bool matching(const Graph& g, MateMap mate, VertexIndexMap vm)
794 {
795
796 InitialMatchingFinder< Graph, MateMap >::find_matching(g, mate);
797
798 AugmentingPathFinder< Graph, MateMap, VertexIndexMap > augmentor(
799 g, mate, vm);
800 bool not_maximum_yet = true;
801 while (not_maximum_yet)
802 {
803 not_maximum_yet = augmentor.augment_matching();
804 }
805 augmentor.get_current_matching(mate);
806
807 return MatchingVerifier< Graph, MateMap, VertexIndexMap >::verify_matching(
808 g, mate, vm);
809 }
810
811 template < typename Graph, typename MateMap, typename VertexIndexMap >
checked_edmonds_maximum_cardinality_matching(const Graph & g,MateMap mate,VertexIndexMap vm)812 inline bool checked_edmonds_maximum_cardinality_matching(
813 const Graph& g, MateMap mate, VertexIndexMap vm)
814 {
815 return matching< Graph, MateMap, VertexIndexMap,
816 edmonds_augmenting_path_finder, extra_greedy_matching,
817 maximum_cardinality_matching_verifier >(g, mate, vm);
818 }
819
820 template < typename Graph, typename MateMap >
checked_edmonds_maximum_cardinality_matching(const Graph & g,MateMap mate)821 inline bool checked_edmonds_maximum_cardinality_matching(
822 const Graph& g, MateMap mate)
823 {
824 return checked_edmonds_maximum_cardinality_matching(
825 g, mate, get(vertex_index, g));
826 }
827
828 template < typename Graph, typename MateMap, typename VertexIndexMap >
edmonds_maximum_cardinality_matching(const Graph & g,MateMap mate,VertexIndexMap vm)829 inline void edmonds_maximum_cardinality_matching(
830 const Graph& g, MateMap mate, VertexIndexMap vm)
831 {
832 matching< Graph, MateMap, VertexIndexMap, edmonds_augmenting_path_finder,
833 extra_greedy_matching, no_matching_verifier >(g, mate, vm);
834 }
835
836 template < typename Graph, typename MateMap >
edmonds_maximum_cardinality_matching(const Graph & g,MateMap mate)837 inline void edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate)
838 {
839 edmonds_maximum_cardinality_matching(g, mate, get(vertex_index, g));
840 }
841
842 } // namespace boost
843
844 #endif // BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP
845