/* -*- C++ -*- * * This file is a part of LEMON, a generic C++ optimization library * * Copyright (C) 2003-2007 * 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 #include #include #include ///\ingroup matching ///\file ///\brief Maximum matching algorithm in undirected 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 graph. The nodes ///in \c D induce a graph with factor-critical components, the nodes ///in \c A form the barrier, and the nodes in \c C induce a graph ///having a perfect matching. This decomposition can be attained by ///calling \c decomposition() after running the algorithm. /// ///\param Graph The undirected graph type the algorithm runs on. /// ///\author Jacint Szabo template class MaxMatching { protected: typedef typename Graph::Node Node; typedef typename Graph::Edge Edge; typedef typename Graph::UEdge UEdge; typedef typename Graph::UEdgeIt UEdgeIt; typedef typename Graph::NodeIt NodeIt; typedef typename Graph::IncEdgeIt IncEdgeIt; typedef typename Graph::template NodeMap UFECrossRef; typedef UnionFindEnum UFE; typedef std::vector NV; typedef typename Graph::template NodeMap EFECrossRef; typedef ExtendFindEnum EFE; public: ///\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 DecompType \c D induce a graph with factor-critical ///components, the nodes in \c A form the canonical barrier, and the ///nodes in \c C induce a graph 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 _mate; typename Graph::template NodeMap 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 edge of the initial ///matching. template 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 edges. /// ///Initialize the matching from an \c UEdge valued \c Node map. \c ///map[v] must be an \c UEdge 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 edge joining \c ///u to \c v will be an edge of the matching. template void matchingMapInit(MatchingMap& map) { for(NodeIt v(g); v!=INVALID; ++v) { position.set(v,C); UEdge 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 edges. /// ///Initialize the matching from a \c bool valued \c UEdge map. This ///map must have the property that there are no two incident edges ///\c e, \c f with \c map[e]==map[f]==true. The edges \c e with \c ///map[e]==true form the matching. template void matchingInit(MatchingMap& map) { for(NodeIt v(g); v!=INVALID; ++v) { _mate.set(v,INVALID); position.set(v,C); } for(UEdgeIt e(g); e!=INVALID; ++e) { if ( map[e] ) { Node u=g.source(e); Node v=g.target(e); _mate.set(u,v); _mate.set(v,u); } } } ///\brief Runs Edmonds' algorithm. /// ///Runs Edmonds' algorithm for sparse graphs (number of edges < ///2*number of nodes), and a heuristical Edmonds' algorithm with a ///heuristic of postponing shrinks for dense graphs. void run() { if (countUEdges(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 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 graphs. void startDense() { typename Graph::template NodeMap 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 graph. int size() const { int s=0; for(NodeIt v(g); v!=INVALID; ++v) { if ( _mate[v]!=INVALID ) { ++s; } } return s/2; } ///\brief Returns the mate of a node in the actual matching. /// ///Returns the mate of a \c node in the actual matching. ///Returns INVALID if the \c node is not covered by the actual matching. Node mate(const Node& node) const { return _mate[node]; } ///\brief Returns the matching edge incident to the given node. /// ///Returns the matching edge of a \c node in the actual matching. ///Returns INVALID if the \c node is not covered by the actual matching. UEdge matchingEdge(const Node& node) const { if (_mate[node] == INVALID) return INVALID; Node n = node < _mate[node] ? node : _mate[node]; for (IncEdgeIt e(g, n); e != INVALID; ++e) { if (g.oppositeNode(n, e) == _mate[n]) { return e; } } return INVALID; } /// \brief Returns the class of the node in the Edmonds-Gallai /// decomposition. /// /// Returns the class of the node in the Edmonds-Gallai /// decomposition. DecompType decomposition(const Node& n) { return position[n] == A; } /// \brief Returns true when the node is in the barrier. /// /// Returns true when the node is in the barrier. bool barrier(const Node& n) { return position[n] == A; } ///\brief Gives back the matching in a \c Node of mates. /// ///Writes the stored matching to a \c Node valued \c Node map. The ///resulting map will be \e symmetric, i.e. if \c map[u]==v then \c ///map[v]==u will hold, and now \c uv is an edge of the matching. template void mateMap(MateMap& map) const { for(NodeIt v(g); v!=INVALID; ++v) { map.set(v,_mate[v]); } } ///\brief Gives back the matching in an \c UEdge valued \c Node ///map. /// ///Writes the stored matching to an \c UEdge valued \c Node ///map. \c map[v] will be an \c UEdge incident to \c v. This ///map will have the property that if \c g.oppositeNode(u,map[u]) ///== v then \c map[u]==map[v] holds, and now this edge is an edge ///of the matching. template void matchingMap(MatchingMap& map) const { typename Graph::template NodeMap todo(g,true); for(NodeIt v(g); v!=INVALID; ++v) { if (_mate[v]!=INVALID && v < _mate[v]) { Node u=_mate[v]; for(IncEdgeIt e(g,v); e!=INVALID; ++e) { if ( g.runningNode(e) == u ) { map.set(u,e); map.set(v,e); todo.set(u,false); todo.set(v,false); break; } } } } } ///\brief Gives back the matching in a \c bool valued \c UEdge ///map. /// ///Writes the matching stored to a \c bool valued \c Edge ///map. This map will have the property that there are no two ///incident edges \c e, \c f with \c map[e]==map[f]==true. The ///edges \c e with \c map[e]==true form the matching. template void matching(MatchingMap& map) const { for(UEdgeIt e(g); e!=INVALID; ++e) map.set(e,false); typename Graph::template NodeMap todo(g,true); for(NodeIt v(g); v!=INVALID; ++v) { if ( todo[v] && _mate[v]!=INVALID ) { Node u=_mate[v]; for(IncEdgeIt e(g,v); e!=INVALID; ++e) { if ( g.runningNode(e) == u ) { map.set(e,true); todo.set(u,false); todo.set(v,false); break; } } } } } ///\brief Returns the canonical decomposition of the graph after running ///the algorithm. /// ///After calling any run methods of the class, it writes the ///Gallai-Edmonds canonical decomposition of the graph. \c map ///must be a node map of \ref DecompType 's. template void decomposition(DecompositionMap& map) const { for(NodeIt v(g); v!=INVALID; ++v) map.set(v,position[v]); } ///\brief Returns a barrier on the nodes. /// ///After calling any run methods of the class, it writes a ///canonical barrier on the nodes. The odd component number of the ///remaining graph minus the barrier size is a lower bound for the ///uncovered nodes in the graph. The \c map must be a node map of ///bools. template void barrier(BarrierMap& barrier) { for(NodeIt v(g); v!=INVALID; ++v) barrier.set(v,position[v] == A); } private: void lateShrink(Node v, typename Graph::template NodeMap& ear, UFE& blossom, NV& rep, EFE& tree) { //We have one tree which we grow, and also shrink but only if it //cannot be postponed. If we augment then we return to the "for" //cycle of runEdmonds(). std::queue Q; //queue of the totally unscanned nodes Q.push(v); std::queue R; //queue of the nodes which must be scanned for a possible shrink while ( !Q.empty() ) { Node x=Q.front(); Q.pop(); for( IncEdgeIt e(g,x); e!= INVALID; ++e ) { Node y=g.runningNode(e); //growOrAugment grows if y is covered by the matching and //augments if not. In this latter case it returns 1. if (position[y]==C && growOrAugment(y, x, ear, blossom, rep, tree, Q)) return; } R.push(x); } while ( !R.empty() ) { Node x=R.front(); R.pop(); for( IncEdgeIt e(g,x); e!=INVALID ; ++e ) { Node y=g.runningNode(e); if ( position[y] == D && blossom.find(x) != blossom.find(y) ) //Recall that we have only one tree. shrink( x, y, ear, blossom, rep, tree, Q); while ( !Q.empty() ) { Node z=Q.front(); Q.pop(); for( IncEdgeIt f(g,z); f!= INVALID; ++f ) { Node w=g.runningNode(f); //growOrAugment grows if y is covered by the matching and //augments if not. In this latter case it returns 1. if (position[w]==C && growOrAugment(w, z, ear, blossom, rep, tree, Q)) return; } R.push(z); } } //for e } // while ( !R.empty() ) } void normShrink(Node v, typename Graph::template NodeMap& ear, UFE& blossom, NV& rep, EFE& tree) { //We have one tree, which we grow and shrink. If we augment then we //return to the "for" cycle of runEdmonds(). std::queue Q; //queue of the unscanned nodes Q.push(v); while ( !Q.empty() ) { Node x=Q.front(); Q.pop(); for( IncEdgeIt e(g,x); e!=INVALID; ++e ) { Node y=g.runningNode(e); switch ( position[y] ) { case D: //x and y must be in the same tree if ( blossom.find(x) != blossom.find(y)) //x and y are in the same tree shrink(x, y, ear, blossom, rep, tree, Q); break; case C: //growOrAugment grows if y is covered by the matching and //augments if not. In this latter case it returns 1. if (growOrAugment(y, x, ear, blossom, rep, tree, Q)) return; break; default: break; } } } } void shrink(Node x,Node y, typename Graph::template NodeMap& ear, UFE& blossom, NV& rep, EFE& tree,std::queue& Q) { //x and y are the two adjacent vertices in two blossoms. typename Graph::template NodeMap path(g,false); Node b=rep[blossom.find(x)]; path.set(b,true); b=_mate[b]; while ( b!=INVALID ) { b=rep[blossom.find(ear[b])]; path.set(b,true); b=_mate[b]; } //we go until the root through bases of blossoms and odd vertices Node top=y; Node middle=rep[blossom.find(top)]; Node bottom=x; while ( !path[middle] ) shrinkStep(top, middle, bottom, ear, blossom, rep, tree, Q); //Until we arrive to a node on the path, we update blossom, tree //and the positions of the odd nodes. Node base=middle; top=x; middle=rep[blossom.find(top)]; bottom=y; Node blossom_base=rep[blossom.find(base)]; while ( middle!=blossom_base ) shrinkStep(top, middle, bottom, ear, blossom, rep, tree, Q); //Until we arrive to a node on the path, we update blossom, tree //and the positions of the odd nodes. rep[blossom.find(base)] = base; } void shrinkStep(Node& top, Node& middle, Node& bottom, typename Graph::template NodeMap& ear, UFE& blossom, NV& rep, EFE& tree, std::queue& Q) { //We traverse a blossom and update everything. ear.set(top,bottom); Node t=top; while ( t!=middle ) { Node u=_mate[t]; t=ear[u]; ear.set(t,u); } bottom=_mate[middle]; position.set(bottom,D); Q.push(bottom); top=ear[bottom]; Node oldmiddle=middle; middle=rep[blossom.find(top)]; tree.erase(bottom); tree.erase(oldmiddle); blossom.insert(bottom); blossom.join(bottom, oldmiddle); blossom.join(top, oldmiddle); } bool growOrAugment(Node& y, Node& x, typename Graph::template NodeMap& ear, UFE& blossom, NV& rep, EFE& tree, std::queue& Q) { //x is in a blossom in the tree, y is outside. If y is covered by //the matching we grow, otherwise we augment. In this case we //return 1. if ( _mate[y]!=INVALID ) { //grow ear.set(y,x); Node w=_mate[y]; rep[blossom.insert(w)] = w; position.set(y,A); position.set(w,D); int t = tree.find(rep[blossom.find(x)]); tree.insert(y,t); tree.insert(w,t); Q.push(w); } else { //augment augment(x, ear, blossom, rep, tree); _mate.set(x,y); _mate.set(y,x); return true; } return false; } void augment(Node x, typename Graph::template NodeMap& ear, UFE& blossom, NV& rep, EFE& tree) { Node v=_mate[x]; while ( v!=INVALID ) { Node u=ear[v]; _mate.set(v,u); Node tmp=v; v=_mate[u]; _mate.set(u,tmp); } int y = tree.find(rep[blossom.find(x)]); for (typename EFE::ItemIt tit(tree, y); tit != INVALID; ++tit) { if ( position[tit] == D ) { int b = blossom.find(tit); for (typename UFE::ItemIt bit(blossom, b); bit != INVALID; ++bit) { position.set(bit, C); } blossom.eraseClass(b); } else position.set(tit, C); } tree.eraseClass(y); } }; } //END OF NAMESPACE LEMON #endif //LEMON_MAX_MATCHING_H