lemon/max_matching.h
author hegyi
Mon, 21 Nov 2005 18:03:20 +0000
changeset 1823 cb082cdf3667
parent 1435 8e85e6bbefdf
child 1875 98698b69a902
permissions -rwxr-xr-x
NewMapWin has become Dialog instead of Window. Therefore it is created dynamically, when there is need for it, instead of keeping one instance in memory. This solution is slower, but more correct than before.
     1 /* -*- C++ -*-
     2  * lemon/max_matching.h - Part of LEMON, a generic C++ optimization library
     3  *
     4  * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     5  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     6  *
     7  * Permission to use, modify and distribute this software is granted
     8  * provided that this copyright notice appears in all copies. For
     9  * precise terms see the accompanying LICENSE file.
    10  *
    11  * This software is provided "AS IS" with no warranty of any kind,
    12  * express or implied, and with no claim as to its suitability for any
    13  * purpose.
    14  *
    15  */
    16 
    17 #ifndef LEMON_MAX_MATCHING_H
    18 #define LEMON_MAX_MATCHING_H
    19 
    20 #include <queue>
    21 #include <lemon/invalid.h>
    22 #include <lemon/unionfind.h>
    23 #include <lemon/graph_utils.h>
    24 
    25 ///\ingroup galgs
    26 ///\file
    27 ///\brief Maximum matching algorithm.
    28 
    29 namespace lemon {
    30 
    31   /// \addtogroup galgs
    32   /// @{
    33 
    34   ///Edmonds' alternating forest maximum matching algorithm.
    35 
    36   ///This class provides Edmonds' alternating forest matching
    37   ///algorithm. The starting matching (if any) can be passed to the
    38   ///algorithm using read-in functions \ref readNMapNode, \ref
    39   ///readNMapEdge or \ref readEMapBool depending on the container. The
    40   ///resulting maximum matching can be attained by write-out functions
    41   ///\ref writeNMapNode, \ref writeNMapEdge or \ref writeEMapBool
    42   ///depending on the preferred container. 
    43   ///
    44   ///The dual side of a matching is a map of the nodes to
    45   ///MaxMatching::pos_enum, having values D, A and C showing the
    46   ///Gallai-Edmonds decomposition of the graph. The nodes in D induce
    47   ///a graph with factor-critical components, the nodes in A form the
    48   ///barrier, and the nodes in C induce a graph having a perfect
    49   ///matching. This decomposition can be attained by calling \ref
    50   ///writePos after running the algorithm. 
    51   ///
    52   ///\param Graph The undirected graph type the algorithm runs on.
    53   ///
    54   ///\author Jacint Szabo  
    55   template <typename Graph>
    56   class MaxMatching {
    57 
    58   protected:
    59 
    60     typedef typename Graph::Node Node;
    61     typedef typename Graph::Edge Edge;
    62     typedef typename Graph::UndirEdge UndirEdge;
    63     typedef typename Graph::UndirEdgeIt UndirEdgeIt;
    64     typedef typename Graph::NodeIt NodeIt;
    65     typedef typename Graph::IncEdgeIt IncEdgeIt;
    66 
    67     typedef UnionFindEnum<Node, Graph::template NodeMap> UFE;
    68 
    69   public:
    70     
    71     ///Indicates the Gallai-Edmonds decomposition of the graph.
    72 
    73     ///Indicates the Gallai-Edmonds decomposition of the graph, which
    74     ///shows an upper bound on the size of a maximum matching. The
    75     ///nodes with pos_enum \c D induce a graph with factor-critical
    76     ///components, the nodes in \c A form the canonical barrier, and the
    77     ///nodes in \c C induce a graph having a perfect matching. 
    78     enum pos_enum {
    79       D=0,
    80       A=1,
    81       C=2
    82     }; 
    83 
    84   protected:
    85 
    86     static const int HEUR_density=2;
    87     const Graph& g;
    88     typename Graph::template NodeMap<Node> _mate;
    89     typename Graph::template NodeMap<pos_enum> position;
    90      
    91   public:
    92     
    93     MaxMatching(const Graph& _g) : g(_g), _mate(_g,INVALID), position(_g) {}
    94 
    95     ///Runs Edmonds' algorithm.
    96 
    97     ///Runs Edmonds' algorithm for sparse graphs (number of edges <
    98     ///2*number of nodes), and a heuristical Edmonds' algorithm with a
    99     ///heuristic of postponing shrinks for dense graphs. 
   100     void run() {
   101       if ( countUndirEdges(g) < HEUR_density*countNodes(g) ) {
   102 	greedyMatching();
   103 	runEdmonds(0);
   104       } else runEdmonds(1);
   105     }
   106 
   107 
   108     ///Runs Edmonds' algorithm.
   109     
   110     ///If heur=0 it runs Edmonds' algorithm. If heur=1 it runs
   111     ///Edmonds' algorithm with a heuristic of postponing shrinks,
   112     ///giving a faster algorithm for dense graphs.  
   113     void runEdmonds( int heur = 1 ) {
   114       
   115       for(NodeIt v(g); v!=INVALID; ++v)
   116 	position.set(v,C);      
   117       
   118       typename Graph::template NodeMap<Node> ear(g,INVALID); 
   119       //undefined for the base nodes of the blossoms (i.e. for the
   120       //representative elements of UFE blossom) and for the nodes in C 
   121       
   122       typename UFE::MapType blossom_base(g);
   123       UFE blossom(blossom_base);
   124       typename UFE::MapType tree_base(g);
   125       UFE tree(tree_base);
   126       //If these UFE's would be members of the class then also
   127       //blossom_base and tree_base should be a member.
   128       
   129       for(NodeIt v(g); v!=INVALID; ++v) {
   130 	if ( position[v]==C && _mate[v]==INVALID ) {
   131 	  blossom.insert(v);
   132 	  tree.insert(v); 
   133 	  position.set(v,D);
   134 	  if ( heur == 1 ) lateShrink( v, ear, blossom, tree );
   135 	  else normShrink( v, ear, blossom, tree );
   136 	}
   137       }
   138     }
   139 
   140 
   141     ///Finds a greedy matching starting from the actual matching.
   142     
   143     ///Starting form the actual matching stored, it finds a maximal
   144     ///greedy matching.
   145     void greedyMatching() {
   146       for(NodeIt v(g); v!=INVALID; ++v)
   147 	if ( _mate[v]==INVALID ) {
   148 	  for( IncEdgeIt e(g,v); e!=INVALID ; ++e ) {
   149 	    Node y=g.runningNode(e);
   150 	    if ( _mate[y]==INVALID && y!=v ) {
   151 	      _mate.set(v,y);
   152 	      _mate.set(y,v);
   153 	      break;
   154 	    }
   155 	  }
   156 	} 
   157     }
   158 
   159     ///Returns the size of the actual matching stored.
   160 
   161     ///Returns the size of the actual matching stored. After \ref
   162     ///run() it returns the size of a maximum matching in the graph.
   163     int size() const {
   164       int s=0;
   165       for(NodeIt v(g); v!=INVALID; ++v) {
   166 	if ( _mate[v]!=INVALID ) {
   167 	  ++s;
   168 	}
   169       }
   170       return s/2;
   171     }
   172 
   173 
   174     ///Resets the actual matching to the empty matching.
   175 
   176     ///Resets the actual matching to the empty matching.  
   177     ///
   178     void resetMatching() {
   179       for(NodeIt v(g); v!=INVALID; ++v)
   180 	_mate.set(v,INVALID);      
   181     }
   182 
   183     ///Returns the mate of a node in the actual matching.
   184 
   185     ///Returns the mate of a \c node in the actual matching. 
   186     ///Returns INVALID if the \c node is not covered by the actual matching. 
   187     Node mate(Node& node) const {
   188       return _mate[node];
   189     } 
   190 
   191     ///Reads a matching from a \c Node valued \c Node map.
   192 
   193     ///Reads a matching from a \c Node valued \c Node map. This map
   194     ///must be \e symmetric, i.e. if \c map[u]==v then \c map[v]==u
   195     ///must hold, and \c uv will be an edge of the matching.
   196     template<typename NMapN>
   197     void readNMapNode(NMapN& map) {
   198       for(NodeIt v(g); v!=INVALID; ++v) {
   199 	_mate.set(v,map[v]);   
   200       } 
   201     } 
   202     
   203     ///Writes the stored matching to a \c Node valued \c Node map.
   204 
   205     ///Writes the stored matching to a \c Node valued \c Node map. The
   206     ///resulting map will be \e symmetric, i.e. if \c map[u]==v then \c
   207     ///map[v]==u will hold, and now \c uv is an edge of the matching.
   208     template<typename NMapN>
   209     void writeNMapNode (NMapN& map) const {
   210       for(NodeIt v(g); v!=INVALID; ++v) {
   211 	map.set(v,_mate[v]);   
   212       } 
   213     } 
   214 
   215     ///Reads a matching from an \c UndirEdge valued \c Node map.
   216 
   217     ///Reads a matching from an \c UndirEdge valued \c Node map. \c
   218     ///map[v] must be an \c UndirEdge incident to \c v. This map must
   219     ///have the property that if \c g.oppositeNode(u,map[u])==v then
   220     ///\c \c g.oppositeNode(v,map[v])==u holds, and now some edge
   221     ///joining \c u to \c v will be an edge of the matching.
   222     template<typename NMapE>
   223     void readNMapEdge(NMapE& map) {
   224      for(NodeIt v(g); v!=INVALID; ++v) {
   225        UndirEdge e=map[v];
   226 	if ( e!=INVALID )
   227 	  _mate.set(v,g.oppositeNode(v,e));
   228       } 
   229     } 
   230     
   231     ///Writes the matching stored to an \c UndirEdge valued \c Node map.
   232 
   233     ///Writes the stored matching to an \c UndirEdge valued \c Node
   234     ///map. \c map[v] will be an \c UndirEdge incident to \c v. This
   235     ///map will have the property that if \c g.oppositeNode(u,map[u])
   236     ///== v then \c map[u]==map[v] holds, and now this edge is an edge
   237     ///of the matching.
   238     template<typename NMapE>
   239     void writeNMapEdge (NMapE& map)  const {
   240       typename Graph::template NodeMap<bool> todo(g,true); 
   241       for(NodeIt v(g); v!=INVALID; ++v) {
   242 	if ( todo[v] && _mate[v]!=INVALID ) {
   243 	  Node u=_mate[v];
   244 	  for(IncEdgeIt e(g,v); e!=INVALID; ++e) {
   245 	    if ( g.runningNode(e) == u ) {
   246 	      map.set(u,e);
   247 	      map.set(v,e);
   248 	      todo.set(u,false);
   249 	      todo.set(v,false);
   250 	      break;
   251 	    }
   252 	  }
   253 	}
   254       } 
   255     }
   256 
   257 
   258     ///Reads a matching from a \c bool valued \c Edge map.
   259     
   260     ///Reads a matching from a \c bool valued \c Edge map. This map
   261     ///must have the property that there are no two incident edges \c
   262     ///e, \c f with \c map[e]==map[f]==true. The edges \c e with \c
   263     ///map[e]==true form the matching.
   264     template<typename EMapB>
   265     void readEMapBool(EMapB& map) {
   266       for(UndirEdgeIt e(g); e!=INVALID; ++e) {
   267 	if ( map[e] ) {
   268 	  Node u=g.source(e);	  
   269 	  Node v=g.target(e);
   270 	  _mate.set(u,v);
   271 	  _mate.set(v,u);
   272 	} 
   273       } 
   274     }
   275 
   276 
   277     ///Writes the matching stored to a \c bool valued \c Edge map.
   278 
   279     ///Writes the matching stored to a \c bool valued \c Edge
   280     ///map. This map will have the property that there are no two
   281     ///incident edges \c e, \c f with \c map[e]==map[f]==true. The
   282     ///edges \c e with \c map[e]==true form the matching.
   283     template<typename EMapB>
   284     void writeEMapBool (EMapB& map) const {
   285       for(UndirEdgeIt e(g); e!=INVALID; ++e) map.set(e,false);
   286 
   287       typename Graph::template NodeMap<bool> todo(g,true); 
   288       for(NodeIt v(g); v!=INVALID; ++v) {
   289 	if ( todo[v] && _mate[v]!=INVALID ) {
   290 	  Node u=_mate[v];
   291 	  for(IncEdgeIt e(g,v); e!=INVALID; ++e) {
   292 	    if ( g.runningNode(e) == u ) {
   293 	      map.set(e,true);
   294 	      todo.set(u,false);
   295 	      todo.set(v,false);
   296 	      break;
   297 	    }
   298 	  }
   299 	}
   300       } 
   301     }
   302 
   303 
   304     ///Writes the canonical decomposition of the graph after running
   305     ///the algorithm.
   306 
   307     ///After calling any run methods of the class, it writes the
   308     ///Gallai-Edmonds canonical decomposition of the graph. \c map
   309     ///must be a node map of \ref pos_enum 's.
   310     template<typename NMapEnum>
   311     void writePos (NMapEnum& map) const {
   312       for(NodeIt v(g); v!=INVALID; ++v)  map.set(v,position[v]);
   313     }
   314 
   315   private: 
   316 
   317  
   318     void lateShrink(Node v, typename Graph::template NodeMap<Node>& ear,  
   319 		    UFE& blossom, UFE& tree);
   320 
   321     void normShrink(Node v, typename Graph::template NodeMap<Node>& ear,  
   322 		    UFE& blossom, UFE& tree);
   323 
   324     bool noShrinkStep(Node x, typename Graph::template NodeMap<Node>& ear,  
   325 		      UFE& blossom, UFE& tree, std::queue<Node>& Q);
   326 
   327     void shrinkStep(Node& top, Node& middle, Node& bottom,
   328 		    typename Graph::template NodeMap<Node>& ear,  
   329 		    UFE& blossom, UFE& tree, std::queue<Node>& Q);
   330 
   331     void augment(Node x, typename Graph::template NodeMap<Node>& ear,  
   332 		 UFE& blossom, UFE& tree);
   333 
   334   };
   335 
   336 
   337   // **********************************************************************
   338   //  IMPLEMENTATIONS
   339   // **********************************************************************
   340 
   341 
   342   template <typename Graph>
   343   void MaxMatching<Graph>::lateShrink(Node v, typename Graph::template NodeMap<Node>& ear,  
   344 				      UFE& blossom, UFE& tree) {
   345 
   346     std::queue<Node> Q;   //queue of the totally unscanned nodes
   347     Q.push(v);  
   348     std::queue<Node> R;   
   349     //queue of the nodes which must be scanned for a possible shrink
   350       
   351     while ( !Q.empty() ) {
   352       Node x=Q.front();
   353       Q.pop();
   354       if ( noShrinkStep( x, ear, blossom, tree, Q ) ) return;
   355       else R.push(x);
   356     }
   357       
   358     while ( !R.empty() ) {
   359       Node x=R.front();
   360       R.pop();
   361 	
   362       for( IncEdgeIt e(g,x); e!=INVALID ; ++e ) {
   363 	Node y=g.runningNode(e);
   364 
   365 	if ( position[y] == D && blossom.find(x) != blossom.find(y) ) { 
   366 	  //x and y must be in the same tree
   367 	
   368 	  typename Graph::template NodeMap<bool> path(g,false);
   369 
   370 	  Node b=blossom.find(x);
   371 	  path.set(b,true);
   372 	  b=_mate[b];
   373 	  while ( b!=INVALID ) { 
   374 	    b=blossom.find(ear[b]);
   375 	    path.set(b,true);
   376 	    b=_mate[b];
   377 	  } //going till the root
   378 	
   379 	  Node top=y;
   380 	  Node middle=blossom.find(top);
   381 	  Node bottom=x;
   382 	  while ( !path[middle] )
   383 	    shrinkStep(top, middle, bottom, ear, blossom, tree, Q);
   384 		  
   385 	  Node base=middle;
   386 	  top=x;
   387 	  middle=blossom.find(top);
   388 	  bottom=y;
   389 	  Node blossom_base=blossom.find(base);
   390 	  while ( middle!=blossom_base )
   391 	    shrinkStep(top, middle, bottom, ear, blossom, tree, Q);
   392 		  
   393 	  blossom.makeRep(base);
   394 	} // if shrink is needed
   395 
   396 	while ( !Q.empty() ) {
   397 	  Node x=Q.front();
   398 	  Q.pop();
   399 	  if ( noShrinkStep(x, ear, blossom, tree, Q) ) return;
   400 	  else R.push(x);
   401 	}
   402       } //for e
   403     } // while ( !R.empty() )
   404   }
   405 
   406 
   407   template <typename Graph>
   408   void MaxMatching<Graph>::normShrink(Node v,
   409 				      typename Graph::template
   410 				      NodeMap<Node>& ear,  
   411 				      UFE& blossom, UFE& tree) {
   412     std::queue<Node> Q;   //queue of the unscanned nodes
   413     Q.push(v);  
   414     while ( !Q.empty() ) {
   415 
   416       Node x=Q.front();
   417       Q.pop();
   418 	
   419       for( IncEdgeIt e(g,x); e!=INVALID; ++e ) {
   420 	Node y=g.runningNode(e);
   421 	      
   422 	switch ( position[y] ) {
   423 	case D:          //x and y must be in the same tree
   424 
   425 	  if ( blossom.find(x) != blossom.find(y) ) { //shrink
   426 	    typename Graph::template NodeMap<bool> path(g,false);
   427 	      
   428 	    Node b=blossom.find(x);
   429 	    path.set(b,true);
   430 	    b=_mate[b];
   431 	    while ( b!=INVALID ) { 
   432 	      b=blossom.find(ear[b]);
   433 	      path.set(b,true);
   434 	      b=_mate[b];
   435 	    } //going till the root
   436 	
   437 	    Node top=y;
   438 	    Node middle=blossom.find(top);
   439 	    Node bottom=x;
   440 	    while ( !path[middle] )
   441 	      shrinkStep(top, middle, bottom, ear, blossom, tree, Q);
   442 		
   443 	    Node base=middle;
   444 	    top=x;
   445 	    middle=blossom.find(top);
   446 	    bottom=y;
   447 	    Node blossom_base=blossom.find(base);
   448 	    while ( middle!=blossom_base )
   449 	      shrinkStep(top, middle, bottom, ear, blossom, tree, Q);
   450 		
   451 	    blossom.makeRep(base);
   452 	  }
   453 	  break;
   454 	case C:
   455 	  if ( _mate[y]!=INVALID ) {   //grow
   456 
   457 	    ear.set(y,x);
   458 	    Node w=_mate[y];
   459 	    blossom.insert(w);
   460 	    position.set(y,A); 
   461 	    position.set(w,D); 
   462 	    tree.insert(y);
   463 	    tree.insert(w);
   464 	    tree.join(y,blossom.find(x));  
   465 	    tree.join(w,y);  
   466 	    Q.push(w);
   467 	  } else {                 //augment  
   468 	    augment(x, ear, blossom, tree);
   469 	    _mate.set(x,y);
   470 	    _mate.set(y,x);
   471 	    return;
   472 	  } //if 
   473 	  break;
   474 	default: break;
   475 	}
   476       }
   477     }
   478   }
   479 
   480   template <typename Graph>
   481   bool MaxMatching<Graph>::noShrinkStep(Node x,
   482 					typename Graph::template 
   483 					NodeMap<Node>& ear,  
   484 					UFE& blossom, UFE& tree,
   485 					std::queue<Node>& Q) {
   486     for( IncEdgeIt e(g,x); e!= INVALID; ++e ) {
   487       Node y=g.runningNode(e);
   488 	
   489       if ( position[y]==C ) {
   490 	if ( _mate[y]!=INVALID ) {       //grow
   491 	  ear.set(y,x);
   492 	  Node w=_mate[y];
   493 	  blossom.insert(w);
   494 	  position.set(y,A);
   495 	  position.set(w,D);
   496 	  tree.insert(y);
   497 	  tree.insert(w);
   498 	  tree.join(y,blossom.find(x));  
   499 	  tree.join(w,y);  
   500 	  Q.push(w);
   501 	} else {                      //augment 
   502 	  augment(x, ear, blossom, tree);
   503 	  _mate.set(x,y);
   504 	  _mate.set(y,x);
   505 	  return true;
   506 	}
   507       }
   508     }
   509     return false;
   510   }
   511 
   512   template <typename Graph>
   513   void MaxMatching<Graph>::shrinkStep(Node& top, Node& middle, Node& bottom,
   514 				      typename Graph::template
   515 				      NodeMap<Node>& ear,  
   516 				      UFE& blossom, UFE& tree,
   517 				      std::queue<Node>& Q) {
   518     ear.set(top,bottom);
   519     Node t=top;
   520     while ( t!=middle ) {
   521       Node u=_mate[t];
   522       t=ear[u];
   523       ear.set(t,u);
   524     } 
   525     bottom=_mate[middle];
   526     position.set(bottom,D);
   527     Q.push(bottom);
   528     top=ear[bottom];		
   529     Node oldmiddle=middle;
   530     middle=blossom.find(top);
   531     tree.erase(bottom);
   532     tree.erase(oldmiddle);
   533     blossom.insert(bottom);
   534     blossom.join(bottom, oldmiddle);
   535     blossom.join(top, oldmiddle);
   536   }
   537 
   538   template <typename Graph>
   539   void MaxMatching<Graph>::augment(Node x,
   540 				   typename Graph::template NodeMap<Node>& ear,  
   541 				   UFE& blossom, UFE& tree) { 
   542     Node v=_mate[x];
   543     while ( v!=INVALID ) {
   544 	
   545       Node u=ear[v];
   546       _mate.set(v,u);
   547       Node tmp=v;
   548       v=_mate[u];
   549       _mate.set(u,tmp);
   550     }
   551     typename UFE::ItemIt it;
   552     for (tree.first(it,blossom.find(x)); tree.valid(it); tree.next(it)) {   
   553       if ( position[it] == D ) {
   554 	typename UFE::ItemIt b_it;
   555 	for (blossom.first(b_it,it); blossom.valid(b_it); blossom.next(b_it)) {  
   556 	  position.set( b_it ,C);
   557 	}
   558 	blossom.eraseClass(it);
   559       } else position.set( it ,C);
   560     }
   561     tree.eraseClass(x);
   562 
   563   }
   564 
   565   /// @}
   566   
   567 } //END OF NAMESPACE LEMON
   568 
   569 #endif //LEMON_MAX_MATCHING_H