lemon/hao_orlin.h
author deba
Fri, 29 Sep 2006 11:26:29 +0000
changeset 2224 f973894da54e
child 2225 bb3d5e6f9fcb
permissions -rw-r--r--
Moving the file into correct group
     1 /* -*- C++ -*-
     2  * lemon/hao_orlin.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_HAO_ORLIN_H
    18 #define LEMON_HAO_ORLIN_H
    19 
    20 #include <vector>
    21 #include <queue>
    22 #include <limits>
    23 
    24 #include <lemon/maps.h>
    25 #include <lemon/graph_utils.h>
    26 #include <lemon/graph_adaptor.h>
    27 #include <lemon/iterable_maps.h>
    28  
    29 
    30 /// \file
    31 /// \ingroup flowalgs
    32 /// Implementation of the Hao-Orlin algorithms class for testing network 
    33 /// reliability.
    34 
    35 namespace lemon {
    36 
    37   /// \addtogroup flowalgs
    38   /// @{                                                   
    39 
    40   /// %Hao-Orlin algorithm for calculate minimum cut in directed graphs.
    41   ///
    42   /// Hao-Orlin calculates the minimum cut in directed graphs. It
    43   /// separates the nodes of the graph into two disjoint sets and the
    44   /// summary of the edge capacities go from the first set to the
    45   /// second set is the minimum.  The algorithm is a modified
    46   /// push-relabel preflow algorithm and it calculates the minimum cat
    47   /// in \f$ O(n^3) \f$ time. The purpose of such algorithm is testing
    48   /// network reliability. For sparse undirected graph you can use the
    49   /// algorithm of Nagamochi and Ibraki which solves the undirected
    50   /// problem in \f$ O(n^3) \f$ time. 
    51   ///
    52   /// \author Attila Bernath and Balazs Dezso
    53   template <typename _Graph,
    54 	    typename _CapacityMap = typename _Graph::template EdgeMap<int>,
    55             typename _Tolerance = Tolerance<typename _CapacityMap::Value> >
    56   class HaoOrlin {
    57   protected:
    58 
    59     typedef _Graph Graph;
    60     typedef _CapacityMap CapacityMap;
    61     typedef _Tolerance Tolerance;
    62 
    63     typedef typename CapacityMap::Value Value;
    64 
    65     
    66     typedef typename Graph::Node Node;
    67     typedef typename Graph::NodeIt NodeIt;
    68     typedef typename Graph::EdgeIt EdgeIt;
    69     typedef typename Graph::OutEdgeIt OutEdgeIt;
    70     typedef typename Graph::InEdgeIt InEdgeIt;
    71 
    72     const Graph* _graph;
    73     const CapacityMap* _capacity;
    74 
    75     typedef typename Graph::template EdgeMap<Value> FlowMap;
    76 
    77     FlowMap* _preflow;
    78 
    79     Node _source, _target;
    80     int _node_num;
    81 
    82     typedef ResGraphAdaptor<const Graph, Value, CapacityMap, 
    83                             FlowMap, Tolerance> ResGraph;
    84     typedef typename ResGraph::Node ResNode;
    85     typedef typename ResGraph::NodeIt ResNodeIt;
    86     typedef typename ResGraph::EdgeIt ResEdgeIt;
    87     typedef typename ResGraph::OutEdgeIt ResOutEdgeIt;
    88     typedef typename ResGraph::Edge ResEdge;
    89     typedef typename ResGraph::InEdgeIt ResInEdgeIt;
    90 
    91     ResGraph* _res_graph;
    92 
    93     typedef typename Graph::template NodeMap<ResEdge> CurrentArcMap;
    94     CurrentArcMap* _current_arc;  
    95 
    96 
    97     typedef IterableBoolMap<Graph, Node> WakeMap;
    98     WakeMap* _wake;
    99 
   100     typedef typename Graph::template NodeMap<int> DistMap;
   101     DistMap* _dist;  
   102     
   103     typedef typename Graph::template NodeMap<Value> ExcessMap;
   104     ExcessMap* _excess;
   105 
   106     typedef typename Graph::template NodeMap<bool> SourceSetMap;
   107     SourceSetMap* _source_set;
   108 
   109     std::vector<int> _level_size;
   110 
   111     int _highest_active;
   112     std::vector<std::list<Node> > _active_nodes;
   113 
   114     int _dormant_max;
   115     std::vector<std::list<Node> > _dormant;
   116 
   117 
   118     Value _min_cut;
   119 
   120     typedef typename Graph::template NodeMap<bool> MinCutMap;
   121     MinCutMap* _min_cut_map;
   122 
   123     Tolerance _tolerance;
   124 
   125   public: 
   126 
   127     HaoOrlin(const Graph& graph, const CapacityMap& capacity, 
   128              const Tolerance& tolerance = Tolerance()) :
   129       _graph(&graph), _capacity(&capacity), 
   130       _preflow(0), _source(), _target(), _res_graph(0), _current_arc(0),
   131       _wake(0),_dist(0), _excess(0), _source_set(0), 
   132       _highest_active(), _active_nodes(), _dormant_max(), _dormant(), 
   133       _min_cut(), _min_cut_map(0), _tolerance(tolerance) {}
   134 
   135     ~HaoOrlin() {
   136       if (_res_graph) {
   137         delete _res_graph;
   138       }
   139       if (_min_cut_map) {
   140         delete _min_cut_map;
   141       } 
   142       if (_current_arc) {
   143         delete _current_arc;
   144       }
   145       if (_source_set) {
   146         delete _source_set;
   147       }
   148       if (_excess) {
   149         delete _excess;
   150       }
   151       if (_dist) {
   152         delete _dist;
   153       }
   154       if (_wake) {
   155         delete _wake;
   156       }
   157       if (_preflow) {
   158         delete _preflow;
   159       }
   160     }
   161     
   162   private:
   163     
   164     void relabel(Node i) {
   165       int k = (*_dist)[i];
   166       if (_level_size[k] == 1) {
   167 	++_dormant_max;
   168 	for (NodeIt it(*_graph); it != INVALID; ++it) {
   169 	  if ((*_wake)[it] && (*_dist)[it] >= k) {
   170 	    (*_wake)[it] = false;
   171 	    _dormant[_dormant_max].push_front(it);
   172 	    --_level_size[(*_dist)[it]];
   173 	  }
   174 	}
   175 	--_highest_active;
   176       } else {
   177 	ResOutEdgeIt e(*_res_graph, i);
   178 	while (e != INVALID && !(*_wake)[_res_graph->target(e)]) {
   179 	  ++e;
   180 	}
   181 
   182 	if (e == INVALID){
   183 	  ++_dormant_max;
   184 	  (*_wake)[i] = false;
   185 	  _dormant[_dormant_max].push_front(i);
   186 	  --_level_size[(*_dist)[i]];
   187 	} else{	    
   188 	  Node j = _res_graph->target(e);
   189 	  int new_dist = (*_dist)[j];
   190 	  ++e;
   191 	  while (e != INVALID){
   192 	    Node j = _res_graph->target(e);
   193 	    if ((*_wake)[j] && new_dist > (*_dist)[j]) {
   194 	      new_dist = (*_dist)[j];
   195             }
   196 	    ++e;
   197 	  }
   198 	  --_level_size[(*_dist)[i]];
   199 	  (*_dist)[i] = new_dist + 1;
   200 	  _highest_active = (*_dist)[i];
   201 	  _active_nodes[_highest_active].push_front(i);
   202 	  ++_level_size[(*_dist)[i]];
   203 	  _res_graph->firstOut((*_current_arc)[i], i);
   204 	}
   205       }
   206     }
   207 
   208     bool selectNewSink(){
   209       Node old_target = _target;
   210       (*_wake)[_target] = false;
   211       --_level_size[(*_dist)[_target]];
   212       _dormant[0].push_front(_target);
   213       (*_source_set)[_target] = true;
   214       if ((int)_dormant[0].size() == _node_num){
   215         _dormant[0].clear();
   216 	return false;
   217       }
   218 
   219       bool wake_was_empty = false;
   220 
   221       if(_wake->trueNum() == 0) {
   222 	while (!_dormant[_dormant_max].empty()){
   223 	  (*_wake)[_dormant[_dormant_max].front()] = true;
   224 	  ++_level_size[(*_dist)[_dormant[_dormant_max].front()]];
   225 	  _dormant[_dormant_max].pop_front();
   226 	}
   227 	--_dormant_max;
   228 	wake_was_empty = true;
   229       }
   230 
   231       int min_dist = std::numeric_limits<int>::max();
   232       for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
   233 	if (min_dist > (*_dist)[it]){
   234 	  _target = it;
   235 	  min_dist = (*_dist)[it];
   236 	}
   237       }
   238 
   239       if (wake_was_empty){
   240 	for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
   241           if (_tolerance.positive((*_excess)[it])) {
   242 	    if ((*_wake)[it] && it != _target) {
   243 	      _active_nodes[(*_dist)[it]].push_front(it);
   244             }
   245 	    if (_highest_active < (*_dist)[it]) {
   246 	      _highest_active = (*_dist)[it];		    
   247             }
   248 	  }
   249 	}
   250       }
   251 
   252       for (ResOutEdgeIt e(*_res_graph, old_target); e!=INVALID; ++e){
   253 	if (!(*_source_set)[_res_graph->target(e)]){
   254 	  push(e, _res_graph->rescap(e));
   255 	}
   256       }
   257       
   258       return true;
   259     }
   260     
   261     Node findActiveNode() {
   262       while (_highest_active > 0 && _active_nodes[_highest_active].empty()){ 
   263 	--_highest_active;
   264       }
   265       if( _highest_active > 0) {
   266        	Node n = _active_nodes[_highest_active].front();
   267 	_active_nodes[_highest_active].pop_front();
   268 	return n;
   269       } else {
   270 	return INVALID;
   271       }
   272     }
   273 
   274     ResEdge findAdmissibleEdge(const Node& n){
   275       ResEdge e = (*_current_arc)[n];
   276       while (e != INVALID && 
   277              ((*_dist)[n] <= (*_dist)[_res_graph->target(e)] || 
   278               !(*_wake)[_res_graph->target(e)])) {
   279 	_res_graph->nextOut(e);
   280       }
   281       if (e != INVALID) {
   282 	(*_current_arc)[n] = e;	
   283 	return e;
   284       } else {
   285 	return INVALID;
   286       }
   287     }
   288 
   289     void push(ResEdge& e,const Value& delta){
   290       _res_graph->augment(e, delta);
   291       if (!_tolerance.positive(delta)) return;
   292       
   293       (*_excess)[_res_graph->source(e)] -= delta;
   294       Node a = _res_graph->target(e);
   295       if (!_tolerance.positive((*_excess)[a]) && (*_wake)[a] && a != _target) {
   296 	_active_nodes[(*_dist)[a]].push_front(a);
   297 	if (_highest_active < (*_dist)[a]) {
   298 	  _highest_active = (*_dist)[a];
   299         }
   300       }
   301       (*_excess)[a] += delta;
   302     }
   303     
   304     Value cutValue() {
   305       Value value = 0;
   306       for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
   307 	for (InEdgeIt e(*_graph, it); e != INVALID; ++e) {
   308 	  if (!(*_wake)[_graph->source(e)]){
   309 	    value += (*_capacity)[e];
   310 	  }	
   311 	}
   312       }
   313       return value;
   314     }    
   315 
   316   public:
   317 
   318     /// \brief Initializes the internal data structures.
   319     ///
   320     /// Initializes the internal data structures. It creates
   321     /// the maps, residual graph adaptor and some bucket structures
   322     /// for the algorithm. 
   323     void init() {
   324       init(NodeIt(*_graph));
   325     }
   326 
   327     /// \brief Initializes the internal data structures.
   328     ///
   329     /// Initializes the internal data structures. It creates
   330     /// the maps, residual graph adaptor and some bucket structures
   331     /// for the algorithm. The \c source node is used as the push-relabel
   332     /// algorithm's source.
   333     void init(const Node& source) {
   334       _source = source;
   335       _node_num = countNodes(*_graph);
   336 
   337       _dormant.resize(_node_num);
   338       _level_size.resize(_node_num, 0);
   339       _active_nodes.resize(_node_num);
   340 
   341       if (!_preflow) {
   342         _preflow = new FlowMap(*_graph);
   343       }
   344       if (!_wake) {
   345         _wake = new WakeMap(*_graph);
   346       }
   347       if (!_dist) {
   348         _dist = new DistMap(*_graph);
   349       }
   350       if (!_excess) {
   351         _excess = new ExcessMap(*_graph);
   352       }
   353       if (!_source_set) {
   354         _source_set = new SourceSetMap(*_graph);
   355       }
   356       if (!_current_arc) {
   357         _current_arc = new CurrentArcMap(*_graph);
   358       }
   359       if (!_min_cut_map) {
   360         _min_cut_map = new MinCutMap(*_graph);
   361       }
   362       if (!_res_graph) {
   363         _res_graph = new ResGraph(*_graph, *_capacity, *_preflow);
   364       }
   365 
   366       _min_cut = std::numeric_limits<Value>::max();
   367     }
   368 
   369 
   370     /// \brief Calculates the minimum cut with the \c source node
   371     /// in the first partition.
   372     ///
   373     /// Calculates the minimum cut with the \c source node
   374     /// in the first partition.
   375     void calculateOut() {
   376       for (NodeIt it(*_graph); it != INVALID; ++it) {
   377         if (it != _source) {
   378           calculateOut(it);
   379           return;
   380         }
   381       }
   382     }
   383 
   384     /// \brief Calculates the minimum cut with the \c source node
   385     /// in the first partition.
   386     ///
   387     /// Calculates the minimum cut with the \c source node
   388     /// in the first partition. The \c target is the initial target
   389     /// for the push-relabel algorithm.
   390     void calculateOut(const Node& target) {
   391       for (NodeIt it(*_graph); it != INVALID; ++it) {
   392         (*_wake)[it] = true;
   393         (*_dist)[it] = 1;
   394         (*_excess)[it] = 0;
   395         (*_source_set)[it] = false;
   396 
   397         _res_graph->firstOut((*_current_arc)[it], it);
   398       }
   399 
   400       _target = target;
   401       (*_dist)[target] = 0;
   402 
   403       for (ResOutEdgeIt it(*_res_graph, _source); it != INVALID; ++it) {
   404 	push(it, _res_graph->rescap(it));
   405       }
   406 
   407       _dormant[0].push_front(_source);
   408       (*_source_set)[_source] = true;
   409       _dormant_max = 0;
   410       (*_wake)[_source]=false;
   411 
   412       _level_size[0] = 1;
   413       _level_size[1] = _node_num - 1;
   414 
   415       do {
   416 	Node n;
   417 	while ((n = findActiveNode()) != INVALID) {
   418 	  ResEdge e;
   419 	  while (_tolerance.positive((*_excess)[n]) && 
   420                  (e = findAdmissibleEdge(n)) != INVALID){
   421 	    Value delta;
   422 	    if ((*_excess)[n] < _res_graph->rescap(e)) {
   423 	      delta = (*_excess)[n];
   424 	    } else {
   425 	      delta = _res_graph->rescap(e);
   426 	      _res_graph->nextOut((*_current_arc)[n]);
   427 	    }
   428             if (!_tolerance.positive(delta)) continue;
   429 	    _res_graph->augment(e, delta);
   430 	    (*_excess)[_res_graph->source(e)] -= delta;
   431 	    Node a = _res_graph->target(e);
   432 	    if (!_tolerance.positive((*_excess)[a]) && a != _target) {
   433 	      _active_nodes[(*_dist)[a]].push_front(a);
   434 	    }
   435 	    (*_excess)[a] += delta;
   436 	  }
   437 	  if (_tolerance.positive((*_excess)[n])) {
   438 	    relabel(n);
   439           }
   440 	}
   441 
   442 	Value current_value = cutValue();
   443  	if (_min_cut > current_value){
   444 	  for (NodeIt it(*_graph); it != INVALID; ++it) {
   445             _min_cut_map->set(it, !(*_wake)[it]);
   446 	  }
   447 
   448 	  _min_cut = current_value;
   449  	}
   450 
   451       } while (selectNewSink());
   452     }
   453 
   454     void calculateIn() {
   455       for (NodeIt it(*_graph); it != INVALID; ++it) {
   456         if (it != _source) {
   457           calculateIn(it);
   458           return;
   459         }
   460       }
   461     }
   462 
   463     void run() {
   464       init();
   465       for (NodeIt it(*_graph); it != INVALID; ++it) {
   466         if (it != _source) {
   467           startOut(it);
   468           //          startIn(it);
   469           return;
   470         }
   471       }
   472     }
   473 
   474     void run(const Node& s) {
   475       init(s);
   476       for (NodeIt it(*_graph); it != INVALID; ++it) {
   477         if (it != _source) {
   478           startOut(it);
   479           //          startIn(it);
   480           return;
   481         }
   482       }
   483     }
   484 
   485     void run(const Node& s, const Node& t) {
   486       init(s);
   487       startOut(t);
   488       startIn(t);
   489     }
   490     
   491     /// \brief Returns the value of the minimum value cut with node \c
   492     /// source on the source side.
   493     /// 
   494     /// Returns the value of the minimum value cut with node \c source
   495     /// on the source side. This function can be called after running
   496     /// \ref findMinCut.
   497     Value minCut() const {
   498       return _min_cut;
   499     }
   500 
   501 
   502     /// \brief Returns a minimum value cut.
   503     ///
   504     /// Sets \c nodeMap to the characteristic vector of a minimum
   505     /// value cut with node \c source on the source side. This
   506     /// function can be called after running \ref findMinCut.  
   507     /// \pre nodeMap should be a bool-valued node-map.
   508     template <typename NodeMap>
   509     Value minCut(NodeMap& nodeMap) const {
   510       for (NodeIt it(*_graph); it != INVALID; ++it) {
   511 	nodeMap.set(it, (*_min_cut_map)[it]);
   512       }
   513       return minCut();
   514     }
   515     
   516   }; //class HaoOrlin 
   517 
   518 
   519 } //namespace lemon
   520 
   521 #endif //LEMON_HAO_ORLIN_H