# HG changeset patch # User Balazs Dezso # Date 1540638048 -7200 # Node ID 8c567e298d7f3fad82cc66754f2fb6c4a420366b # Parent 4fd76139b69ec938db4d67ce0927ad5923647ed2 Paremeter to stop matching calculation when only single node is unmatched diff -r 4fd76139b69e -r 8c567e298d7f lemon/matching.h --- a/lemon/matching.h Sat Feb 17 23:44:32 2018 +0100 +++ b/lemon/matching.h Sat Oct 27 13:00:48 2018 +0200 @@ -115,7 +115,7 @@ NodeQueue _node_queue; int _process, _postpone, _last; - int _node_num; + int _node_num, _unmatched; private: @@ -179,6 +179,7 @@ extendOnArc(a); } else if ((*_status)[v] == UNMATCHED) { augmentOnArc(a); + --_unmatched; return; } } @@ -204,6 +205,7 @@ extendOnArc(b); } else if ((*_status)[x] == UNMATCHED) { augmentOnArc(b); + --_unmatched; return; } } @@ -228,6 +230,7 @@ extendOnArc(a); } else if ((*_status)[v] == UNMATCHED) { augmentOnArc(a); + --_unmatched; return; } } @@ -437,6 +440,7 @@ (*_matching)[n] = INVALID; (*_status)[n] = UNMATCHED; } + _unmatched = _node_num; } /// \brief Find an initial matching in a greedy way. @@ -448,6 +452,7 @@ (*_matching)[n] = INVALID; (*_status)[n] = UNMATCHED; } + _unmatched = _node_num; for (NodeIt n(_graph); n != INVALID; ++n) { if ((*_matching)[n] == INVALID) { for (OutArcIt a(_graph, n); a != INVALID ; ++a) { @@ -457,6 +462,7 @@ (*_status)[n] = MATCHED; (*_matching)[v] = _graph.oppositeArc(a); (*_status)[v] = MATCHED; + _unmatched -= 2; break; } } @@ -479,6 +485,7 @@ (*_matching)[n] = INVALID; (*_status)[n] = UNMATCHED; } + _unmatched = _node_num; for(EdgeIt e(_graph); e!=INVALID; ++e) { if (matching[e]) { @@ -491,6 +498,8 @@ if ((*_matching)[v] != INVALID) return false; (*_matching)[v] = _graph.direct(e, false); (*_status)[v] = MATCHED; + + _unmatched -= 2; } } return true; @@ -498,16 +507,20 @@ /// \brief Start Edmonds' algorithm /// - /// This function runs the original Edmonds' algorithm. + /// This function runs the original Edmonds' algorithm. If the + /// \c decomposition parameter is set to false, then the Gallai-Edmonds + /// decomposition is not computed. /// /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be /// called before using this function. - void startSparse() { - for(NodeIt n(_graph); n != INVALID; ++n) { + void startSparse(bool decomposition = true) { + int _unmatched_limit = decomposition ? 0 : 1; + for(NodeIt n(_graph); _unmatched > _unmatched_limit; ++n) { if ((*_status)[n] == UNMATCHED) { (*_blossom_rep)[_blossom_set->insert(n)] = n; _tree_set->insert(n); (*_status)[n] = EVEN; + --_unmatched; processSparse(n); } } @@ -517,16 +530,20 @@ /// for dense graphs /// /// This function runs Edmonds' algorithm with a heuristic of postponing - /// shrinks, therefore resulting in a faster algorithm for dense graphs. + /// shrinks, therefore resulting in a faster algorithm for dense graphs. If + /// the \c decomposition parameter is set to false, then the Gallai-Edmonds + /// decomposition is not computed. /// /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be /// called before using this function. - void startDense() { - for(NodeIt n(_graph); n != INVALID; ++n) { + void startDense(bool decomposition = true) { + int _unmatched_limit = decomposition ? 0 : 1; + for(NodeIt n(_graph); _unmatched > _unmatched_limit; ++n) { if ((*_status)[n] == UNMATCHED) { (*_blossom_rep)[_blossom_set->insert(n)] = n; _tree_set->insert(n); (*_status)[n] = EVEN; + --_unmatched; processDense(n); } } @@ -536,15 +553,18 @@ /// \brief Run Edmonds' algorithm /// /// This function runs Edmonds' algorithm. An additional heuristic of - /// postponing shrinks is used for relatively dense graphs - /// (for which m>=2*n holds). - void run() { + /// postponing shrinks is used for relatively dense graphs (for which + /// m>=2*n holds). If the \c decomposition parameter is set to + /// false, then the Gallai-Edmonds decomposition is not computed. In some + /// cases, this can speed up the algorithm significantly, especially when a + /// maximum matching is computed in a dense graph with odd number of nodes. + void run(bool decomposition = true) { if (countEdges(_graph) < 2 * countNodes(_graph)) { greedyInit(); - startSparse(); + startSparse(decomposition); } else { init(); - startDense(); + startDense(decomposition); } } diff -r 4fd76139b69e -r 8c567e298d7f test/matching_test.cc --- a/test/matching_test.cc Sat Feb 17 23:44:32 2018 +0100 +++ b/test/matching_test.cc Sat Oct 27 13:00:48 2018 +0200 @@ -134,6 +134,9 @@ mat_test.startSparse(); mat_test.startDense(); mat_test.run(); + mat_test.startSparse(false); + mat_test.startDense(false); + mat_test.run(false); const_mat_test.matchingSize(); const_mat_test.matching(e); @@ -402,15 +405,83 @@ graphReader(graph, lgfs). edgeMap("weight", weight).run(); + int size; bool perfect; { MaxMatching mm(graph); mm.run(); checkMatching(graph, mm); + size = mm.matchingSize(); perfect = 2 * mm.matchingSize() == countNodes(graph); } { + MaxMatching mm(graph); + mm.init(); + mm.startSparse(); + checkMatching(graph, mm); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { + MaxMatching mm(graph); + mm.init(); + mm.startDense(); + checkMatching(graph, mm); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { + MaxMatching mm(graph); + mm.greedyInit(); + mm.startSparse(); + checkMatching(graph, mm); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { + MaxMatching mm(graph); + mm.greedyInit(); + mm.startDense(); + checkMatching(graph, mm); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { + MaxMatching mm(graph); + mm.run(false); + check(size == mm.matchingSize(), "Inconsistent max cardinality matching"); + } + + { + MaxMatching mm(graph); + mm.init(); + mm.startSparse(false); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { + MaxMatching mm(graph); + mm.init(); + mm.startDense(false); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { + MaxMatching mm(graph); + mm.greedyInit(); + mm.startSparse(false); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { + MaxMatching mm(graph); + mm.greedyInit(); + mm.startDense(false); + check(size == mm.matchingSize(), "Inconsistent matching size"); + } + + { MaxWeightedMatching mwm(graph, weight); mwm.run(); checkWeightedMatching(graph, weight, mwm);