• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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