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