[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