[Lemon-commits] Balazs Dezso: Several improvements in maximum ma...
Lemon HG
hg at lemon.cs.elte.hu
Wed Oct 22 15:41:48 CEST 2008
details: http://lemon.cs.elte.hu/hg/lemon/rev/91d63b8b1a4c
changeset: 339:91d63b8b1a4c
user: Balazs Dezso <deba [at] inf.elte.hu>
date: Mon Oct 13 14:00:11 2008 +0200
description:
Several improvements in maximum matching algorithms
- The interface of MaxMatching is changed to be similar to the
weighted algorithms
- The internal data structure (the queue implementation and the
matching map) is changed in the MaxMatching algorithm, which
provides better runtime properties
- The Blossom iterators are changed slightly in the weighted matching
algorithms
- Several documentation improvments
- The test files are merged
diffstat:
5 files changed, 874 insertions(+), 1005 deletions(-)
lemon/max_matching.h | 1219 +++++++++++++++++-------------------
test/CMakeLists.txt | 1
test/Makefile.am | 2
test/max_matching_test.cc | 407 +++++++-----
test/max_weighted_matching_test.cc | 250 -------
diffs (truncated from 2328 to 300 lines):
diff -r 64ad48007fb2 -r 91d63b8b1a4c lemon/max_matching.h
--- a/lemon/max_matching.h Mon Oct 13 13:56:00 2008 +0200
+++ b/lemon/max_matching.h Mon Oct 13 14:00:11 2008 +0200
@@ -31,76 +31,405 @@
///\ingroup matching
///\file
-///\brief Maximum matching algorithms in graph.
+///\brief Maximum matching algorithms in general graphs.
namespace lemon {
- ///\ingroup matching
+ /// \ingroup matching
///
- ///\brief Edmonds' alternating forest maximum matching algorithm.
+ /// \brief Edmonds' alternating forest maximum matching algorithm.
///
- ///This class provides Edmonds' alternating forest matching
- ///algorithm. The starting matching (if any) can be passed to the
- ///algorithm using some of init functions.
+ /// This class provides Edmonds' alternating forest matching
+ /// algorithm. The starting matching (if any) can be passed to the
+ /// algorithm using some of init functions.
///
- ///The dual side of a matching is a map of the nodes to
- ///MaxMatching::DecompType, having values \c D, \c A and \c C
- ///showing the Gallai-Edmonds decomposition of the digraph. The nodes
- ///in \c D induce a digraph with factor-critical components, the nodes
- ///in \c A form the barrier, and the nodes in \c C induce a digraph
- ///having a perfect matching. This decomposition can be attained by
- ///calling \c decomposition() after running the algorithm.
+ /// The dual side of a matching is a map of the nodes to
+ /// MaxMatching::Status, having values \c EVEN/D, \c ODD/A and \c
+ /// MATCHED/C showing the Gallai-Edmonds decomposition of the
+ /// graph. The nodes in \c EVEN/D induce a graph with
+ /// factor-critical components, the nodes in \c ODD/A form the
+ /// barrier, and the nodes in \c MATCHED/C induce a graph having a
+ /// perfect matching. The number of the fractor critical components
+ /// minus the number of barrier nodes is a lower bound on the
+ /// unmatched nodes, and if the matching is optimal this bound is
+ /// tight. This decomposition can be attained by calling \c
+ /// decomposition() after running the algorithm.
///
- ///\param Digraph The graph type the algorithm runs on.
- template <typename Graph>
+ /// \param _Graph The graph type the algorithm runs on.
+ template <typename _Graph>
class MaxMatching {
+ public:
- protected:
+ typedef _Graph Graph;
+ typedef typename Graph::template NodeMap<typename Graph::Arc>
+ MatchingMap;
+
+ ///\brief Indicates the Gallai-Edmonds decomposition of the graph.
+ ///
+ ///Indicates the Gallai-Edmonds decomposition of the graph, which
+ ///shows an upper bound on the size of a maximum matching. The
+ ///nodes with Status \c EVEN/D induce a graph with factor-critical
+ ///components, the nodes in \c ODD/A form the canonical barrier,
+ ///and the nodes in \c MATCHED/C induce a graph having a perfect
+ ///matching.
+ enum Status {
+ EVEN = 1, D = 1, MATCHED = 0, C = 0, ODD = -1, A = -1, UNMATCHED = -2
+ };
+
+ typedef typename Graph::template NodeMap<Status> StatusMap;
+
+ private:
TEMPLATE_GRAPH_TYPEDEFS(Graph);
- typedef typename Graph::template NodeMap<int> UFECrossRef;
- typedef UnionFindEnum<UFECrossRef> UFE;
- typedef std::vector<Node> NV;
+ typedef UnionFindEnum<IntNodeMap> BlossomSet;
+ typedef ExtendFindEnum<IntNodeMap> TreeSet;
+ typedef RangeMap<Node> NodeIntMap;
+ typedef MatchingMap EarMap;
+ typedef std::vector<Node> NodeQueue;
- typedef typename Graph::template NodeMap<int> EFECrossRef;
- typedef ExtendFindEnum<EFECrossRef> EFE;
+ const Graph& _graph;
+ MatchingMap* _matching;
+ StatusMap* _status;
+
+ EarMap* _ear;
+
+ IntNodeMap* _blossom_set_index;
+ BlossomSet* _blossom_set;
+ NodeIntMap* _blossom_rep;
+
+ IntNodeMap* _tree_set_index;
+ TreeSet* _tree_set;
+
+ NodeQueue _node_queue;
+ int _process, _postpone, _last;
+
+ int _node_num;
+
+ private:
+
+ void createStructures() {
+ _node_num = countNodes(_graph);
+ if (!_matching) {
+ _matching = new MatchingMap(_graph);
+ }
+ if (!_status) {
+ _status = new StatusMap(_graph);
+ }
+ if (!_ear) {
+ _ear = new EarMap(_graph);
+ }
+ if (!_blossom_set) {
+ _blossom_set_index = new IntNodeMap(_graph);
+ _blossom_set = new BlossomSet(*_blossom_set_index);
+ }
+ if (!_blossom_rep) {
+ _blossom_rep = new NodeIntMap(_node_num);
+ }
+ if (!_tree_set) {
+ _tree_set_index = new IntNodeMap(_graph);
+ _tree_set = new TreeSet(*_tree_set_index);
+ }
+ _node_queue.resize(_node_num);
+ }
+
+ void destroyStructures() {
+ if (_matching) {
+ delete _matching;
+ }
+ if (_status) {
+ delete _status;
+ }
+ if (_ear) {
+ delete _ear;
+ }
+ if (_blossom_set) {
+ delete _blossom_set;
+ delete _blossom_set_index;
+ }
+ if (_blossom_rep) {
+ delete _blossom_rep;
+ }
+ if (_tree_set) {
+ delete _tree_set_index;
+ delete _tree_set;
+ }
+ }
+
+ void processDense(const Node& n) {
+ _process = _postpone = _last = 0;
+ _node_queue[_last++] = n;
+
+ while (_process != _last) {
+ Node u = _node_queue[_process++];
+ for (OutArcIt a(_graph, u); a != INVALID; ++a) {
+ Node v = _graph.target(a);
+ if ((*_status)[v] == MATCHED) {
+ extendOnArc(a);
+ } else if ((*_status)[v] == UNMATCHED) {
+ augmentOnArc(a);
+ return;
+ }
+ }
+ }
+
+ while (_postpone != _last) {
+ Node u = _node_queue[_postpone++];
+
+ for (OutArcIt a(_graph, u); a != INVALID ; ++a) {
+ Node v = _graph.target(a);
+
+ if ((*_status)[v] == EVEN) {
+ if (_blossom_set->find(u) != _blossom_set->find(v)) {
+ shrinkOnEdge(a);
+ }
+ }
+
+ while (_process != _last) {
+ Node w = _node_queue[_process++];
+ for (OutArcIt b(_graph, w); b != INVALID; ++b) {
+ Node x = _graph.target(b);
+ if ((*_status)[x] == MATCHED) {
+ extendOnArc(b);
+ } else if ((*_status)[x] == UNMATCHED) {
+ augmentOnArc(b);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void processSparse(const Node& n) {
+ _process = _last = 0;
+ _node_queue[_last++] = n;
+ while (_process != _last) {
+ Node u = _node_queue[_process++];
+ for (OutArcIt a(_graph, u); a != INVALID; ++a) {
+ Node v = _graph.target(a);
+
+ if ((*_status)[v] == EVEN) {
+ if (_blossom_set->find(u) != _blossom_set->find(v)) {
+ shrinkOnEdge(a);
+ }
+ } else if ((*_status)[v] == MATCHED) {
+ extendOnArc(a);
+ } else if ((*_status)[v] == UNMATCHED) {
+ augmentOnArc(a);
+ return;
+ }
+ }
+ }
+ }
+
+ void shrinkOnEdge(const Edge& e) {
+ Node nca = INVALID;
+
+ {
+ std::set<Node> left_set, right_set;
+
+ Node left = (*_blossom_rep)[_blossom_set->find(_graph.u(e))];
+ left_set.insert(left);
+
+ Node right = (*_blossom_rep)[_blossom_set->find(_graph.v(e))];
+ right_set.insert(right);
+
+ while (true) {
+ if ((*_matching)[left] == INVALID) break;
+ left = _graph.target((*_matching)[left]);
+ left = (*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[left]))];
+ if (right_set.find(left) != right_set.end()) {
+ nca = left;
+ break;
+ }
+ left_set.insert(left);
+
+ if ((*_matching)[right] == INVALID) break;
+ right = _graph.target((*_matching)[right]);
+ right = (*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[right]))];
+ if (left_set.find(right) != left_set.end()) {
+ nca = right;
+ break;
+ }
+ right_set.insert(right);
+ }
+
+ if (nca == INVALID) {
+ if ((*_matching)[left] == INVALID) {
+ nca = right;
+ while (left_set.find(nca) == left_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ nca =(*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[nca]))];
+ }
+ } else {
+ nca = left;
+ while (right_set.find(nca) == right_set.end()) {
+ nca = _graph.target((*_matching)[nca]);
+ nca = (*_blossom_rep)[_blossom_set->
+ find(_graph.target((*_ear)[nca]))];
+ }
+ }
+ }
+ }
+
+ {
+
+ Node node = _graph.u(e);
+ Arc arc = _graph.direct(e, true);
+ Node base = (*_blossom_rep)[_blossom_set->find(node)];
+
+ while (base != nca) {
+ _ear->set(node, arc);
+
+ Node n = node;
+ while (n != base) {
+ n = _graph.target((*_matching)[n]);
+ Arc a = (*_ear)[n];
+ n = _graph.target(a);
+ _ear->set(n, _graph.oppositeArc(a));
+ }
+ node = _graph.target((*_matching)[base]);
+ _tree_set->erase(base);
+ _tree_set->erase(node);
+ _blossom_set->insert(node, _blossom_set->find(base));
+ _status->set(node, EVEN);
+ _node_queue[_last++] = node;
+ arc = _graph.oppositeArc((*_ear)[node]);
+ node = _graph.target((*_ear)[node]);
+ base = (*_blossom_rep)[_blossom_set->find(node)];
+ _blossom_set->join(_graph.target(arc), base);
+ }
More information about the Lemon-commits
mailing list