[Lemon-commits] [lemon_svn] deba: r2679 - in hugo/trunk: lemon test

Lemon SVN svn at lemon.cs.elte.hu
Mon Nov 6 20:54:25 CET 2006


Author: deba
Date: Fri Apr  7 11:51:23 2006
New Revision: 2679

Added:
   hugo/trunk/lemon/bipartite_matching.h
   hugo/trunk/test/bipartite_matching_test.cc
Modified:
   hugo/trunk/lemon/Makefile.am
   hugo/trunk/lemon/bpugraph_adaptor.h
   hugo/trunk/test/Makefile.am

Log:
Bipartite Graph Max Cardinality Matching (Hopcroft-Karp)
Test for it

Some BpUgraph improvments



Modified: hugo/trunk/lemon/Makefile.am
==============================================================================
--- hugo/trunk/lemon/Makefile.am	(original)
+++ hugo/trunk/lemon/Makefile.am	Fri Apr  7 11:51:23 2006
@@ -31,6 +31,8 @@
 	dfs.h \
 	bin_heap.h \
 	bpugraph_adaptor.h \
+	bipartite_matching.h \
+	bucket_heap.h \
 	color.h \
 	config.h \
 	counter.h \
@@ -53,7 +55,6 @@
 	iterable_maps.h \
 	johnson.h \
 	kruskal.h \
-	bucket_heap.h \
 	list_graph.h \
 	lp.h \
 	lp_base.h \

Added: hugo/trunk/lemon/bipartite_matching.h
==============================================================================
--- (empty file)
+++ hugo/trunk/lemon/bipartite_matching.h	Fri Apr  7 11:51:23 2006
@@ -0,0 +1,466 @@
+/* -*- C++ -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library
+ *
+ * Copyright (C) 2003-2006
+ * 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_BIPARTITE_MATCHING
+#define LEMON_BIPARTITE_MATCHING
+
+#include <lemon/bpugraph_adaptor.h>
+#include <lemon/bfs.h>
+
+#include <iostream>
+
+///\ingroup matching
+///\file
+///\brief Maximum matching algorithms in bipartite graphs.
+
+namespace lemon {
+
+  /// \ingroup matching
+  ///
+  /// \brief Bipartite Max Cardinality Matching algorithm
+  ///
+  /// Bipartite Max Cardinality Matching algorithm. This class implements
+  /// the Hopcroft-Karp algorithm wich has \f$ O(e\sqrt{n}) \f$ time
+  /// complexity.
+  template <typename BpUGraph>
+  class MaxBipartiteMatching {
+  protected:
+
+    typedef BpUGraph Graph;
+
+    typedef typename Graph::Node Node;
+    typedef typename Graph::ANodeIt ANodeIt;
+    typedef typename Graph::BNodeIt BNodeIt;
+    typedef typename Graph::UEdge UEdge;
+    typedef typename Graph::UEdgeIt UEdgeIt;
+    typedef typename Graph::IncEdgeIt IncEdgeIt;
+
+    typedef typename BpUGraph::template ANodeMap<UEdge> ANodeMatchingMap;
+    typedef typename BpUGraph::template BNodeMap<UEdge> BNodeMatchingMap;
+
+
+  public:
+
+    /// \brief Constructor.
+    ///
+    /// Constructor of the algorithm. 
+    MaxBipartiteMatching(const BpUGraph& _graph) 
+      : anode_matching(_graph), bnode_matching(_graph), graph(&_graph) {}
+
+    /// \name Execution control
+    /// The simplest way to execute the algorithm is to use
+    /// one of the member functions called \c run().
+    /// \n
+    /// If you need more control on the execution,
+    /// first you must call \ref init() or one alternative for it.
+    /// Finally \ref start() will perform the matching computation or
+    /// with step-by-step execution you can augment the solution.
+
+    /// @{
+
+    /// \brief Initalize the data structures.
+    ///
+    /// It initalizes the data structures and creates an empty matching.
+    void init() {
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        anode_matching[it] = INVALID;
+      }
+      for (BNodeIt it(*graph); it != INVALID; ++it) {
+        bnode_matching[it] = INVALID;
+      }
+      matching_value = 0;
+    }
+
+    /// \brief Initalize the data structures.
+    ///
+    /// It initalizes the data structures and creates a greedy
+    /// matching.  From this matching sometimes it is faster to get
+    /// the matching than from the initial empty matching.
+    void greedyInit() {
+      matching_value = 0;
+      for (BNodeIt it(*graph); it != INVALID; ++it) {
+        bnode_matching[it] = INVALID;
+      }
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        anode_matching[it] = INVALID;
+        for (IncEdgeIt jt(*graph, it); jt != INVALID; ++jt) {
+          if (bnode_matching[graph->bNode(jt)] == INVALID) {
+            anode_matching[it] = jt;
+            bnode_matching[graph->bNode(jt)] = jt;
+            ++matching_value;
+            break;
+          }
+        }
+      }
+    }
+
+    /// \brief Initalize the data structures with an initial matching.
+    ///
+    /// It initalizes the data structures with an initial matching.
+    template <typename MatchingMap>
+    void matchingInit(const MatchingMap& matching) {
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        anode_matching[it] = INVALID;
+      }
+      for (BNodeIt it(*graph); it != INVALID; ++it) {
+        bnode_matching[it] = INVALID;
+      }
+      matching_value = 0;
+      for (UEdgeIt it(*graph); it != INVALID; ++it) {
+        if (matching[it]) {
+          ++matching_value;
+          anode_matching[graph->aNode(it)] = it;
+          bnode_matching[graph->bNode(it)] = it;
+        }
+      }
+    }
+
+    /// \brief Initalize the data structures with an initial matching.
+    ///
+    /// It initalizes the data structures with an initial matching.
+    /// \return %True when the given map contains really a matching.
+    template <typename MatchingMap>
+    void checkedMatchingInit(const MatchingMap& matching) {
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        anode_matching[it] = INVALID;
+      }
+      for (BNodeIt it(*graph); it != INVALID; ++it) {
+        bnode_matching[it] = INVALID;
+      }
+      matching_value = 0;
+      for (UEdgeIt it(*graph); it != INVALID; ++it) {
+        if (matching[it]) {
+          ++matching_value;
+          if (anode_matching[graph->aNode(it)] != INVALID) {
+            return false;
+          }
+          anode_matching[graph->aNode(it)] = it;
+          if (bnode_matching[graph->aNode(it)] != INVALID) {
+            return false;
+          }
+          bnode_matching[graph->bNode(it)] = it;
+        }
+      }
+      return false;
+    }
+
+    /// \brief An augmenting phase of the Hopcroft-Karp algorithm
+    ///
+    /// It runs an augmenting phase of the Hopcroft-Karp
+    /// algorithm. The phase finds maximum count of edge disjoint
+    /// augmenting paths and augments on these paths. The algorithm
+    /// consists at most of \f$ O(\sqrt{n}) \f$ phase and one phase is
+    /// \f$ O(e) \f$ long.
+    bool augment() {
+
+      typename Graph::template ANodeMap<bool> areached(*graph, false);
+      typename Graph::template BNodeMap<bool> breached(*graph, false);
+
+      typename Graph::template BNodeMap<UEdge> bpred(*graph, INVALID);
+
+      std::vector<Node> queue, bqueue;
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        if (anode_matching[it] == INVALID) {
+          queue.push_back(it);
+          areached[it] = true;
+        }
+      }
+
+      bool success = false;
+
+      while (!success && !queue.empty()) {
+        std::vector<Node> newqueue;
+        for (int i = 0; i < (int)queue.size(); ++i) {
+          Node anode = queue[i];
+          for (IncEdgeIt jt(*graph, anode); jt != INVALID; ++jt) {
+            Node bnode = graph->bNode(jt);
+            if (breached[bnode]) continue;
+            breached[bnode] = true;
+            bpred[bnode] = jt;
+            if (bnode_matching[bnode] == INVALID) {
+              bqueue.push_back(bnode);
+              success = true;
+            } else {           
+              Node newanode = graph->aNode(bnode_matching[bnode]);
+              if (!areached[newanode]) {
+                areached[newanode] = true;
+                newqueue.push_back(newanode);
+              }
+            }
+          }
+        }
+        queue.swap(newqueue);
+      }
+
+      if (success) {
+
+        typename Graph::template ANodeMap<bool> aused(*graph, false);
+        
+        for (int i = 0; i < (int)bqueue.size(); ++i) {
+          Node bnode = bqueue[i];
+
+          bool used = false;
+
+          while (bnode != INVALID) {
+            UEdge uedge = bpred[bnode];
+            Node anode = graph->aNode(uedge);
+            
+            if (aused[anode]) {
+              used = true;
+              break;
+            }
+            
+            bnode = anode_matching[anode] != INVALID ? 
+              graph->bNode(anode_matching[anode]) : INVALID;
+            
+          }
+          
+          if (used) continue;
+
+          bnode = bqueue[i];
+          while (bnode != INVALID) {
+            UEdge uedge = bpred[bnode];
+            Node anode = graph->aNode(uedge);
+            
+            bnode_matching[bnode] = uedge;
+
+            bnode = anode_matching[anode] != INVALID ? 
+              graph->bNode(anode_matching[anode]) : INVALID;
+            
+            anode_matching[anode] = uedge;
+
+            aused[anode] = true;
+          }
+          ++matching_value;
+
+        }
+      }
+      return success;
+    }
+
+    /// \brief An augmenting phase of the Ford-Fulkerson algorithm
+    ///
+    /// It runs an augmenting phase of the Ford-Fulkerson
+    /// algorithm. The phase finds only one augmenting path and 
+    /// augments only on this paths. The algorithm consists at most 
+    /// of \f$ O(n) \f$ simple phase and one phase is at most 
+    /// \f$ O(e) \f$ long.
+    bool simpleAugment() {
+
+      typename Graph::template ANodeMap<bool> areached(*graph, false);
+      typename Graph::template BNodeMap<bool> breached(*graph, false);
+
+      typename Graph::template BNodeMap<UEdge> bpred(*graph, INVALID);
+
+      std::vector<Node> queue;
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        if (anode_matching[it] == INVALID) {
+          queue.push_back(it);
+          areached[it] = true;
+        }
+      }
+
+      while (!queue.empty()) {
+        std::vector<Node> newqueue;
+        for (int i = 0; i < (int)queue.size(); ++i) {
+          Node anode = queue[i];
+          for (IncEdgeIt jt(*graph, anode); jt != INVALID; ++jt) {
+            Node bnode = graph->bNode(jt);
+            if (breached[bnode]) continue;
+            breached[bnode] = true;
+            bpred[bnode] = jt;
+            if (bnode_matching[bnode] == INVALID) {
+              while (bnode != INVALID) {
+                UEdge uedge = bpred[bnode];
+                anode = graph->aNode(uedge);
+                
+                bnode_matching[bnode] = uedge;
+                
+                bnode = anode_matching[anode] != INVALID ? 
+                  graph->bNode(anode_matching[anode]) : INVALID;
+                
+                anode_matching[anode] = uedge;
+                
+              }
+              ++matching_value;
+              return true;
+            } else {           
+              Node newanode = graph->aNode(bnode_matching[bnode]);
+              if (!areached[newanode]) {
+                areached[newanode] = true;
+                newqueue.push_back(newanode);
+              }
+            }
+          }
+        }
+        queue.swap(newqueue);
+      }
+      
+      return false;
+    }
+
+    /// \brief Starts the algorithm.
+    ///
+    /// Starts the algorithm. It runs augmenting phases until the optimal
+    /// solution reached.
+    void start() {
+      while (augment()) {}
+    }
+
+    /// \brief Runs the algorithm.
+    ///
+    /// It just initalize the algorithm and then start it.
+    void run() {
+      init();
+      start();
+    }
+
+    /// @}
+
+    /// \name Query Functions
+    /// The result of the %Matching algorithm can be obtained using these
+    /// functions.\n
+    /// Before the use of these functions,
+    /// either run() or start() must be called.
+    
+    ///@{
+
+    /// \brief Returns an minimum covering of the nodes.
+    ///
+    /// The minimum covering set problem is the dual solution of the
+    /// maximum bipartite matching. It provides an solution for this
+    /// problem what is proof of the optimality of the matching.
+    /// \return The size of the cover set.
+    template <typename CoverMap>
+    int coverSet(CoverMap& covering) {
+
+      typename Graph::template ANodeMap<bool> areached(*graph, false);
+      typename Graph::template BNodeMap<bool> breached(*graph, false);
+      
+      std::vector<Node> queue;
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        if (anode_matching[it] == INVALID) {
+          queue.push_back(it);
+        }
+      }
+
+      while (!queue.empty()) {
+        std::vector<Node> newqueue;
+        for (int i = 0; i < (int)queue.size(); ++i) {
+          Node anode = queue[i];
+          for (IncEdgeIt jt(*graph, anode); jt != INVALID; ++jt) {
+            Node bnode = graph->bNode(jt);
+            if (breached[bnode]) continue;
+            breached[bnode] = true;
+            if (bnode_matching[bnode] != INVALID) {
+              Node newanode = graph->aNode(bnode_matching[bnode]);
+              if (!areached[newanode]) {
+                areached[newanode] = true;
+                newqueue.push_back(newanode);
+              }
+            }
+          }
+        }
+        queue.swap(newqueue);
+      }
+
+      int size = 0;
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        covering[it] = !areached[it] && anode_matching[it] != INVALID;
+        if (!areached[it] && anode_matching[it] != INVALID) {
+          ++size;
+        }
+      }
+      for (BNodeIt it(*graph); it != INVALID; ++it) {
+        covering[it] = breached[it];
+        if (breached[it]) {
+          ++size;
+        }
+      }
+      return size;
+    }
+
+    /// \brief Set true all matching uedge in the map.
+    /// 
+    /// Set true all matching uedge in the map. It does not change the
+    /// value mapped to the other uedges.
+    /// \return The number of the matching edges.
+    template <typename MatchingMap>
+    int quickMatching(MatchingMap& matching) {
+      for (ANodeIt it(*graph); it != INVALID; ++it) {
+        if (anode_matching[it] != INVALID) {
+          matching[anode_matching[it]] = true;
+        }
+      }
+      return matching_value;
+    }
+
+    /// \brief Set true all matching uedge in the map and the others to false.
+    /// 
+    /// Set true all matching uedge in the map and the others to false.
+    /// \return The number of the matching edges.
+    template <typename MatchingMap>
+    int matching(MatchingMap& matching) {
+      for (UEdgeIt it(*graph); it != INVALID; ++it) {
+        matching[it] = it == anode_matching[graph->aNode(it)];
+      }
+      return matching_value;
+    }
+
+
+    /// \brief Return true if the given uedge is in the matching.
+    /// 
+    /// It returns true if the given uedge is in the matching.
+    bool matchingEdge(const UEdge& edge) {
+      return anode_matching[graph->aNode(edge)] == edge;
+    }
+
+    /// \brief Returns the matching edge from the node.
+    /// 
+    /// Returns the matching edge from the node. If there is not such
+    /// edge it gives back \c INVALID.
+    UEdge matchingEdge(const Node& node) {
+      if (graph->aNode(node)) {
+        return anode_matching[node];
+      } else {
+        return bnode_matching[node];
+      }
+    }
+
+    /// \brief Gives back the number of the matching edges.
+    ///
+    /// Gives back the number of the matching edges.
+    int matchingValue() const {
+      return matching_value;
+    }
+
+    /// @}
+
+  private:
+
+    ANodeMatchingMap anode_matching;
+    BNodeMatchingMap bnode_matching;
+    const Graph *graph;
+
+    int matching_value;
+  
+  };
+
+}
+
+#endif

Modified: hugo/trunk/lemon/bpugraph_adaptor.h
==============================================================================
--- hugo/trunk/lemon/bpugraph_adaptor.h	(original)
+++ hugo/trunk/lemon/bpugraph_adaptor.h	Fri Apr  7 11:51:23 2006
@@ -103,6 +103,12 @@
     Node source(const Edge& e) const { return graph->source(e); }
     Node target(const Edge& e) const { return graph->target(e); }
 
+    Node aNode(const UEdge& e) const { return graph->aNode(e); }
+    Node bNode(const UEdge& e) const { return graph->bNode(e); }
+
+    bool aNode(const Node& n) const { return graph->aNode(n); }
+    bool bNode(const Node& n) const { return graph->bNode(n); }
+
     typedef NodeNumTagIndicator<Graph> NodeNumTag;
     int nodeNum() const { return graph->nodeNum(); }
     int aNodeNum() const { return graph->aNodeNum(); }
@@ -122,7 +128,8 @@
       return graph->findUEdge(source, target, prev);
     }
   
-    Node addNode() const { return graph->addNode(); }
+    Node addANode() const { return graph->addANode(); }
+    Node addBNode() const { return graph->addBNode(); }
     UEdge addEdge(const Node& source, const Node& target) const { 
       return graph->addEdge(source, target); 
     }
@@ -281,6 +288,11 @@
   };
 
   /// \ingroup graph_adaptors
+  ///
+  /// \brief Trivial Bipartite Undirected Graph Adaptor
+  ///
+  /// Trivial Bipartite Undirected Graph Adaptor. It does not change
+  /// the functionality of the adapted graph.
   template <typename _BpUGraph>
   class BpUGraphAdaptor 
     : public BpUGraphAdaptorExtender< BpUGraphAdaptorBase<_BpUGraph> > { 
@@ -310,6 +322,17 @@
     typedef typename Parent::Node Node;
     typedef typename Parent::BNode ANode;
     typedef typename Parent::ANode BNode;
+    typedef typename Parent::Edge Edge;
+    typedef typename Parent::UEdge UEdge;
+
+    bool direction(const Edge& e) const { return !Parent::direction(e); }
+    Edge direct(const UEdge& e, bool b) const { return Parent::direct(e, !b); }
+
+    Node aNode(const UEdge& e) const { return Parent::bNode(e); }
+    Node bNode(const UEdge& e) const { return Parent::aNode(e); }
+
+    bool aNode(const Node& n) const { return Parent::bNode(n); }
+    bool bNode(const Node& n) const { return Parent::aNode(n); }
 
     void firstANode(Node& i) const { Parent::firstBNode(i); }
     void firstBNode(Node& i) const { Parent::firstANode(i); }
@@ -407,6 +430,126 @@
   };
 
 
+  template <typename _BpUGraph, 
+            typename _ANMatchingMap, typename _BNMatchingMap>
+  class MatchingBpUGraphAdaptorBase 
+    : public BpUGraphAdaptorBase<const _BpUGraph>
+  {
+  public:
+    
+    typedef _BpUGraph Graph;
+    typedef _ANMatchingMap ANodeMatchingMap;
+    typedef _BNMatchingMap BNodeMatchingMap;
+
+    typedef BpUGraphAdaptorBase<const _BpUGraph> Parent;
+
+  protected:
+    
+    MatchingBpUGraphAdaptorBase() {}
+
+    void setANodeMatchingMap(ANodeMatchingMap& _anode_matching) {
+      anode_matching = &_anode_matching;
+    }
+
+    void setBNodeMatchingMap(BNodeMatchingMap& _bnode_matching) {
+      bnode_matching = &_bnode_matching;
+    }
+
+  public:
+
+    typedef typename Parent::Node Node;
+    typedef typename Parent::Edge Edge;
+
+    void firstOut(Edge& edge, const Node& node) const {
+      if (Parent::aNode(node)) {
+        Parent::firstOut(edge, node);
+        if (edge != INVALID && (*anode_matching)[node] == edge) {
+          Parent::nextOut(edge);
+        }
+      } else {
+        edge = (*bnode_matching)[node] != INVALID ?
+          Parent::direct((*bnode_matching)[node], false) : INVALID;
+      }
+    }
+
+    void nextOut(Edge& edge) const {
+      if (Parent::aNode(Parent::source(edge))) {
+        Parent::nextOut(edge);
+        if (edge != INVALID && (*anode_matching)[Parent::aNode(edge)] == edge) {
+          Parent::nextOut(edge);
+        }
+      } else {
+        edge = INVALID;
+      }
+    }
+ 
+    void firstIn(Edge& edge, const Node& node) const {
+      if (Parent::aNode(node)) {
+        edge = (*bnode_matching)[node] != INVALID ?
+          Parent::direct((*anode_matching)[node], false) : INVALID;
+      } else {
+        Parent::firstIn(edge, node);
+        if (edge != INVALID && (*bnode_matching)[node] == edge) {
+          Parent::nextIn(edge);
+        }
+      }
+    }
+
+    void nextIn(Edge& edge) const {
+      if (Parent::aNode(Parent::target(edge))) {
+        edge = INVALID;
+      } else {
+        Parent::nextIn(edge);
+        if (edge != INVALID && (*bnode_matching)[Parent::bNode(edge)] == edge) {
+          Parent::nextIn(edge);
+        }
+      }
+    } 
+
+  private:
+    ANodeMatchingMap* anode_matching;
+    BNodeMatchingMap* bnode_matching;
+  };
+
+
+  /// \ingroup graph_adaptors
+  ///
+  /// \brief Bipartite graph adaptor to implement matching algorithms.
+  ///
+  /// Bipartite graph adaptor to implement matchings. It implements
+  /// the residual graph of the matching.
+  template <typename _BpUGraph, 
+            typename _ANMatchingMap, typename _BNMatchingMap>
+  class MatchingBpUGraphAdaptor 
+    : public BpUGraphAdaptorExtender<
+    MatchingBpUGraphAdaptorBase<_BpUGraph, _ANMatchingMap, _BNMatchingMap> > 
+  { 
+  public:
+
+    typedef _BpUGraph BpUGraph;
+    typedef _BpUGraph Graph;
+    typedef _ANMatchingMap ANodeMatchingMap;
+    typedef _BNMatchingMap BNodeMatchingMap;
+    typedef BpUGraphAdaptorExtender<
+      MatchingBpUGraphAdaptorBase<BpUGraph, 
+                                  ANodeMatchingMap, BNodeMatchingMap> > 
+    Parent;
+
+  protected:
+    MatchingBpUGraphAdaptor() : Parent() {}
+
+  public:
+
+    MatchingBpUGraphAdaptor(const Graph& _graph, 
+                            ANodeMatchingMap& _anode_matching,
+                            BNodeMatchingMap& _bnode_matching) {
+      setGraph(_graph);
+      setANodeMatchingMap(_anode_matching);
+      setBNodeMatchingMap(_bnode_matching);
+    }
+
+  };
+
 }
 
 #endif

Modified: hugo/trunk/test/Makefile.am
==============================================================================
--- hugo/trunk/test/Makefile.am	(original)
+++ hugo/trunk/test/Makefile.am	Fri Apr  7 11:51:23 2006
@@ -15,6 +15,7 @@
 	all_pairs_shortest_path_test \
 	arborescence_test \
 	bfs_test \
+	bipartite_matching_test \
 	counter_test \
 	dfs_test \
 	dijkstra_test \
@@ -55,6 +56,7 @@
 all_pairs_shortest_path_test_SOURCES = all_pairs_shortest_path_test.cc
 arborescence_test_SOURCES = arborescence_test.cc
 bfs_test_SOURCES = bfs_test.cc
+bipartite_matching_test_SOURCES = bipartite_matching_test.cc
 counter_test_SOURCES = counter_test.cc
 dfs_test_SOURCES = dfs_test.cc
 dijkstra_test_SOURCES = dijkstra_test.cc

Added: hugo/trunk/test/bipartite_matching_test.cc
==============================================================================
--- (empty file)
+++ hugo/trunk/test/bipartite_matching_test.cc	Fri Apr  7 11:51:23 2006
@@ -0,0 +1,138 @@
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+
+#include <lemon/list_graph.h>
+
+#include <lemon/bpugraph_adaptor.h>
+#include <lemon/bipartite_matching.h>
+
+#include <lemon/graph_utils.h>
+
+#include "test_tools.h"
+
+using namespace std;
+using namespace lemon;
+
+typedef ListBpUGraph Graph;
+BPUGRAPH_TYPEDEFS(Graph);
+
+int main(int argc, const char *argv[]) {
+  Graph graph;
+  vector<Node> aNodes;
+  vector<Node> bNodes;
+  int n = argc > 1 ? atoi(argv[1]) : 100;
+  int m = argc > 2 ? atoi(argv[2]) : 100;
+  int e = argc > 3 ? atoi(argv[3]) : (int)((n+m) * log(n+m));
+
+  for (int i = 0; i < n; ++i) {
+    Node node = graph.addANode();
+    aNodes.push_back(node);
+  }
+  for (int i = 0; i < m; ++i) {
+    Node node = graph.addBNode();
+    bNodes.push_back(node);
+  }
+  for (int i = 0; i < e; ++i) {
+    Node aNode = aNodes[urandom(n)];
+    Node bNode = bNodes[urandom(m)];
+    graph.addEdge(aNode, bNode);
+  }
+
+  {
+    MaxBipartiteMatching<Graph> bpmatch(graph);
+
+    bpmatch.run();
+
+    Graph::UEdgeMap<bool> mm(graph);
+    Graph::NodeMap<bool> cs(graph);
+    
+    check(bpmatch.coverSet(cs) == bpmatch.matching(mm), "INVALID PRIMAL-DUAL");
+    
+    for (UEdgeIt it(graph); it != INVALID; ++it) {
+      check(cs[graph.aNode(it)] || cs[graph.bNode(it)], "INVALID DUAL");
+    }
+    
+    for (ANodeIt it(graph); it != INVALID; ++it) {
+      int num = 0;
+      for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
+        if (mm[jt]) ++num;
+    }
+      check(num <= 1, "INVALID PRIMAL");
+    }
+  }
+
+  {
+    MaxBipartiteMatching<Graph> bpmatch(graph);
+
+    bpmatch.greedyInit();
+    bpmatch.start();
+
+    Graph::UEdgeMap<bool> mm(graph);
+    Graph::NodeMap<bool> cs(graph);
+
+    check(bpmatch.coverSet(cs) == bpmatch.matching(mm), "INVALID PRIMAL-DUAL");
+    
+    for (UEdgeIt it(graph); it != INVALID; ++it) {
+      check(cs[graph.aNode(it)] || cs[graph.bNode(it)], "INVALID DUAL");
+    }
+    
+    for (ANodeIt it(graph); it != INVALID; ++it) {
+      int num = 0;
+      for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
+        if (mm[jt]) ++num;
+    }
+      check(num <= 1, "INVALID PRIMAL");
+    }
+  }
+
+  {
+    MaxBipartiteMatching<Graph> bpmatch(graph);
+
+    bpmatch.greedyInit();
+    while (bpmatch.simpleAugment());
+    
+    Graph::UEdgeMap<bool> mm(graph);
+    Graph::NodeMap<bool> cs(graph);
+    
+    check(bpmatch.coverSet(cs) == bpmatch.matching(mm), "INVALID PRIMAL-DUAL");
+    
+    for (UEdgeIt it(graph); it != INVALID; ++it) {
+      check(cs[graph.aNode(it)] || cs[graph.bNode(it)], "INVALID DUAL");
+    }
+    
+    for (ANodeIt it(graph); it != INVALID; ++it) {
+      int num = 0;
+      for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
+        if (mm[jt]) ++num;
+    }
+      check(num <= 1, "INVALID PRIMAL");
+    }
+  }
+
+  {
+    SwapBpUGraphAdaptor<Graph> swapgraph(graph);
+    MaxBipartiteMatching<SwapBpUGraphAdaptor<Graph> > bpmatch(swapgraph);
+
+    bpmatch.run();
+
+    Graph::UEdgeMap<bool> mm(graph);
+    Graph::NodeMap<bool> cs(graph);
+    
+    check(bpmatch.coverSet(cs) == bpmatch.matching(mm), "INVALID PRIMAL-DUAL");
+    
+    for (UEdgeIt it(graph); it != INVALID; ++it) {
+      check(cs[graph.aNode(it)] || cs[graph.bNode(it)], "INVALID DUAL");
+    }
+    
+    for (ANodeIt it(graph); it != INVALID; ++it) {
+      int num = 0;
+      for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
+        if (mm[jt]) ++num;
+    }
+      check(num <= 1, "INVALID PRIMAL");
+    }
+  }
+
+  return 0;
+}



More information about the Lemon-commits mailing list