COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/pr_bipartite_matching.h @ 2462:7a096a6bf53a

Last change on this file since 2462:7a096a6bf53a was 2462:7a096a6bf53a, checked in by Balazs Dezso, 17 years ago

Common interface for bipartite matchings
Some useful query function for push-relabel based matching

The naming should be rethink for these classes
for example: pr-ap prefix for push-relabel and augmenting path
algorithms

File size: 17.5 KB
Line 
1/* -*- C++ -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library
4 *
5 * Copyright (C) 2003-2007
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
18
19#ifndef LEMON_PR_BIPARTITE_MATCHING
20#define LEMON_PR_BIPARTITE_MATCHING
21
22#include <lemon/graph_utils.h>
23#include <lemon/iterable_maps.h>
24#include <iostream>
25#include <queue>
26#include <lemon/elevator.h>
27
28///\ingroup matching
29///\file
30///\brief Push-prelabel maximum matching algorithms in bipartite graphs.
31///
32namespace lemon {
33
34  ///Max cardinality matching algorithm based on push-relabel principle
35
36  ///\ingroup matching
37  ///Bipartite Max Cardinality Matching algorithm. This class uses the
38  ///push-relabel principle which in several cases has better runtime
39  ///performance than the augmenting path solutions.
40  ///
41  ///\author Alpar Juttner
42  template<class Graph>
43  class PrBipartiteMatching {
44    typedef typename Graph::Node Node;
45    typedef typename Graph::ANodeIt ANodeIt;
46    typedef typename Graph::BNodeIt BNodeIt;
47    typedef typename Graph::UEdge UEdge;
48    typedef typename Graph::UEdgeIt UEdgeIt;
49    typedef typename Graph::IncEdgeIt IncEdgeIt;
50   
51    const Graph &_g;
52    int _node_num;
53    int _matching_size;
54    int _empty_level;
55   
56    typename Graph::template ANodeMap<typename Graph::UEdge> _matching;
57    Elevator<Graph,typename Graph::BNode> _levels;
58    typename Graph::template BNodeMap<int> _cov;
59
60  public:
61
62    PrBipartiteMatching(const Graph &g) :
63      _g(g),
64      _node_num(countBNodes(g)),
65      _matching(g),
66      _levels(g,_node_num),
67      _cov(g,0)
68    {
69    }
70   
71    /// \name Execution control
72    /// The simplest way to execute the algorithm is to use one of the
73    /// member functions called \c run(). \n
74    /// If you need more control on the execution, first
75    /// you must call \ref init() and then one variant of the start()
76    /// member.
77
78    /// @{
79
80    ///Initialize the data structures
81
82    ///This function constructs a prematching first, which is a
83    ///regular matching on the A-side of the graph, but on the B-side
84    ///each node could cover more matching edges. After that, the
85    ///B-nodes which multiple matched, will be pushed into the lowest
86    ///level of the Elevator. The remaning B-nodes will be pushed to
87    ///the consequent levels respect to a Bfs on following graph: the
88    ///nodes are the B-nodes of the original bipartite graph and two
89    ///nodes are adjacent if a node can pass over a matching edge to
90    ///an other node. The source of the Bfs are the lowest level
91    ///nodes. Last, the reached B-nodes without covered matching edge
92    ///becomes active.
93    void init() {
94      _matching_size=0;
95      _empty_level=_node_num;
96      for(ANodeIt n(_g);n!=INVALID;++n)
97        if((_matching[n]=IncEdgeIt(_g,n))!=INVALID)
98          ++_cov[_g.bNode(_matching[n])];
99
100      std::queue<Node> q;
101      _levels.initStart();
102      for(BNodeIt n(_g);n!=INVALID;++n)
103        if(_cov[n]>1) {
104          _levels.initAddItem(n);
105          q.push(n);
106        }
107      int hlev=0;
108      while(!q.empty()) {
109        Node n=q.front();
110        q.pop();
111        int nlev=_levels[n]+1;
112        for(IncEdgeIt e(_g,n);e!=INVALID;++e) {
113          Node m=_g.runningNode(e);
114          if(e==_matching[m]) {
115            for(IncEdgeIt f(_g,m);f!=INVALID;++f) {
116              Node r=_g.runningNode(f);
117              if(_levels[r]>nlev) {
118                for(;nlev>hlev;hlev++)
119                  _levels.initNewLevel();
120                _levels.initAddItem(r);
121                q.push(r);
122              }
123            }
124          }
125        }
126      }
127      _levels.initFinish();
128      for(BNodeIt n(_g);n!=INVALID;++n)
129        if(_cov[n]<1&&_levels[n]<_node_num)
130          _levels.activate(n);
131    }
132
133    ///Start the main phase of the algorithm
134   
135    ///This algorithm calculates the maximum matching with the
136    ///push-relabel principle. This function should be called just
137    ///after the init() function which already set the initial
138    ///prematching, the level function on the B-nodes and the active,
139    ///ie. unmatched B-nodes.
140    ///
141    ///The algorithm always takes highest active B-node, and it try to
142    ///find a B-node which is eligible to pass over one of it's
143    ///matching edge. This condition holds when the B-node is one
144    ///level lower, and the opposite node of it's matching edge is
145    ///adjacent to the highest active node. In this case the current
146    ///node steals the matching edge and becomes inactive. If there is
147    ///not eligible node then the highest active node should be lift
148    ///to the next proper level.
149    ///
150    ///The nodes should not lift higher than the number of the
151    ///B-nodes, if a node reach this level it remains unmatched. If
152    ///during the execution one level becomes empty the nodes above it
153    ///can be deactivated and lift to the highest level.
154    void start() {
155      Node act;
156      Node bact=INVALID;
157      Node last_activated=INVALID;
158      while((act=_levels.highestActive())!=INVALID) {
159        last_activated=INVALID;
160        int actlevel=_levels[act];
161       
162        UEdge bedge=INVALID;
163        int nlevel=_node_num;
164        {
165          int nnlevel;
166          for(IncEdgeIt tbedge(_g,act);
167              tbedge!=INVALID && nlevel>=actlevel;
168              ++tbedge)
169            if((nnlevel=_levels[_g.bNode(_matching[_g.runningNode(tbedge)])])<
170               nlevel)
171              {
172                nlevel=nnlevel;
173                bedge=tbedge;
174              }
175        }
176        if(nlevel<_node_num) {
177          if(nlevel>=actlevel)
178            _levels.liftHighestActiveTo(nlevel+1);
179          bact=_g.bNode(_matching[_g.aNode(bedge)]);
180          if(--_cov[bact]<1) {
181            _levels.activate(bact);
182            last_activated=bact;
183          }
184          _matching[_g.aNode(bedge)]=bedge;
185          _cov[act]=1;
186          _levels.deactivate(act);
187        }
188        else {
189          if(_node_num>actlevel)
190            _levels.liftHighestActiveTo(_node_num);
191          _levels.deactivate(act);
192        }
193
194        if(_levels.onLevel(actlevel)==0)
195          _levels.liftToTop(actlevel);
196      }
197     
198      _matching_size = _node_num;
199      for(ANodeIt n(_g);n!=INVALID;++n)
200        if(_matching[n]==INVALID) _matching_size--;
201        else if (_cov[_g.bNode(_matching[n])]>1) {
202          _cov[_g.bNode(_matching[n])]--;
203          _matching_size--;
204          _matching[n]=INVALID;
205        }
206    }
207
208    ///Start the algorithm to find a perfect matching
209
210    ///This function is close to identical to the simple start()
211    ///member function but it calculates just perfect matching.
212    ///However, the perfect property is only checked on the B-side of
213    ///the graph
214    ///
215    ///The main difference between the two function is the handling of
216    ///the empty levels. The simple start() function let the nodes
217    ///above the empty levels unmatched while this variant if it find
218    ///an empty level immediately terminates and gives back false
219    ///return value.
220    bool startPerfect() {
221      Node act;
222      Node bact=INVALID;
223      Node last_activated=INVALID;
224      while((act=_levels.highestActive())!=INVALID) {
225        last_activated=INVALID;
226        int actlevel=_levels[act];
227       
228        UEdge bedge=INVALID;
229        int nlevel=_node_num;
230        {
231          int nnlevel;
232          for(IncEdgeIt tbedge(_g,act);
233              tbedge!=INVALID && nlevel>=actlevel;
234              ++tbedge)
235            if((nnlevel=_levels[_g.bNode(_matching[_g.runningNode(tbedge)])])<
236               nlevel)
237              {
238                nlevel=nnlevel;
239                bedge=tbedge;
240              }
241        }
242        if(nlevel<_node_num) {
243          if(nlevel>=actlevel)
244            _levels.liftHighestActiveTo(nlevel+1);
245          bact=_g.bNode(_matching[_g.aNode(bedge)]);
246          if(--_cov[bact]<1) {
247            _levels.activate(bact);
248            last_activated=bact;
249          }
250          _matching[_g.aNode(bedge)]=bedge;
251          _cov[act]=1;
252          _levels.deactivate(act);
253        }
254        else {
255          if(_node_num>actlevel)
256            _levels.liftHighestActiveTo(_node_num);
257          _levels.deactivate(act);
258        }
259
260        if(_levels.onLevel(actlevel)==0)
261          _empty_level=actlevel;
262          return false;
263      }
264      return true;
265    }
266 
267    ///Runs the algorithm
268   
269    ///Just a shortcut for the next code:
270    ///\code
271    /// init();
272    /// start();
273    ///\endcode
274    void run() {
275      init();
276      start();
277    }
278   
279    ///Runs the algorithm to find a perfect matching
280   
281    ///Just a shortcut for the next code:
282    ///\code
283    /// init();
284    /// startPerfect();
285    ///\endcode
286    ///
287    ///\note If the two nodesets of the graph have different size then
288    ///this algorithm checks the perfect property on the B-side.
289    bool runPerfect() {
290      init();
291      return startPerfect();
292    }
293
294    ///Runs the algorithm to find a perfect matching
295   
296    ///Just a shortcut for the next code:
297    ///\code
298    /// init();
299    /// startPerfect();
300    ///\endcode
301    ///
302    ///\note It checks that the size of the two nodesets are equal.
303    bool checkedRunPerfect() {
304      if (countANodes(_g) != _node_num) return false;
305      init();
306      return startPerfect();
307    }
308
309    ///@}
310
311    /// \name Query Functions
312    /// The result of the %Matching algorithm can be obtained using these
313    /// functions.\n
314    /// Before the use of these functions,
315    /// either run() or start() must be called.
316    ///@{
317
318    /// \brief Set true all matching uedge in the map.
319    ///
320    /// Set true all matching uedge in the map. It does not change the
321    /// value mapped to the other uedges.
322    /// \return The number of the matching edges.
323    template <typename MatchingMap>
324    int quickMatching(MatchingMap& mm) const {
325      for (ANodeIt n(_g);n!=INVALID;++n) {
326        if (_matching[n]!=INVALID) mm.set(_matching[n],true);
327      }
328      return _matching_size;
329    }
330
331    ///\brief Set true all matching uedge in the map and the others to false.
332
333    ///Set true all matching uedge in the map and the others to false.
334    ///\return The number of the matching edges.
335    template<class MatchingMap>
336    int matching(MatchingMap& mm) const {
337      for (UEdgeIt e(_g);e!=INVALID;++e) {
338        mm.set(e,e==_matching[_g.aNode(e)]);
339      }
340      return _matching_size;
341    }
342
343
344    ///Returns true if the given uedge is in the matching.
345
346    ///It returns true if the given uedge is in the matching.
347    ///
348    bool matchingEdge(const UEdge& e) const {
349      return _matching[_g.aNode(e)]==e;
350    }
351
352    ///Returns the matching edge from the node.
353
354    ///Returns the matching edge from the node. If there is not such
355    ///edge it gives back \c INVALID. 
356    ///\note If the parameter node is a B-node then the running time is
357    ///propotional to the degree of the node.
358    UEdge matchingEdge(const Node& n) const {
359      if (_g.aNode(n)) {
360        return _matching[n];
361      } else {
362        for (IncEdgeIt e(_g,n);e!=INVALID;++e)
363          if (e==_matching[_g.aNode(e)]) return e;
364        return INVALID;
365      }
366    }
367
368    ///Gives back the number of the matching edges.
369
370    ///Gives back the number of the matching edges.
371    int matchingSize() const {
372      return _matching_size;
373    }
374
375    ///Gives back a barrier on the A-nodes
376   
377    ///The barrier is s subset of the nodes on the same side of the
378    ///graph. If we tried to find a perfect matching and it failed
379    ///then the barrier size will be greater than its neighbours. If
380    ///the maximum matching searched then the barrier size minus its
381    ///neighbours will be exactly the unmatched nodes on the A-side.
382    ///\retval bar A WriteMap on the ANodes with bool value.
383    template<class BarrierMap>
384    void aBarrier(BarrierMap &bar) const
385    {
386      for(ANodeIt n(_g);n!=INVALID;++n)
387        bar.set(n,_matching[n]==INVALID ||
388          _levels[_g.bNode(_matching[n])]<_empty_level); 
389    } 
390
391    ///Gives back a barrier on the B-nodes
392   
393    ///The barrier is s subset of the nodes on the same side of the
394    ///graph. If we tried to find a perfect matching and it failed
395    ///then the barrier size will be greater than its neighbours. If
396    ///the maximum matching searched then the barrier size minus its
397    ///neighbours will be exactly the unmatched nodes on the B-side.
398    ///\retval bar A WriteMap on the BNodes with bool value.
399    template<class BarrierMap>
400    void bBarrier(BarrierMap &bar) const
401    {
402      for(BNodeIt n(_g);n!=INVALID;++n) bar.set(n,_levels[n]>=_empty_level); 
403    }
404
405    ///Returns a minimum covering of the nodes.
406
407    ///The minimum covering set problem is the dual solution of the
408    ///maximum bipartite matching. It provides a solution for this
409    ///problem what is proof of the optimality of the matching.
410    ///\param covering NodeMap of bool values, the nodes of the cover
411    ///set will set true while the others false. 
412    ///\return The size of the cover set.
413    ///\note This function can be called just after the algorithm have
414    ///already found a matching.
415    template<class CoverMap>
416    int coverSet(CoverMap& covering) const {
417      int ret=0;
418      for(BNodeIt n(_g);n!=INVALID;++n) {
419        if (_levels[n]<_empty_level) { covering.set(n,true); ++ret; }
420        else covering.set(n,false);
421      }
422      for(ANodeIt n(_g);n!=INVALID;++n) {
423        if (_matching[n]!=INVALID &&
424            _levels[_g.bNode(_matching[n])]>=_empty_level)
425          { covering.set(n,true); ++ret; }
426        else covering.set(n,false);
427      }
428      return ret;
429    }
430
431
432    /// @}
433   
434  };
435 
436 
437  ///Maximum cardinality of the matchings in a bipartite graph
438
439  ///\ingroup matching
440  ///This function finds the maximum cardinality of the matchings
441  ///in a bipartite graph \c g.
442  ///\param g An undirected bipartite graph.
443  ///\return The cardinality of the maximum matching.
444  ///
445  ///\note The the implementation is based
446  ///on the push-relabel principle.
447  template<class Graph>
448  int prBipartiteMatching(const Graph &g)
449  {
450    PrBipartiteMatching<Graph> bpm(g);
451    return bpm.matchingSize();
452  }
453
454  ///Maximum cardinality matching in a bipartite graph
455
456  ///\ingroup matching
457  ///This function finds a maximum cardinality matching
458  ///in a bipartite graph \c g.
459  ///\param g An undirected bipartite graph.
460  ///\retval matching A write UEdgeMap of value type \c bool.
461  /// The found edges will be returned in this map.
462  ///\return The cardinality of the maximum matching.
463  ///
464  ///\note The the implementation is based
465  ///on the push-relabel principle.
466  template<class Graph,class MT>
467  int prBipartiteMatching(const Graph &g,MT &matching)
468  {
469    PrBipartiteMatching<Graph> bpm(g);
470    bpm.run();
471    bpm.matching(matching);
472    return bpm.matchingSize();
473  }
474
475  ///Maximum cardinality matching in a bipartite graph
476
477  ///\ingroup matching
478  ///This function finds a maximum cardinality matching
479  ///in a bipartite graph \c g.
480  ///\param g An undirected bipartite graph.
481  ///\retval matching A write UEdgeMap of value type \c bool.
482  /// The found edges will be returned in this map.
483  ///\retval barrier A \c bool WriteMap on the BNodes. The map will be set
484  /// exactly once for each BNode. The nodes with \c true value represent
485  /// a barrier \e B, i.e. the cardinality of \e B minus the number of its
486  /// neighbor is equal to the number of the <tt>BNode</tt>s minus the
487  /// cardinality of the maximum matching.
488  ///\return The cardinality of the maximum matching.
489  ///
490  ///\note The the implementation is based
491  ///on the push-relabel principle.
492  template<class Graph,class MT, class GT>
493  int prBipartiteMatching(const Graph &g,MT &matching,GT &barrier)
494  {
495    PrBipartiteMatching<Graph> bpm(g);
496    bpm.run();
497    bpm.matching(matching);
498    bpm.bBarrier(barrier);
499    return bpm.matchingSize();
500  } 
501
502  ///Perfect matching in a bipartite graph
503
504  ///\ingroup matching
505  ///This function checks whether the bipartite graph \c g
506  ///has a perfect matching.
507  ///\param g An undirected bipartite graph.
508  ///\return \c true iff \c g has a perfect matching.
509  ///
510  ///\note The the implementation is based
511  ///on the push-relabel principle.
512  template<class Graph>
513  bool prPerfectBipartiteMatching(const Graph &g)
514  {
515    PrBipartiteMatching<Graph> bpm(g);
516    return bpm.runPerfect();
517  }
518
519  ///Perfect matching in a bipartite graph
520
521  ///\ingroup matching
522  ///This function finds a perfect matching in a bipartite graph \c g.
523  ///\param g An undirected bipartite graph.
524  ///\retval matching A write UEdgeMap of value type \c bool.
525  /// The found edges will be returned in this map.
526  /// The values are unchanged if the graph
527  /// has no perfect matching.
528  ///\return \c true iff \c g has a perfect matching.
529  ///
530  ///\note The the implementation is based
531  ///on the push-relabel principle.
532  template<class Graph,class MT>
533  bool prPerfectBipartiteMatching(const Graph &g,MT &matching)
534  {
535    PrBipartiteMatching<Graph> bpm(g);
536    bool ret = bpm.runPerfect();
537    if (ret) bpm.matching(matching);
538    return ret;
539  }
540
541  ///Perfect matching in a bipartite graph
542
543  ///\ingroup matching
544  ///This function finds a perfect matching in a bipartite graph \c g.
545  ///\param g An undirected bipartite graph.
546  ///\retval matching A readwrite UEdgeMap of value type \c bool.
547  /// The found edges will be returned in this map.
548  /// The values are unchanged if the graph
549  /// has no perfect matching.
550  ///\retval barrier A \c bool WriteMap on the BNodes. The map will only
551  /// be set if \c g has no perfect matching. In this case it is set
552  /// exactly once for each BNode. The nodes with \c true value represent
553  /// a barrier, i.e. a subset \e B a of BNodes with the property that
554  /// the cardinality of \e B is greater than the number of its neighbors.
555  ///\return \c true iff \c g has a perfect matching.
556  ///
557  ///\note The the implementation is based
558  ///on the push-relabel principle.
559  template<class Graph,class MT, class GT>
560  int prPerfectBipartiteMatching(const Graph &g,MT &matching,GT &barrier)
561  {
562    PrBipartiteMatching<Graph> bpm(g);
563    bool ret=bpm.runPerfect();
564    if(ret)
565      bpm.matching(matching);
566    else
567      bpm.bBarrier(barrier);
568    return ret;
569  } 
570}
571
572#endif
Note: See TracBrowser for help on using the repository browser.