[Lemon-commits] Balazs Dezso: Port maximum matching algorithms f...

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/64ad48007fb2
changeset: 338:64ad48007fb2
user:      Balazs Dezso <deba [at] inf.elte.hu>
date:      Mon Oct 13 13:56:00 2008 +0200
description:
	Port maximum matching algorithms from svn 3498 (ticket #48)

diffstat:

6 files changed, 3550 insertions(+)
lemon/Makefile.am                  |    1 
lemon/max_matching.h               | 3112 ++++++++++++++++++++++++++++++++++++
test/CMakeLists.txt                |    2 
test/Makefile.am                   |    4 
test/max_matching_test.cc          |  181 ++
test/max_weighted_matching_test.cc |  250 ++

diffs (truncated from 3599 to 300 lines):

diff -r 6dbd5184c6a9 -r 64ad48007fb2 lemon/Makefile.am
--- a/lemon/Makefile.am	Sun Oct 12 19:35:48 2008 +0100
+++ b/lemon/Makefile.am	Mon Oct 13 13:56:00 2008 +0200
@@ -35,6 +35,7 @@
 	lemon/list_graph.h \
 	lemon/maps.h \
 	lemon/math.h \
+	lemon/max_matching.h \
 	lemon/path.h \
         lemon/random.h \
 	lemon/smart_graph.h \
diff -r 6dbd5184c6a9 -r 64ad48007fb2 lemon/max_matching.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lemon/max_matching.h	Mon Oct 13 13:56:00 2008 +0200
@@ -0,0 +1,3112 @@
+/* -*- mode: C++; indent-tabs-mode: nil; -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library.
+ *
+ * Copyright (C) 2003-2008
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_MAX_MATCHING_H
+#define LEMON_MAX_MATCHING_H
+
+#include <vector>
+#include <queue>
+#include <set>
+#include <limits>
+
+#include <lemon/core.h>
+#include <lemon/unionfind.h>
+#include <lemon/bin_heap.h>
+#include <lemon/maps.h>
+
+///\ingroup matching
+///\file
+///\brief Maximum matching algorithms in graph.
+
+namespace lemon {
+
+  ///\ingroup matching
+  ///
+  ///\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.
+  ///
+  ///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.
+  ///
+  ///\param Digraph The graph type the algorithm runs on.
+  template <typename Graph>
+  class MaxMatching {
+
+  protected:
+
+    TEMPLATE_GRAPH_TYPEDEFS(Graph);
+
+    typedef typename Graph::template NodeMap<int> UFECrossRef;
+    typedef UnionFindEnum<UFECrossRef> UFE;
+    typedef std::vector<Node> NV;
+
+    typedef typename Graph::template NodeMap<int> EFECrossRef;
+    typedef ExtendFindEnum<EFECrossRef> EFE;
+
+  public:
+
+    ///\brief Indicates the Gallai-Edmonds decomposition of the digraph.
+    ///
+    ///Indicates the Gallai-Edmonds decomposition of the digraph, which
+    ///shows an upper bound on the size of a maximum matching. The
+    ///nodes with DecompType \c D induce a digraph with factor-critical
+    ///components, the nodes in \c A form the canonical barrier, and the
+    ///nodes in \c C induce a digraph having a perfect matching.
+    enum DecompType {
+      D=0,
+      A=1,
+      C=2
+    };
+
+  protected:
+
+    static const int HEUR_density=2;
+    const Graph& g;
+    typename Graph::template NodeMap<Node> _mate;
+    typename Graph::template NodeMap<DecompType> position;
+
+  public:
+
+    MaxMatching(const Graph& _g)
+      : g(_g), _mate(_g), position(_g) {}
+
+    ///\brief Sets the actual matching to the empty matching.
+    ///
+    ///Sets the actual matching to the empty matching.
+    ///
+    void init() {
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        _mate.set(v,INVALID);
+        position.set(v,C);
+      }
+    }
+
+    ///\brief Finds a greedy matching for initial matching.
+    ///
+    ///For initial matchig it finds a maximal greedy matching.
+    void greedyInit() {
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        _mate.set(v,INVALID);
+        position.set(v,C);
+      }
+      for(NodeIt v(g); v!=INVALID; ++v)
+        if ( _mate[v]==INVALID ) {
+          for( IncEdgeIt e(g,v); e!=INVALID ; ++e ) {
+            Node y=g.runningNode(e);
+            if ( _mate[y]==INVALID && y!=v ) {
+              _mate.set(v,y);
+              _mate.set(y,v);
+              break;
+            }
+          }
+        }
+    }
+
+    ///\brief Initialize the matching from each nodes' mate.
+    ///
+    ///Initialize the matching from a \c Node valued \c Node map. This
+    ///map must be \e symmetric, i.e. if \c map[u]==v then \c
+    ///map[v]==u must hold, and \c uv will be an arc of the initial
+    ///matching.
+    template <typename MateMap>
+    void mateMapInit(MateMap& map) {
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        _mate.set(v,map[v]);
+        position.set(v,C);
+      }
+    }
+
+    ///\brief Initialize the matching from a node map with the
+    ///incident matching arcs.
+    ///
+    ///Initialize the matching from an \c Edge valued \c Node map. \c
+    ///map[v] must be an \c Edge incident to \c v. This map must have
+    ///the property that if \c g.oppositeNode(u,map[u])==v then \c \c
+    ///g.oppositeNode(v,map[v])==u holds, and now some arc joining \c
+    ///u to \c v will be an arc of the matching.
+    template<typename MatchingMap>
+    void matchingMapInit(MatchingMap& map) {
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        position.set(v,C);
+        Edge e=map[v];
+        if ( e!=INVALID )
+          _mate.set(v,g.oppositeNode(v,e));
+        else
+          _mate.set(v,INVALID);
+      }
+    }
+
+    ///\brief Initialize the matching from the map containing the
+    ///undirected matching arcs.
+    ///
+    ///Initialize the matching from a \c bool valued \c Edge map. This
+    ///map must have the property that there are no two incident arcs
+    ///\c e, \c f with \c map[e]==map[f]==true. The arcs \c e with \c
+    ///map[e]==true form the matching.
+    template <typename MatchingMap>
+    void matchingInit(MatchingMap& map) {
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        _mate.set(v,INVALID);
+        position.set(v,C);
+      }
+      for(EdgeIt e(g); e!=INVALID; ++e) {
+        if ( map[e] ) {
+          Node u=g.u(e);
+          Node v=g.v(e);
+          _mate.set(u,v);
+          _mate.set(v,u);
+        }
+      }
+    }
+
+
+    ///\brief Runs Edmonds' algorithm.
+    ///
+    ///Runs Edmonds' algorithm for sparse digraphs (number of arcs <
+    ///2*number of nodes), and a heuristical Edmonds' algorithm with a
+    ///heuristic of postponing shrinks for dense digraphs.
+    void run() {
+      if (countEdges(g) < HEUR_density * countNodes(g)) {
+        greedyInit();
+        startSparse();
+      } else {
+        init();
+        startDense();
+      }
+    }
+
+
+    ///\brief Starts Edmonds' algorithm.
+    ///
+    ///If runs the original Edmonds' algorithm.
+    void startSparse() {
+
+      typename Graph::template NodeMap<Node> ear(g,INVALID);
+      //undefined for the base nodes of the blossoms (i.e. for the
+      //representative elements of UFE blossom) and for the nodes in C
+
+      UFECrossRef blossom_base(g);
+      UFE blossom(blossom_base);
+      NV rep(countNodes(g));
+
+      EFECrossRef tree_base(g);
+      EFE tree(tree_base);
+
+      //If these UFE's would be members of the class then also
+      //blossom_base and tree_base should be a member.
+
+      //We build only one tree and the other vertices uncovered by the
+      //matching belong to C. (They can be considered as singleton
+      //trees.) If this tree can be augmented or no more
+      //grow/augmentation/shrink is possible then we return to this
+      //"for" cycle.
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        if (position[v]==C && _mate[v]==INVALID) {
+          rep[blossom.insert(v)] = v;
+          tree.insert(v);
+          position.set(v,D);
+          normShrink(v, ear, blossom, rep, tree);
+        }
+      }
+    }
+
+    ///\brief Starts Edmonds' algorithm.
+    ///
+    ///It runs Edmonds' algorithm with a heuristic of postponing
+    ///shrinks, giving a faster algorithm for dense digraphs.
+    void startDense() {
+
+      typename Graph::template NodeMap<Node> ear(g,INVALID);
+      //undefined for the base nodes of the blossoms (i.e. for the
+      //representative elements of UFE blossom) and for the nodes in C
+
+      UFECrossRef blossom_base(g);
+      UFE blossom(blossom_base);
+      NV rep(countNodes(g));
+
+      EFECrossRef tree_base(g);
+      EFE tree(tree_base);
+
+      //If these UFE's would be members of the class then also
+      //blossom_base and tree_base should be a member.
+
+      //We build only one tree and the other vertices uncovered by the
+      //matching belong to C. (They can be considered as singleton
+      //trees.) If this tree can be augmented or no more
+      //grow/augmentation/shrink is possible then we return to this
+      //"for" cycle.
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        if ( position[v]==C && _mate[v]==INVALID ) {
+          rep[blossom.insert(v)] = v;
+          tree.insert(v);
+          position.set(v,D);
+          lateShrink(v, ear, blossom, rep, tree);
+        }
+      }
+    }
+
+
+
+    ///\brief Returns the size of the actual matching stored.
+    ///
+    ///Returns the size of the actual matching stored. After \ref
+    ///run() it returns the size of a maximum matching in the digraph.
+    int size() const {
+      int s=0;
+      for(NodeIt v(g); v!=INVALID; ++v) {
+        if ( _mate[v]!=INVALID ) {
+          ++s;
+        }
+      }
+      return s/2;
+    }



More information about the Lemon-commits mailing list