|
1 // -*- C++ -*- |
|
2 #ifndef HUGO_MAX_MATCHING_H |
|
3 #define HUGO_MAX_MATCHING_H |
|
4 |
|
5 ///\ingroup galgs |
|
6 ///\file |
|
7 ///\brief Maximum matching algorithm. |
|
8 |
|
9 #include <queue> |
|
10 |
|
11 #include <invalid.h> |
|
12 #include <unionfind.h> |
|
13 |
|
14 namespace hugo { |
|
15 |
|
16 /// \addtogroup galgs |
|
17 /// @{ |
|
18 |
|
19 ///Maximum matching algorithms class. |
|
20 |
|
21 ///This class provides Edmonds' alternating forest matching |
|
22 ///algorithm. The starting matching (if any) can be passed to the |
|
23 ///algorithm using read-in functions \ref readNMapNode, \ref |
|
24 ///readNMapEdge or \ref readEMapBool depending on the container. The |
|
25 ///resulting maximum matching can be attained by write-out functions |
|
26 ///\ref writeNMapNode, \ref writeNMapEdge or \ref writeEMapBool |
|
27 ///depending on the preferred container. |
|
28 |
|
29 ///The dual side of a mathcing is a map of the nodes to |
|
30 ///MaxMatching::pos_enum, having values D, A and C showing the |
|
31 ///Gallai-Edmonds decomposition of the graph. The nodes in D induce |
|
32 ///a graph with factor-critical components, the nodes in A form the |
|
33 ///barrier, and the nodes in C induce a graph having a perfect |
|
34 ///matching. This decomposition can be attained by calling \ref |
|
35 ///writePos after running the algorithm. Before subsequent runs, |
|
36 ///the function \ref resetPos() must be called. |
|
37 |
|
38 ///\param Graph The undirected graph type the algorithm runs on. |
|
39 |
|
40 ///\author Jacint Szabo |
|
41 template <typename Graph> |
|
42 class MaxMatching { |
|
43 typedef typename Graph::Node Node; |
|
44 typedef typename Graph::Edge Edge; |
|
45 typedef typename Graph::EdgeIt EdgeIt; |
|
46 typedef typename Graph::NodeIt NodeIt; |
|
47 typedef typename Graph::OutEdgeIt OutEdgeIt; |
|
48 |
|
49 typedef UnionFindEnum<Node, Graph::template NodeMap> UFE; |
|
50 |
|
51 public: |
|
52 |
|
53 ///Indicates the Gallai-Edmonds decomposition of the graph. |
|
54 |
|
55 ///Indicates the Gallai-Edmonds decomposition of the graph, which |
|
56 ///shows an upper bound on the size of a maximum matching. The |
|
57 ///nodes with pos_enum D induce a graph with factor-critical |
|
58 ///components, the nodes in A form the canonical barrier, and the |
|
59 ///nodes in C induce a graph having a perfect matching. |
|
60 enum pos_enum { |
|
61 D=0, |
|
62 A=1, |
|
63 C=2 |
|
64 }; |
|
65 |
|
66 private: |
|
67 |
|
68 const Graph& G; |
|
69 typename Graph::template NodeMap<Node> mate; |
|
70 typename Graph::template NodeMap<pos_enum> position; |
|
71 |
|
72 public: |
|
73 |
|
74 MaxMatching(Graph& _G) : G(_G), mate(_G,INVALID), position(_G,C) {} |
|
75 |
|
76 ///Runs Edmonds' algorithm. |
|
77 |
|
78 ///Runs Edmonds' algorithm for sparse graphs (edgeNum >= |
|
79 ///2*nodeNum), and a heuristical Edmonds' algorithm with a |
|
80 ///heuristic of postponing shrinks for dense graphs. \pre Before |
|
81 ///the subsequent calls \ref resetPos must be called. |
|
82 void run(); |
|
83 |
|
84 ///Runs Edmonds' algorithm. |
|
85 |
|
86 ///If heur=0 it runs Edmonds' algorithm. If heur=1 it runs |
|
87 ///Edmonds' algorithm with a heuristic of postponing shrinks, |
|
88 ///giving a faster algorithm for dense graphs. \pre Before the |
|
89 ///subsequent calls \ref resetPos must be called. |
|
90 void runEdmonds( int heur ); |
|
91 |
|
92 ///Finds a greedy matching starting from the actual matching. |
|
93 |
|
94 ///Starting form the actual matching stored, it finds a maximal |
|
95 ///greedy matching. |
|
96 void greedyMatching(); |
|
97 |
|
98 ///Returns the size of the actual matching stored. |
|
99 |
|
100 ///Returns the size of the actual matching stored. After \ref |
|
101 ///run() it returns the size of a maximum matching in the graph. |
|
102 int size(); |
|
103 |
|
104 ///Resets the map storing the Gallai-Edmonds decomposition. |
|
105 |
|
106 ///Resets the map storing the Gallai-Edmonds decomposition of the |
|
107 ///graph, making it possible to run the algorithm. Must be called |
|
108 ///before all runs of the Edmonds algorithm, except for the first |
|
109 ///run. |
|
110 void resetPos(); |
|
111 |
|
112 ///Resets the actual matching to the empty matching. |
|
113 |
|
114 ///Resets the actual matching to the empty matching. |
|
115 /// |
|
116 void resetMatching(); |
|
117 |
|
118 ///Reads a matching from a \c Node map of \c Nodes. |
|
119 |
|
120 ///Reads a matching from a \c Node map of \c Nodes. This map must be \e |
|
121 ///symmetric, i.e. if \c map[u]=v then \c map[v]=u must hold, and |
|
122 ///now \c uv is an edge of the matching. |
|
123 template<typename NMapN> |
|
124 void readNMapNode(NMapN& map) { |
|
125 NodeIt v; |
|
126 for( G.first(v); G.valid(v); G.next(v)) { |
|
127 mate.set(v,map[v]); |
|
128 } |
|
129 } |
|
130 |
|
131 ///Writes the stored matching to a \c Node map of \c Nodes. |
|
132 |
|
133 ///Writes the stored matching to a \c Node map of \c Nodes. The |
|
134 ///resulting map will be \e symmetric, i.e. if \c map[u]=v then \c |
|
135 ///map[v]=u will hold, and now \c uv is an edge of the matching. |
|
136 template<typename NMapN> |
|
137 void writeNMapNode(NMapN& map) { |
|
138 NodeIt v; |
|
139 for( G.first(v); G.valid(v); G.next(v)) { |
|
140 map.set(v,mate[v]); |
|
141 } |
|
142 } |
|
143 |
|
144 ///Reads a matching from a \c Node map of \c Edges. |
|
145 |
|
146 ///Reads a matching from a \c Node map of incident \c Edges. This |
|
147 ///map must have the property that if \c G.bNode(map[u])=v then \c |
|
148 ///G.bNode(map[v])=u must hold, and now this edge is an edge of |
|
149 ///the matching. |
|
150 template<typename NMapE> |
|
151 void readNMapEdge(NMapE& map) { |
|
152 NodeIt v; |
|
153 for( G.first(v); G.valid(v); G.next(v)) { |
|
154 Edge e=map[v]; |
|
155 if ( G.valid(e) ) |
|
156 G.tail(e) == v ? mate.set(v,G.head(e)) : mate.set(v,G.tail(e)); |
|
157 } |
|
158 } |
|
159 |
|
160 ///Writes the matching stored to a \c Node map of \c Edges. |
|
161 |
|
162 ///Writes the stored matching to a \c Node map of incident \c |
|
163 ///Edges. This map will have the property that if \c |
|
164 ///G.bNode(map[u])=v then \c G.bNode(map[v])=u holds, and now this |
|
165 ///edge is an edge of the matching. |
|
166 template<typename NMapE> |
|
167 void writeNMapEdge(NMapE& map) { |
|
168 typename Graph::template NodeMap<bool> todo(G,false); |
|
169 NodeIt v; |
|
170 for( G.first(v); G.valid(v); G.next(v)) { |
|
171 if ( mate[v]!=INVALID ) todo.set(v,true); |
|
172 } |
|
173 NodeIt e; |
|
174 for( G.first(e); G.valid(e); G.next(e)) { |
|
175 if ( todo[G.head(e)] && todo[G.tail(e)] ) { |
|
176 Node u=G.tail(e); |
|
177 Node v=G.head(e); |
|
178 if ( mate[u]=v && mate[v]=u ) { |
|
179 map.set(u,e); |
|
180 map.set(v,e); |
|
181 todo.set(u,false); |
|
182 todo.set(v,false); |
|
183 } |
|
184 } |
|
185 } |
|
186 } |
|
187 |
|
188 ///Reads a matching from an \c Edge map of \c bools. |
|
189 |
|
190 ///Reads a matching from an \c Edge map of \c bools. This map must |
|
191 ///have the property that there are no two adjacent edges \c e, \c |
|
192 ///f with \c map[e]=map[f]=true. The edges \c e with \c |
|
193 ///map[e]=true form the matching. |
|
194 template<typename EMapB> |
|
195 void readEMapBool(EMapB& map) { |
|
196 EdgeIt e; |
|
197 for( G.first(e); G.valid(e); G.next(e)) { |
|
198 if ( G.valid(e) ) { |
|
199 Node u=G.tail(e); |
|
200 Node v=G.head(e); |
|
201 mate.set(u,v); |
|
202 mate.set(v,u); |
|
203 } |
|
204 } |
|
205 } |
|
206 |
|
207 |
|
208 ///Writes the matching stored to an \c Edge map of \c bools. |
|
209 |
|
210 ///Writes the matching stored to an \c Edge map of \c bools. This |
|
211 ///map will have the property that there are no two adjacent edges |
|
212 ///\c e, \c f with \c map[e]=map[f]=true. The edges \c e with \c |
|
213 ///map[e]=true form the matching. |
|
214 template<typename EMapB> |
|
215 void writeEMapBool(EMapB& map) { |
|
216 typename Graph::template NodeMap<bool> todo(G,false); |
|
217 NodeIt v; |
|
218 for( G.first(v); G.valid(v); G.next(v)) { |
|
219 if ( mate[v]!=INVALID ) todo.set(v,true); |
|
220 } |
|
221 |
|
222 NodeIt e; |
|
223 for( G.first(e); G.valid(e); G.next(e)) { |
|
224 map.set(e,false); |
|
225 if ( todo[G.head(e)] && todo[G.tail(e)] ) { |
|
226 Node u=G.tail(e); |
|
227 Node v=G.head(e); |
|
228 if ( mate[u]=v && mate[v]=u ) { |
|
229 map.set(e,true); |
|
230 todo.set(u,false); |
|
231 todo.set(v,false); |
|
232 } |
|
233 } |
|
234 } |
|
235 } |
|
236 |
|
237 ///Writes the canonical decomposition of the graph after running |
|
238 ///the algorithm. |
|
239 |
|
240 ///After calling any run methods of the class, and before calling |
|
241 ///\ref resetPos(), it writes the Gallai-Edmonds canonical |
|
242 ///decomposition of the graph. \c map must be a node map of \ref pos_enum 's. |
|
243 template<typename NMapEnum> |
|
244 void writePos(NMapEnum& map) { |
|
245 NodeIt v; |
|
246 for( G.first(v); G.valid(v); G.next(v)) map.set(v,position[v]); |
|
247 } |
|
248 |
|
249 private: |
|
250 |
|
251 void lateShrink(Node v, typename Graph::template NodeMap<Node>& ear, |
|
252 UFE& blossom, UFE& tree); |
|
253 |
|
254 void normShrink(Node v, typename Graph::NodeMap<Node>& ear, |
|
255 UFE& blossom, UFE& tree); |
|
256 |
|
257 bool noShrinkStep(Node x, typename Graph::NodeMap<Node>& ear, |
|
258 UFE& blossom, UFE& tree, std::queue<Node>& Q); |
|
259 |
|
260 void shrinkStep(Node& top, Node& middle, Node& bottom, typename Graph::NodeMap<Node>& ear, |
|
261 UFE& blossom, UFE& tree, std::queue<Node>& Q); |
|
262 |
|
263 void augment(Node x, typename Graph::NodeMap<Node>& ear, |
|
264 UFE& blossom, UFE& tree); |
|
265 |
|
266 }; |
|
267 |
|
268 |
|
269 // ********************************************************************** |
|
270 // IMPLEMENTATIONS |
|
271 // ********************************************************************** |
|
272 |
|
273 |
|
274 template <typename Graph> |
|
275 void MaxMatching<Graph>::run() { |
|
276 if ( G.edgeNum() > 2*G.nodeNum() ) { |
|
277 greedyMatching(); |
|
278 runEdmonds(1); |
|
279 } else runEdmonds(0); |
|
280 } |
|
281 |
|
282 template <typename Graph> |
|
283 void MaxMatching<Graph>::runEdmonds( int heur=1 ) { |
|
284 |
|
285 typename Graph::template NodeMap<Node> ear(G,INVALID); |
|
286 //undefined for the base nodes of the blossoms (i.e. for the |
|
287 //representative elements of UFE blossom) and for the nodes in C |
|
288 |
|
289 typename UFE::MapType blossom_base(G); |
|
290 UFE blossom(blossom_base); |
|
291 typename UFE::MapType tree_base(G); |
|
292 UFE tree(tree_base); |
|
293 |
|
294 NodeIt v; |
|
295 for( G.first(v); G.valid(v); G.next(v) ) { |
|
296 if ( position[v]==C && mate[v]==INVALID ) { |
|
297 blossom.insert(v); |
|
298 tree.insert(v); |
|
299 position.set(v,D); |
|
300 if ( heur == 1 ) lateShrink( v, ear, blossom, tree ); |
|
301 else normShrink( v, ear, blossom, tree ); |
|
302 } |
|
303 } |
|
304 } |
|
305 |
|
306 template <typename Graph> |
|
307 void MaxMatching<Graph>::lateShrink(Node v, typename Graph::template NodeMap<Node>& ear, |
|
308 UFE& blossom, UFE& tree) { |
|
309 |
|
310 std::queue<Node> Q; //queue of the totally unscanned nodes |
|
311 Q.push(v); |
|
312 std::queue<Node> R; |
|
313 //queue of the nodes which must be scanned for a possible shrink |
|
314 |
|
315 while ( !Q.empty() ) { |
|
316 Node x=Q.front(); |
|
317 Q.pop(); |
|
318 if ( noShrinkStep( x, ear, blossom, tree, Q ) ) return; |
|
319 else R.push(x); |
|
320 } |
|
321 |
|
322 while ( !R.empty() ) { |
|
323 Node x=R.front(); |
|
324 R.pop(); |
|
325 |
|
326 OutEdgeIt e; |
|
327 for( G.first(e,x); G.valid(e); G.next(e) ) { |
|
328 Node y=G.bNode(e); |
|
329 |
|
330 if ( position[y] == D && blossom.find(x) != blossom.find(y) ) { |
|
331 //x and y must be in the same tree |
|
332 |
|
333 typename Graph::template NodeMap<bool> path(G,false); |
|
334 |
|
335 Node b=blossom.find(x); |
|
336 path.set(b,true); |
|
337 b=mate[b]; |
|
338 while ( b!=INVALID ) { |
|
339 b=blossom.find(ear[b]); |
|
340 path.set(b,true); |
|
341 b=mate[b]; |
|
342 } //going till the root |
|
343 |
|
344 Node top=y; |
|
345 Node middle=blossom.find(top); |
|
346 Node bottom=x; |
|
347 while ( !path[middle] ) |
|
348 shrinkStep(top, middle, bottom, ear, blossom, tree, Q); |
|
349 |
|
350 Node base=middle; |
|
351 top=x; |
|
352 middle=blossom.find(top); |
|
353 bottom=y; |
|
354 Node blossom_base=blossom.find(base); |
|
355 while ( middle!=blossom_base ) |
|
356 shrinkStep(top, middle, bottom, ear, blossom, tree, Q); |
|
357 |
|
358 blossom.makeRep(base); |
|
359 } // if shrink is needed |
|
360 |
|
361 while ( !Q.empty() ) { |
|
362 Node x=Q.front(); |
|
363 Q.pop(); |
|
364 if ( noShrinkStep(x, ear, blossom, tree, Q) ) return; |
|
365 else R.push(x); |
|
366 } |
|
367 } //for e |
|
368 } // while ( !R.empty() ) |
|
369 } |
|
370 |
|
371 template <typename Graph> |
|
372 void MaxMatching<Graph>::normShrink(Node v, typename Graph::NodeMap<Node>& ear, |
|
373 UFE& blossom, UFE& tree) { |
|
374 |
|
375 std::queue<Node> Q; //queue of the unscanned nodes |
|
376 Q.push(v); |
|
377 while ( !Q.empty() ) { |
|
378 Node x=Q.front(); |
|
379 Q.pop(); |
|
380 |
|
381 OutEdgeIt e; |
|
382 for( G.first(e,x); G.valid(e); G.next(e) ) { |
|
383 Node y=G.bNode(e); |
|
384 |
|
385 switch ( position[y] ) { |
|
386 case D: //x and y must be in the same tree |
|
387 if ( blossom.find(x) != blossom.find(y) ) { //shrink |
|
388 typename Graph::template NodeMap<bool> path(G,false); |
|
389 |
|
390 Node b=blossom.find(x); |
|
391 path.set(b,true); |
|
392 b=mate[b]; |
|
393 while ( b!=INVALID ) { |
|
394 b=blossom.find(ear[b]); |
|
395 path.set(b,true); |
|
396 b=mate[b]; |
|
397 } //going till the root |
|
398 |
|
399 Node top=y; |
|
400 Node middle=blossom.find(top); |
|
401 Node bottom=x; |
|
402 while ( !path[middle] ) |
|
403 shrinkStep(top, middle, bottom, ear, blossom, tree, Q); |
|
404 |
|
405 Node base=middle; |
|
406 top=x; |
|
407 middle=blossom.find(top); |
|
408 bottom=y; |
|
409 Node blossom_base=blossom.find(base); |
|
410 while ( middle!=blossom_base ) |
|
411 shrinkStep(top, middle, bottom, ear, blossom, tree, Q); |
|
412 |
|
413 blossom.makeRep(base); |
|
414 } |
|
415 break; |
|
416 case C: |
|
417 if ( mate[y]!=INVALID ) { //grow |
|
418 ear.set(y,x); |
|
419 Node w=mate[y]; |
|
420 blossom.insert(w); |
|
421 position.set(y,A); |
|
422 position.set(w,D); |
|
423 tree.insert(y); |
|
424 tree.insert(w); |
|
425 tree.join(y,blossom.find(x)); |
|
426 tree.join(w,y); |
|
427 Q.push(w); |
|
428 } else { //augment |
|
429 augment(x, ear, blossom, tree); |
|
430 mate.set(x,y); |
|
431 mate.set(y,x); |
|
432 return; |
|
433 } //if |
|
434 break; |
|
435 default: break; |
|
436 } |
|
437 } |
|
438 } |
|
439 } |
|
440 |
|
441 template <typename Graph> |
|
442 void MaxMatching<Graph>::greedyMatching() { |
|
443 NodeIt v; |
|
444 for( G.first(v); G.valid(v); G.next(v) ) |
|
445 if ( mate[v]==INVALID ) { |
|
446 OutEdgeIt e; |
|
447 for( G.first(e,v); G.valid(e); G.next(e) ) { |
|
448 Node y=G.bNode(e); |
|
449 if ( mate[y]==INVALID && y!=v ) { |
|
450 mate.set(v,y); |
|
451 mate.set(y,v); |
|
452 break; |
|
453 } |
|
454 } |
|
455 } |
|
456 } |
|
457 |
|
458 template <typename Graph> |
|
459 int MaxMatching<Graph>::size() { |
|
460 int s=0; |
|
461 NodeIt v; |
|
462 for(G.first(v); G.valid(v); G.next(v) ) { |
|
463 if ( G.valid(mate[v]) ) { |
|
464 ++s; |
|
465 } |
|
466 } |
|
467 return (int)s/2; |
|
468 } |
|
469 |
|
470 template <typename Graph> |
|
471 void MaxMatching<Graph>::resetPos() { |
|
472 NodeIt v; |
|
473 for( G.first(v); G.valid(v); G.next(v)) |
|
474 position.set(v,C); |
|
475 } |
|
476 |
|
477 template <typename Graph> |
|
478 void MaxMatching<Graph>::resetMatching() { |
|
479 NodeIt v; |
|
480 for( G.first(v); G.valid(v); G.next(v)) |
|
481 mate.set(v,INVALID); |
|
482 } |
|
483 |
|
484 template <typename Graph> |
|
485 bool MaxMatching<Graph>::noShrinkStep(Node x, typename Graph::NodeMap<Node>& ear, |
|
486 UFE& blossom, UFE& tree, std::queue<Node>& Q) { |
|
487 OutEdgeIt e; |
|
488 for( G.first(e,x); G.valid(e); G.next(e) ) { |
|
489 Node y=G.bNode(e); |
|
490 |
|
491 if ( position[y]==C ) { |
|
492 if ( mate[y]!=INVALID ) { //grow |
|
493 ear.set(y,x); |
|
494 Node w=mate[y]; |
|
495 blossom.insert(w); |
|
496 position.set(y,A); |
|
497 position.set(w,D); |
|
498 tree.insert(y); |
|
499 tree.insert(w); |
|
500 tree.join(y,blossom.find(x)); |
|
501 tree.join(w,y); |
|
502 Q.push(w); |
|
503 } else { //augment |
|
504 augment(x, ear, blossom, tree); |
|
505 mate.set(x,y); |
|
506 mate.set(y,x); |
|
507 return true; |
|
508 } |
|
509 } |
|
510 } |
|
511 return false; |
|
512 } |
|
513 |
|
514 template <typename Graph> |
|
515 void MaxMatching<Graph>::shrinkStep(Node& top, Node& middle, Node& bottom, typename Graph::NodeMap<Node>& ear, |
|
516 UFE& blossom, UFE& tree, std::queue<Node>& Q) { |
|
517 ear.set(top,bottom); |
|
518 Node t=top; |
|
519 while ( t!=middle ) { |
|
520 Node u=mate[t]; |
|
521 t=ear[u]; |
|
522 ear.set(t,u); |
|
523 } |
|
524 bottom=mate[middle]; |
|
525 position.set(bottom,D); |
|
526 Q.push(bottom); |
|
527 top=ear[bottom]; |
|
528 Node oldmiddle=middle; |
|
529 middle=blossom.find(top); |
|
530 tree.erase(bottom); |
|
531 tree.erase(oldmiddle); |
|
532 blossom.insert(bottom); |
|
533 blossom.join(bottom, oldmiddle); |
|
534 blossom.join(top, oldmiddle); |
|
535 } |
|
536 |
|
537 template <typename Graph> |
|
538 void MaxMatching<Graph>::augment(Node x, typename Graph::NodeMap<Node>& ear, |
|
539 UFE& blossom, UFE& tree) { |
|
540 Node v=mate[x]; |
|
541 while ( G.valid(v) ) { |
|
542 |
|
543 Node u=ear[v]; |
|
544 mate.set(v,u); |
|
545 Node tmp=v; |
|
546 v=mate[u]; |
|
547 mate.set(u,tmp); |
|
548 } |
|
549 typename UFE::ItemIt it; |
|
550 for (tree.first(it,blossom.find(x)); tree.valid(it); tree.next(it)) { |
|
551 if ( position[it] == D ) { |
|
552 typename UFE::ItemIt b_it; |
|
553 for (blossom.first(b_it,it); blossom.valid(b_it); blossom.next(b_it)) { |
|
554 position.set( b_it ,C); |
|
555 } |
|
556 blossom.eraseClass(it); |
|
557 } else position.set( it ,C); |
|
558 } |
|
559 tree.eraseClass(x); |
|
560 } |
|
561 |
|
562 |
|
563 |
|
564 /// @} |
|
565 |
|
566 } //END OF NAMESPACE HUGO |
|
567 |
|
568 #endif //EDMONDS_H |