[Lemon-commits] deba: r3408 - in lemon/trunk: doc lemon
Lemon SVN
svn at lemon.cs.elte.hu
Tue Dec 4 11:55:28 CET 2007
Author: deba
Date: Tue Dec 4 11:55:27 2007
New Revision: 3408
Modified:
lemon/trunk/doc/groups.dox
lemon/trunk/lemon/hao_orlin.h
lemon/trunk/lemon/nagamochi_ibaraki.h
Log:
Reimplementation of Hao-Orlin algorithm
Little modifictaion in NagamochiIbaraki
More docs for minimum cut algorithms
Modified: lemon/trunk/doc/groups.dox
==============================================================================
--- lemon/trunk/doc/groups.dox (original)
+++ lemon/trunk/doc/groups.dox Tue Dec 4 11:55:27 2007
@@ -258,13 +258,34 @@
*/
/**
- at defgroup min_cut Minimum Cut algorithms
- at ingroup algs
-\brief This group describes the algorithms
-for finding minimum cut in graphs.
+ at defgroup min_cut Minimum Cut algorithms
+ at ingroup algs
+
+\brief This group describes the algorithms for finding minimum cut in
+graphs.
+
+This group describes the algorithms for finding minimum cut in graphs.
+
+The minimum cut problem is to find a non-empty and non-complete
+\f$X\f$ subset of the vertices with minimum overall capacity on
+outgoing arcs. Formally, there is \f$G=(V,A)\f$ directed graph, an
+\f$c_a:A\rightarrow\mathbf{R}^+_0\f$ capacity function. The minimum
+cut is the solution of the next optimization problem:
+
+\f[ \min_{X \subset V, X\not\in \{\emptyset, V\}}\sum_{uv\in A, u\in X, v\not\in X}c_{uv}\f]
+
+The lemon contains several algorithms related to minimum cut problems:
+
+- \ref lemon::HaoOrlin "Hao-Orlin algorithm" for calculate minimum cut
+ in directed graphs
+- \ref lemon::NagamochiIbaraki "Nagamochi-Ibaraki algorithm" for
+ calculate minimum cut in undirected graphs
+- \ref lemon::GomoryHuTree "Gomory-Hu tree computation" for calculate all
+ pairs minimum cut in undirected graphs
+
+If you want to find minimum cut just between two distinict nodes,
+please see the \ref max_flow "Maximum Flow page".
-This group describes the algorithms
-for finding minimum cut in graphs.
*/
/**
Modified: lemon/trunk/lemon/hao_orlin.h
==============================================================================
--- lemon/trunk/lemon/hao_orlin.h (original)
+++ lemon/trunk/lemon/hao_orlin.h Tue Dec 4 11:55:27 2007
@@ -19,13 +19,9 @@
#ifndef LEMON_HAO_ORLIN_H
#define LEMON_HAO_ORLIN_H
-#include <cassert>
-
-
-
#include <vector>
-#include <queue>
#include <list>
+#include <ext/hash_set>
#include <limits>
#include <lemon/maps.h>
@@ -37,7 +33,7 @@
/// \ingroup min_cut
/// \brief Implementation of the Hao-Orlin algorithm.
///
-/// Implementation of the HaoOrlin algorithms class for testing network
+/// Implementation of the Hao-Orlin algorithm class for testing network
/// reliability.
namespace lemon {
@@ -46,24 +42,25 @@
///
/// \brief %Hao-Orlin algorithm to find a minimum cut in directed graphs.
///
- /// Hao-Orlin calculates a minimum cut in a directed graph
- /// \f$ D=(V,A) \f$. It takes a fixed node \f$ source \in V \f$ and consists
- /// of two phases: in the first phase it determines a minimum cut
- /// with \f$ source \f$ on the source-side (i.e. a set \f$ X\subsetneq V \f$
- /// with \f$ source \in X \f$ and minimal out-degree) and in the
- /// second phase it determines a minimum cut with \f$ source \f$ on the
- /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source \notin X \f$
- /// and minimal out-degree). Obviously, the smaller of these two
- /// cuts will be a minimum cut of \f$ D \f$. The algorithm is a
- /// modified push-relabel preflow algorithm and our implementation
- /// calculates the minimum cut in \f$ O(n^3) \f$ time (we use the
- /// highest-label rule). The purpose of such an algorithm is testing
- /// network reliability. For an undirected graph with \f$ n \f$
- /// nodes and \f$ e \f$ edges you can use the algorithm of Nagamochi
- /// and Ibaraki which solves the undirected problem in
- /// \f$ O(ne + n^2 \log(n)) \f$ time: it is implemented in the MinCut
- /// algorithm
- /// class.
+ /// Hao-Orlin calculates a minimum cut in a directed graph
+ /// \f$D=(V,A)\f$. It takes a fixed node \f$ source \in V \f$ and
+ /// consists of two phases: in the first phase it determines a
+ /// minimum cut with \f$ source \f$ on the source-side (i.e. a set
+ /// \f$ X\subsetneq V \f$ with \f$ source \in X \f$ and minimal
+ /// out-degree) and in the second phase it determines a minimum cut
+ /// with \f$ source \f$ on the sink-side (i.e. a set
+ /// \f$ X\subsetneq V \f$ with \f$ source \notin X \f$ and minimal
+ /// out-degree). Obviously, the smaller of these two cuts will be a
+ /// minimum cut of \f$ D \f$. The algorithm is a modified
+ /// push-relabel preflow algorithm and our implementation calculates
+ /// the minimum cut in \f$ O(n^2\sqrt{m}) \f$ time (we use the
+ /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. The
+ /// purpose of such algorithm is testing network reliability. For an
+ /// undirected graph you can run just the first phase of the
+ /// algorithm or you can use the algorithm of Nagamochi and Ibaraki
+ /// which solves the undirected problem in
+ /// \f$ O(nm + n^2 \log(n)) \f$ time: it is implemented in the
+ /// NagamochiIbaraki algorithm class.
///
/// \param _Graph is the graph type of the algorithm.
/// \param _CapacityMap is an edge map of capacities which should
@@ -80,7 +77,7 @@
typename _Tolerance = Tolerance<typename _CapacityMap::Value> >
#endif
class HaoOrlin {
- protected:
+ private:
typedef _Graph Graph;
typedef _CapacityMap CapacityMap;
@@ -88,44 +85,29 @@
typedef typename CapacityMap::Value Value;
+ GRAPH_TYPEDEFS(typename Graph);
- typedef typename Graph::Node Node;
- typedef typename Graph::NodeIt NodeIt;
- typedef typename Graph::EdgeIt EdgeIt;
- typedef typename Graph::OutEdgeIt OutEdgeIt;
- typedef typename Graph::InEdgeIt InEdgeIt;
-
- const Graph* _graph;
-
+ const Graph& _graph;
const CapacityMap* _capacity;
typedef typename Graph::template EdgeMap<Value> FlowMap;
+ FlowMap* _flow;
- FlowMap* _preflow;
+ Node _source;
- Node _source, _target;
int _node_num;
- typedef ResGraphAdaptor<const Graph, Value, CapacityMap,
- FlowMap, Tolerance> OutResGraph;
- typedef typename OutResGraph::Edge OutResEdge;
+ // Bucketing structure
+ std::vector<Node> _first, _last;
+ typename Graph::template NodeMap<Node>* _next;
+ typename Graph::template NodeMap<Node>* _prev;
+ typename Graph::template NodeMap<bool>* _active;
+ typename Graph::template NodeMap<int>* _bucket;
- OutResGraph* _out_res_graph;
+ std::vector<bool> _dormant;
- typedef RevGraphAdaptor<const Graph> RevGraph;
- RevGraph* _rev_graph;
-
- typedef ResGraphAdaptor<const RevGraph, Value, CapacityMap,
- FlowMap, Tolerance> InResGraph;
- typedef typename InResGraph::Edge InResEdge;
-
- InResGraph* _in_res_graph;
-
- typedef IterableBoolMap<Graph, Node> WakeMap;
- WakeMap* _wake;
-
- typedef typename Graph::template NodeMap<int> DistMap;
- DistMap* _dist;
+ std::list<std::list<int> > _sets;
+ std::list<int>::iterator _highest;
typedef typename Graph::template NodeMap<Value> ExcessMap;
ExcessMap* _excess;
@@ -133,15 +115,6 @@
typedef typename Graph::template NodeMap<bool> SourceSetMap;
SourceSetMap* _source_set;
- std::vector<int> _level_size;
-
- int _highest_active;
- std::vector<std::list<Node> > _active_nodes;
-
- int _dormant_max;
- std::vector<std::list<Node> > _dormant;
-
-
Value _min_cut;
typedef typename Graph::template NodeMap<bool> MinCutMap;
@@ -156,267 +129,695 @@
/// Constructor of the algorithm class.
HaoOrlin(const Graph& graph, const CapacityMap& capacity,
const Tolerance& tolerance = Tolerance()) :
- _graph(&graph), _capacity(&capacity),
- _preflow(0), _source(), _target(),
- _out_res_graph(0), _rev_graph(0), _in_res_graph(0),
- _wake(0),_dist(0), _excess(0), _source_set(0),
- _highest_active(), _active_nodes(), _dormant_max(), _dormant(),
- _min_cut(), _min_cut_map(0), _tolerance(tolerance) {}
+ _graph(graph), _capacity(&capacity), _flow(0), _source(),
+ _node_num(), _first(), _last(), _next(0), _prev(0),
+ _active(0), _bucket(0), _dormant(), _sets(), _highest(),
+ _excess(0), _source_set(0), _min_cut(), _min_cut_map(0),
+ _tolerance(tolerance) {}
~HaoOrlin() {
if (_min_cut_map) {
delete _min_cut_map;
}
- if (_in_res_graph) {
- delete _in_res_graph;
- }
- if (_rev_graph) {
- delete _rev_graph;
- }
- if (_out_res_graph) {
- delete _out_res_graph;
- }
if (_source_set) {
delete _source_set;
}
if (_excess) {
delete _excess;
}
- if (_dist) {
- delete _dist;
+ if (_next) {
+ delete _next;
+ }
+ if (_prev) {
+ delete _prev;
+ }
+ if (_active) {
+ delete _active;
}
- if (_wake) {
- delete _wake;
+ if (_bucket) {
+ delete _bucket;
}
- if (_preflow) {
- delete _preflow;
+ if (_flow) {
+ delete _flow;
}
}
private:
+
+ void activate(const Node& i) {
+ _active->set(i, true);
+
+ int bucket = (*_bucket)[i];
+
+ if ((*_prev)[i] == INVALID || (*_active)[(*_prev)[i]]) return;
+ //unlace
+ _next->set((*_prev)[i], (*_next)[i]);
+ if ((*_next)[i] != INVALID) {
+ _prev->set((*_next)[i], (*_prev)[i]);
+ } else {
+ _last[bucket] = (*_prev)[i];
+ }
+ //lace
+ _next->set(i, _first[bucket]);
+ _prev->set(_first[bucket], i);
+ _prev->set(i, INVALID);
+ _first[bucket] = i;
+ }
+
+ void deactivate(const Node& i) {
+ _active->set(i, false);
+ int bucket = (*_bucket)[i];
+
+ if ((*_next)[i] == INVALID || !(*_active)[(*_next)[i]]) return;
+
+ //unlace
+ _prev->set((*_next)[i], (*_prev)[i]);
+ if ((*_prev)[i] != INVALID) {
+ _next->set((*_prev)[i], (*_next)[i]);
+ } else {
+ _first[bucket] = (*_next)[i];
+ }
+ //lace
+ _prev->set(i, _last[bucket]);
+ _next->set(_last[bucket], i);
+ _next->set(i, INVALID);
+ _last[bucket] = i;
+ }
+
+ void addItem(const Node& i, int bucket) {
+ (*_bucket)[i] = bucket;
+ if (_last[bucket] != INVALID) {
+ _prev->set(i, _last[bucket]);
+ _next->set(_last[bucket], i);
+ _next->set(i, INVALID);
+ _last[bucket] = i;
+ } else {
+ _prev->set(i, INVALID);
+ _first[bucket] = i;
+ _next->set(i, INVALID);
+ _last[bucket] = i;
+ }
+ }
- template <typename ResGraph>
- void findMinCut(const Node& target, bool out, ResGraph& res_graph) {
- typedef typename ResGraph::Edge ResEdge;
- typedef typename ResGraph::OutEdgeIt ResOutEdgeIt;
-
- for (typename Graph::EdgeIt it(*_graph); it != INVALID; ++it) {
- (*_preflow)[it] = 0;
- }
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- (*_wake)[it] = true;
- (*_dist)[it] = 1;
- (*_excess)[it] = 0;
- (*_source_set)[it] = false;
- }
-
- _dormant[0].push_front(_source);
- (*_source_set)[_source] = true;
- _dormant_max = 0;
- (*_wake)[_source] = false;
-
- _level_size[0] = 1;
- _level_size[1] = _node_num - 1;
-
- _target = target;
- (*_dist)[target] = 0;
-
- for (ResOutEdgeIt it(res_graph, _source); it != INVALID; ++it) {
- Value delta = res_graph.rescap(it);
- (*_excess)[_source] -= delta;
- res_graph.augment(it, delta);
- Node a = res_graph.target(it);
- if ((*_excess)[a] == 0 && (*_wake)[a] && a != _target) {
- _active_nodes[(*_dist)[a]].push_front(a);
- if (_highest_active < (*_dist)[a]) {
- _highest_active = (*_dist)[a];
- }
- }
- (*_excess)[a] += delta;
+ void findMinCutOut() {
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _excess->set(n, 0);
+ }
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ _flow->set(e, 0);
+ }
+
+ int bucket_num = 1;
+
+ {
+ typename Graph::template NodeMap<bool> reached(_graph, false);
+
+ reached.set(_source, true);
+
+ bool first_set = true;
+
+ for (NodeIt t(_graph); t != INVALID; ++t) {
+ if (reached[t]) continue;
+ _sets.push_front(std::list<int>());
+ _sets.front().push_front(bucket_num);
+ _dormant[bucket_num] = !first_set;
+
+ _bucket->set(t, bucket_num);
+ _first[bucket_num] = _last[bucket_num] = t;
+ _next->set(t, INVALID);
+ _prev->set(t, INVALID);
+
+ ++bucket_num;
+
+ std::vector<Node> queue;
+ queue.push_back(t);
+ reached.set(t, true);
+
+ while (!queue.empty()) {
+ _sets.front().push_front(bucket_num);
+ _dormant[bucket_num] = !first_set;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+
+ std::vector<Node> nqueue;
+ for (int i = 0; i < int(queue.size()); ++i) {
+ Node n = queue[i];
+ for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
+ Node u = _graph.source(e);
+ if (!reached[u] && _tolerance.positive((*_capacity)[e])) {
+ reached.set(u, true);
+ addItem(u, bucket_num);
+ nqueue.push_back(u);
+ }
+ }
+ }
+ queue.swap(nqueue);
+ ++bucket_num;
+ }
+ _sets.front().pop_front();
+ --bucket_num;
+ first_set = false;
+ }
+
+ _bucket->set(_source, 0);
+ _dormant[0] = true;
+ }
+ _source_set->set(_source, true);
+
+ Node target = _last[_sets.back().back()];
+ {
+ for (OutEdgeIt e(_graph, _source); e != INVALID; ++e) {
+ if (_tolerance.positive((*_capacity)[e])) {
+ Node u = _graph.target(e);
+ _flow->set(e, (*_capacity)[e]);
+ _excess->set(u, (*_excess)[u] + (*_capacity)[e]);
+ if (!(*_active)[u] && u != _source) {
+ activate(u);
+ }
+ }
+ }
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
}
- do {
- Node n;
- while ((n = findActiveNode()) != INVALID) {
- for (ResOutEdgeIt e(res_graph, n); e != INVALID; ++e) {
- Node a = res_graph.target(e);
- if ((*_dist)[a] >= (*_dist)[n] || !(*_wake)[a]) continue;
- Value delta = res_graph.rescap(e);
- if (_tolerance.positive((*_excess)[n] - delta)) {
- (*_excess)[n] -= delta;
+ while (true) {
+ while (_highest != _sets.back().end()) {
+ Node n = _first[*_highest];
+ Value excess = (*_excess)[n];
+ int next_bucket = _node_num;
+
+ int under_bucket;
+ if (++std::list<int>::iterator(_highest) == _sets.back().end()) {
+ under_bucket = -1;
+ } else {
+ under_bucket = *(++std::list<int>::iterator(_highest));
+ }
+
+ for (OutEdgeIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.target(e);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] + excess);
+ _excess->set(v, (*_excess)[v] + excess);
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, (*_capacity)[e]);
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] - excess);
+ _excess->set(v, (*_excess)[v] + excess);
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, 0);
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ no_more_push:
+
+ _excess->set(n, excess);
+
+ if (excess != 0) {
+ if ((*_next)[n] == INVALID) {
+ typename std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+ new_set->splice(new_set->end(), _sets.back(),
+ _sets.back().begin(), ++_highest);
+ for (std::list<int>::iterator it = new_set->begin();
+ it != new_set->end(); ++it) {
+ _dormant[*it] = true;
+ }
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ } else if (next_bucket == _node_num) {
+ _first[(*_bucket)[n]] = (*_next)[n];
+ _prev->set((*_next)[n], INVALID);
+
+ std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+
+ new_set->push_front(bucket_num);
+ _bucket->set(n, bucket_num);
+ _first[bucket_num] = _last[bucket_num] = n;
+ _next->set(n, INVALID);
+ _prev->set(n, INVALID);
+ _dormant[bucket_num] = true;
+ ++bucket_num;
+
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
} else {
- delta = (*_excess)[n];
- (*_excess)[n] = 0;
+ _first[*_highest] = (*_next)[n];
+ _prev->set((*_next)[n], INVALID);
+
+ while (next_bucket != *_highest) {
+ --_highest;
+ }
+
+ if (_highest == _sets.back().begin()) {
+ _sets.back().push_front(bucket_num);
+ _dormant[bucket_num] = false;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+ ++bucket_num;
+ }
+ --_highest;
+
+ _bucket->set(n, *_highest);
+ _next->set(n, _first[*_highest]);
+ if (_first[*_highest] != INVALID) {
+ _prev->set(_first[*_highest], n);
+ } else {
+ _last[*_highest] = n;
+ }
+ _first[*_highest] = n;
+ }
+ } else {
+
+ deactivate(n);
+ if (!(*_active)[_first[*_highest]]) {
+ ++_highest;
+ if (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ _highest = _sets.back().end();
+ }
}
- res_graph.augment(e, delta);
- if ((*_excess)[a] == 0 && a != _target) {
- _active_nodes[(*_dist)[a]].push_front(a);
- }
- (*_excess)[a] += delta;
- if ((*_excess)[n] == 0) break;
- }
- if ((*_excess)[n] != 0) {
- relabel(n, res_graph);
- }
- }
-
- Value current_value = cutValue(out);
- if (_min_cut > current_value){
- if (out) {
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- _min_cut_map->set(it, !(*_wake)[it]);
- }
- } else {
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- _min_cut_map->set(it, (*_wake)[it]);
- }
- }
-
- _min_cut = current_value;
- }
-
- } while (selectNewSink(res_graph));
- }
-
- template <typename ResGraph>
- void relabel(const Node& n, ResGraph& res_graph) {
- typedef typename ResGraph::OutEdgeIt ResOutEdgeIt;
-
- int k = (*_dist)[n];
- if (_level_size[k] == 1) {
- ++_dormant_max;
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- if ((*_wake)[it] && (*_dist)[it] >= k) {
- (*_wake)[it] = false;
- _dormant[_dormant_max].push_front(it);
- --_level_size[(*_dist)[it]];
- }
- }
- --_highest_active;
- } else {
- int new_dist = _node_num;
- for (ResOutEdgeIt e(res_graph, n); e != INVALID; ++e) {
- Node t = res_graph.target(e);
- if ((*_wake)[t] && new_dist > (*_dist)[t]) {
- new_dist = (*_dist)[t];
- }
- }
- if (new_dist == _node_num) {
- ++_dormant_max;
- (*_wake)[n] = false;
- _dormant[_dormant_max].push_front(n);
- --_level_size[(*_dist)[n]];
- } else {
- --_level_size[(*_dist)[n]];
- (*_dist)[n] = new_dist + 1;
- _highest_active = (*_dist)[n];
- _active_nodes[_highest_active].push_front(n);
- ++_level_size[(*_dist)[n]];
- }
- }
- }
-
- template <typename ResGraph>
- bool selectNewSink(ResGraph& res_graph) {
- typedef typename ResGraph::OutEdgeIt ResOutEdgeIt;
-
- Node old_target = _target;
- (*_wake)[_target] = false;
- --_level_size[(*_dist)[_target]];
- _dormant[0].push_front(_target);
- (*_source_set)[_target] = true;
- if (int(_dormant[0].size()) == _node_num){
- _dormant[0].clear();
- return false;
- }
-
- bool wake_was_empty = false;
-
- if(_wake->trueNum() == 0) {
- while (!_dormant[_dormant_max].empty()){
- (*_wake)[_dormant[_dormant_max].front()] = true;
- ++_level_size[(*_dist)[_dormant[_dormant_max].front()]];
- _dormant[_dormant_max].pop_front();
- }
- --_dormant_max;
- wake_was_empty = true;
- }
-
- int min_dist = std::numeric_limits<int>::max();
- for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
- if (min_dist > (*_dist)[it]){
- _target = it;
- min_dist = (*_dist)[it];
- }
- }
-
- if (wake_was_empty){
- for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
- if ((*_excess)[it] != 0 && it != _target) {
- _active_nodes[(*_dist)[it]].push_front(it);
- if (_highest_active < (*_dist)[it]) {
- _highest_active = (*_dist)[it];
- }
- }
- }
- }
-
- Node n = old_target;
- for (ResOutEdgeIt e(res_graph, n); e != INVALID; ++e){
- Node a = res_graph.target(e);
- if (!(*_wake)[a]) continue;
- Value delta = res_graph.rescap(e);
- res_graph.augment(e, delta);
- (*_excess)[n] -= delta;
- if ((*_excess)[a] == 0 && (*_wake)[a] && a != _target) {
- _active_nodes[(*_dist)[a]].push_front(a);
- if (_highest_active < (*_dist)[a]) {
- _highest_active = (*_dist)[a];
- }
- }
- (*_excess)[a] += delta;
+ }
+ }
+
+ if ((*_excess)[target] < _min_cut) {
+ _min_cut = (*_excess)[target];
+ for (NodeIt i(_graph); i != INVALID; ++i) {
+ _min_cut_map->set(i, true);
+ }
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ Node n = _first[*it];
+ while (n != INVALID) {
+ _min_cut_map->set(n, false);
+ n = (*_next)[n];
+ }
+ }
+ }
+
+ {
+ Node new_target;
+ if ((*_prev)[target] != INVALID) {
+ _last[(*_bucket)[target]] = (*_prev)[target];
+ _next->set((*_prev)[target], INVALID);
+ new_target = (*_prev)[target];
+ } else {
+ _sets.back().pop_back();
+ if (_sets.back().empty()) {
+ _sets.pop_back();
+ if (_sets.empty())
+ break;
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ _dormant[*it] = false;
+ }
+ }
+ new_target = _last[_sets.back().back()];
+ }
+
+ _bucket->set(target, 0);
+
+ _source_set->set(target, true);
+ for (OutEdgeIt e(_graph, target); e != INVALID; ++e) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.target(e);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, (*_capacity)[e]);
+ }
+
+ for (InEdgeIt e(_graph, target); e != INVALID; ++e) {
+ Value rem = (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.source(e);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, 0);
+ }
+
+ target = new_target;
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ }
+ }
+ }
+
+ void findMinCutIn() {
+
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ _excess->set(n, 0);
}
+
+ for (EdgeIt e(_graph); e != INVALID; ++e) {
+ _flow->set(e, 0);
+ }
+
+ int bucket_num = 1;
- return true;
- }
+ {
+ typename Graph::template NodeMap<bool> reached(_graph, false);
+
+ reached.set(_source, true);
+
+ bool first_set = true;
+
+ for (NodeIt t(_graph); t != INVALID; ++t) {
+ if (reached[t]) continue;
+ _sets.push_front(std::list<int>());
+ _sets.front().push_front(bucket_num);
+ _dormant[bucket_num] = !first_set;
+
+ _bucket->set(t, bucket_num);
+ _first[bucket_num] = _last[bucket_num] = t;
+ _next->set(t, INVALID);
+ _prev->set(t, INVALID);
+
+ ++bucket_num;
+
+ std::vector<Node> queue;
+ queue.push_back(t);
+ reached.set(t, true);
+
+ while (!queue.empty()) {
+ _sets.front().push_front(bucket_num);
+ _dormant[bucket_num] = !first_set;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+
+ std::vector<Node> nqueue;
+ for (int i = 0; i < int(queue.size()); ++i) {
+ Node n = queue[i];
+ for (OutEdgeIt e(_graph, n); e != INVALID; ++e) {
+ Node u = _graph.target(e);
+ if (!reached[u] && _tolerance.positive((*_capacity)[e])) {
+ reached.set(u, true);
+ addItem(u, bucket_num);
+ nqueue.push_back(u);
+ }
+ }
+ }
+ queue.swap(nqueue);
+ ++bucket_num;
+ }
+ _sets.front().pop_front();
+ --bucket_num;
+ first_set = false;
+ }
- Node findActiveNode() {
- while (_highest_active > 0 && _active_nodes[_highest_active].empty()){
- --_highest_active;
+ _bucket->set(_source, 0);
+ _dormant[0] = true;
}
- if( _highest_active > 0) {
- Node n = _active_nodes[_highest_active].front();
- _active_nodes[_highest_active].pop_front();
- return n;
- } else {
- return INVALID;
+ _source_set->set(_source, true);
+
+ Node target = _last[_sets.back().back()];
+ {
+ for (InEdgeIt e(_graph, _source); e != INVALID; ++e) {
+ if (_tolerance.positive((*_capacity)[e])) {
+ Node u = _graph.source(e);
+ _flow->set(e, (*_capacity)[e]);
+ _excess->set(u, (*_excess)[u] + (*_capacity)[e]);
+ if (!(*_active)[u] && u != _source) {
+ activate(u);
+ }
+ }
+ }
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
}
- }
- Value cutValue(bool out) {
- Value value = 0;
- if (out) {
- for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
- for (InEdgeIt e(*_graph, it); e != INVALID; ++e) {
- if (!(*_wake)[_graph->source(e)]){
- value += (*_capacity)[e];
- }
- }
- }
- } else {
- for (typename WakeMap::TrueIt it(*_wake); it != INVALID; ++it) {
- for (OutEdgeIt e(*_graph, it); e != INVALID; ++e) {
- if (!(*_wake)[_graph->target(e)]){
- value += (*_capacity)[e];
- }
- }
- }
+
+ while (true) {
+ while (_highest != _sets.back().end()) {
+ Node n = _first[*_highest];
+ Value excess = (*_excess)[n];
+ int next_bucket = _node_num;
+
+ int under_bucket;
+ if (++std::list<int>::iterator(_highest) == _sets.back().end()) {
+ under_bucket = -1;
+ } else {
+ under_bucket = *(++std::list<int>::iterator(_highest));
+ }
+
+ for (InEdgeIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.source(e);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] + excess);
+ _excess->set(v, (*_excess)[v] + excess);
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, (*_capacity)[e]);
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ for (OutEdgeIt e(_graph, n); e != INVALID; ++e) {
+ Node v = _graph.target(e);
+ if (_dormant[(*_bucket)[v]]) continue;
+ Value rem = (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ if ((*_bucket)[v] == under_bucket) {
+ if (!(*_active)[v] && v != target) {
+ activate(v);
+ }
+ if (!_tolerance.less(rem, excess)) {
+ _flow->set(e, (*_flow)[e] - excess);
+ _excess->set(v, (*_excess)[v] + excess);
+ excess = 0;
+ goto no_more_push;
+ } else {
+ excess -= rem;
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, 0);
+ }
+ } else if (next_bucket > (*_bucket)[v]) {
+ next_bucket = (*_bucket)[v];
+ }
+ }
+
+ no_more_push:
+
+ _excess->set(n, excess);
+
+ if (excess != 0) {
+ if ((*_next)[n] == INVALID) {
+ typename std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+ new_set->splice(new_set->end(), _sets.back(),
+ _sets.back().begin(), ++_highest);
+ for (std::list<int>::iterator it = new_set->begin();
+ it != new_set->end(); ++it) {
+ _dormant[*it] = true;
+ }
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ } else if (next_bucket == _node_num) {
+ _first[(*_bucket)[n]] = (*_next)[n];
+ _prev->set((*_next)[n], INVALID);
+
+ std::list<std::list<int> >::iterator new_set =
+ _sets.insert(--_sets.end(), std::list<int>());
+
+ new_set->push_front(bucket_num);
+ _bucket->set(n, bucket_num);
+ _first[bucket_num] = _last[bucket_num] = n;
+ _next->set(n, INVALID);
+ _prev->set(n, INVALID);
+ _dormant[bucket_num] = true;
+ ++bucket_num;
+
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ } else {
+ _first[*_highest] = (*_next)[n];
+ _prev->set((*_next)[n], INVALID);
+
+ while (next_bucket != *_highest) {
+ --_highest;
+ }
+ if (_highest == _sets.back().begin()) {
+ _sets.back().push_front(bucket_num);
+ _dormant[bucket_num] = false;
+ _first[bucket_num] = _last[bucket_num] = INVALID;
+ ++bucket_num;
+ }
+ --_highest;
+
+ _bucket->set(n, *_highest);
+ _next->set(n, _first[*_highest]);
+ if (_first[*_highest] != INVALID) {
+ _prev->set(_first[*_highest], n);
+ } else {
+ _last[*_highest] = n;
+ }
+ _first[*_highest] = n;
+ }
+ } else {
+
+ deactivate(n);
+ if (!(*_active)[_first[*_highest]]) {
+ ++_highest;
+ if (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ _highest = _sets.back().end();
+ }
+ }
+ }
+ }
+
+ if ((*_excess)[target] < _min_cut) {
+ _min_cut = (*_excess)[target];
+ for (NodeIt i(_graph); i != INVALID; ++i) {
+ _min_cut_map->set(i, false);
+ }
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ Node n = _first[*it];
+ while (n != INVALID) {
+ _min_cut_map->set(n, true);
+ n = (*_next)[n];
+ }
+ }
+ }
+
+ {
+ Node new_target;
+ if ((*_prev)[target] != INVALID) {
+ _last[(*_bucket)[target]] = (*_prev)[target];
+ _next->set((*_prev)[target], INVALID);
+ new_target = (*_prev)[target];
+ } else {
+ _sets.back().pop_back();
+ if (_sets.back().empty()) {
+ _sets.pop_back();
+ if (_sets.empty())
+ break;
+ for (std::list<int>::iterator it = _sets.back().begin();
+ it != _sets.back().end(); ++it) {
+ _dormant[*it] = false;
+ }
+ }
+ new_target = _last[_sets.back().back()];
+ }
+
+ _bucket->set(target, 0);
+
+ _source_set->set(target, true);
+ for (InEdgeIt e(_graph, target); e != INVALID; ++e) {
+ Value rem = (*_capacity)[e] - (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.source(e);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, (*_capacity)[e]);
+ }
+
+ for (OutEdgeIt e(_graph, target); e != INVALID; ++e) {
+ Value rem = (*_flow)[e];
+ if (!_tolerance.positive(rem)) continue;
+ Node v = _graph.target(e);
+ if (!(*_active)[v] && !(*_source_set)[v]) {
+ activate(v);
+ }
+ _excess->set(v, (*_excess)[v] + rem);
+ _flow->set(e, 0);
+ }
+
+ target = new_target;
+ if ((*_active)[target]) {
+ deactivate(target);
+ }
+
+ _highest = _sets.back().begin();
+ while (_highest != _sets.back().end() &&
+ !(*_active)[_first[*_highest]]) {
+ ++_highest;
+ }
+ }
}
- return value;
}
-
public:
/// \name Execution control
@@ -435,7 +836,7 @@
/// the maps, residual graph adaptors and some bucket structures
/// for the algorithm.
void init() {
- init(NodeIt(*_graph));
+ init(NodeIt(_graph));
}
/// \brief Initializes the internal data structures.
@@ -446,38 +847,37 @@
/// algorithm's source.
void init(const Node& source) {
_source = source;
- _node_num = countNodes(*_graph);
+
+ _node_num = countNodes(_graph);
+
+ _first.resize(_node_num);
+ _last.resize(_node_num);
_dormant.resize(_node_num);
- _level_size.resize(_node_num, 0);
- _active_nodes.resize(_node_num);
- if (!_preflow) {
- _preflow = new FlowMap(*_graph);
- }
- if (!_wake) {
- _wake = new WakeMap(*_graph);
+ if (!_flow) {
+ _flow = new FlowMap(_graph);
}
- if (!_dist) {
- _dist = new DistMap(*_graph);
+ if (!_next) {
+ _next = new typename Graph::template NodeMap<Node>(_graph);
}
- if (!_excess) {
- _excess = new ExcessMap(*_graph);
+ if (!_prev) {
+ _prev = new typename Graph::template NodeMap<Node>(_graph);
}
- if (!_source_set) {
- _source_set = new SourceSetMap(*_graph);
+ if (!_active) {
+ _active = new typename Graph::template NodeMap<bool>(_graph);
}
- if (!_out_res_graph) {
- _out_res_graph = new OutResGraph(*_graph, *_capacity, *_preflow);
+ if (!_bucket) {
+ _bucket = new typename Graph::template NodeMap<int>(_graph);
}
- if (!_rev_graph) {
- _rev_graph = new RevGraph(*_graph);
+ if (!_excess) {
+ _excess = new ExcessMap(_graph);
}
- if (!_in_res_graph) {
- _in_res_graph = new InResGraph(*_rev_graph, *_capacity, *_preflow);
+ if (!_source_set) {
+ _source_set = new SourceSetMap(_graph);
}
if (!_min_cut_map) {
- _min_cut_map = new MinCutMap(*_graph);
+ _min_cut_map = new MinCutMap(_graph);
}
_min_cut = std::numeric_limits<Value>::max();
@@ -487,56 +887,23 @@
/// \brief Calculates a minimum cut with \f$ source \f$ on the
/// source-side.
///
- /// \brief Calculates a minimum cut with \f$ source \f$ on the
- /// source-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source \in X \f$
- /// and minimal out-degree).
+ /// Calculates a minimum cut with \f$ source \f$ on the
+ /// source-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source
+ /// \in X \f$ and minimal out-degree).
void calculateOut() {
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- if (it != _source) {
- calculateOut(it);
- return;
- }
- }
- }
-
- /// \brief Calculates a minimum cut with \f$ source \f$ on the
- /// source-side.
- ///
- /// \brief Calculates a minimum cut with \f$ source \f$ on the
- /// source-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source \in X \f$
- /// and minimal out-degree). The \c target is the initial target
- /// for the push-relabel algorithm.
- void calculateOut(const Node& target) {
- findMinCut(target, true, *_out_res_graph);
+ findMinCutOut();
}
/// \brief Calculates a minimum cut with \f$ source \f$ on the
- /// sink-side.
+ /// target-side.
///
- /// \brief Calculates a minimum cut with \f$ source \f$ on the
- /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with
- /// \f$ source \notin X \f$
- /// and minimal out-degree).
+ /// Calculates a minimum cut with \f$ source \f$ on the
+ /// target-side (i.e. a set \f$ X\subsetneq V \f$ with \f$ source
+ /// \in X \f$ and minimal out-degree).
void calculateIn() {
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- if (it != _source) {
- calculateIn(it);
- return;
- }
- }
+ findMinCutIn();
}
- /// \brief Calculates a minimum cut with \f$ source \f$ on the
- /// sink-side.
- ///
- /// \brief Calculates a minimum cut with \f$ source \f$ on the
- /// sink-side (i.e. a set \f$ X\subsetneq V
- /// \f$ with \f$ source \notin X \f$ and minimal out-degree).
- /// The \c target is the initial
- /// target for the push-relabel algorithm.
- void calculateIn(const Node& target) {
- findMinCut(target, false, *_in_res_graph);
- }
/// \brief Runs the algorithm.
///
@@ -545,13 +912,8 @@
/// and \ref calculateIn().
void run() {
init();
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- if (it != _source) {
- calculateOut(it);
- calculateIn(it);
- return;
- }
- }
+ calculateOut();
+ calculateIn();
}
/// \brief Runs the algorithm.
@@ -561,23 +923,8 @@
/// calculateOut() and \ref calculateIn().
void run(const Node& s) {
init(s);
- for (NodeIt it(*_graph); it != INVALID; ++it) {
- if (it != _source) {
- calculateOut(it);
- calculateIn(it);
- return;
- }
- }
- }
-
- /// \brief Runs the algorithm.
- ///
- /// Runs the algorithm. It just calls the \ref init() and then
- /// \ref calculateOut() and \ref calculateIn().
- void run(const Node& s, const Node& t) {
- init(s);
- calculateOut(t);
- calculateIn(t);
+ calculateOut();
+ calculateIn();
}
/// @}
@@ -608,7 +955,7 @@
/// bool-valued node-map.
template <typename NodeMap>
Value minCut(NodeMap& nodeMap) const {
- for (NodeIt it(*_graph); it != INVALID; ++it) {
+ for (NodeIt it(_graph); it != INVALID; ++it) {
nodeMap.set(it, (*_min_cut_map)[it]);
}
return minCut();
Modified: lemon/trunk/lemon/nagamochi_ibaraki.h
==============================================================================
--- lemon/trunk/lemon/nagamochi_ibaraki.h (original)
+++ lemon/trunk/lemon/nagamochi_ibaraki.h Tue Dec 4 11:55:27 2007
@@ -847,9 +847,9 @@
/// distinict subnetwork.
///
/// The complexity of the algorithm is \f$ O(ne\log(n)) \f$ but with
- /// Fibonacci heap it can be decreased to \f$ O(ne+n^2\log(n)) \f$.
- /// When capacity map is neutral then it uses BucketHeap which
- /// results \f$ O(ne) \f$ time complexity.
+ /// Fibonacci heap it can be decreased to \f$ O(ne+n^2\log(n)) \f$.
+ /// When unit capacity minimum cut is computed then it uses
+ /// BucketHeap which results \f$ O(ne) \f$ time complexity.
///
/// \warning The value type of the capacity map should be able to hold
/// any cut value of the graph, otherwise the result can overflow.
@@ -906,7 +906,7 @@
///@{
- struct DefNeutralCapacityTraits : public Traits {
+ struct DefUnitCapacityTraits : public Traits {
typedef ConstMap<typename Graph::UEdge, Const<int, 1> > CapacityMap;
static CapacityMap *createCapacityMap(const Graph&) {
return new CapacityMap();
@@ -917,11 +917,11 @@
///
/// \ref named-templ-param "Named parameter" for setting
/// the capacity type to constMap<UEdge, int, 1>()
- struct DefNeutralCapacity
+ struct DefUnitCapacity
: public NagamochiIbaraki<Graph, CapacityMap,
- DefNeutralCapacityTraits> {
+ DefUnitCapacityTraits> {
typedef NagamochiIbaraki<Graph, CapacityMap,
- DefNeutralCapacityTraits> Create;
+ DefUnitCapacityTraits> Create;
};
@@ -1134,7 +1134,7 @@
///
/// This constructor can be used only when the Traits class
/// defines how can we instantiate a local capacity map.
- /// If the DefNeutralCapacity used the algorithm automatically
+ /// If the DefUnitCapacity used the algorithm automatically
/// construct the capacity map.
///
///\param graph the graph the algorithm will run on.
More information about the Lemon-commits
mailing list