[Lemon-commits] Peter Kovacs: Rework and fix the implementation ...
Lemon HG
hg at lemon.cs.elte.hu
Thu Nov 5 08:59:56 CET 2009
details: http://lemon.cs.elte.hu/hg/lemon/rev/83ce7ce39f21
changeset: 820:83ce7ce39f21
user: Peter Kovacs <kpeter [at] inf.elte.hu>
date: Thu Aug 06 20:12:43 2009 +0200
description:
Rework and fix the implementation of MinMeanCycle (#179)
- Fix the handling of the cycle means.
- Many implementation improvements:
- More efficient data storage for the strongly connected
components.
- Better handling of BFS queues.
- Merge consecutive BFS searches (perform two BFS searches
instead of three).
This version is about two times faster on average and an order of
magnitude faster if there are a lot of strongly connected
components.
diffstat:
lemon/min_mean_cycle.h | 355 ++++++++++++++++++++++++++-----------------------
1 files changed, 188 insertions(+), 167 deletions(-)
diffs (truncated from 457 to 300 lines):
diff --git a/lemon/min_mean_cycle.h b/lemon/min_mean_cycle.h
--- a/lemon/min_mean_cycle.h
+++ b/lemon/min_mean_cycle.h
@@ -74,26 +74,32 @@
// The length of the arcs
const LengthMap &_length;
- // The total length of the found cycle
- Value _cycle_length;
- // The number of arcs on the found cycle
- int _cycle_size;
- // The found cycle
+ // Data for the found cycles
+ bool _curr_found, _best_found;
+ Value _curr_length, _best_length;
+ int _curr_size, _best_size;
+ Node _curr_node, _best_node;
+
Path *_cycle_path;
+ bool _local_path;
- bool _local_path;
- bool _cycle_found;
- Node _cycle_node;
+ // Internal data used by the algorithm
+ typename Digraph::template NodeMap<Arc> _policy;
+ typename Digraph::template NodeMap<bool> _reached;
+ typename Digraph::template NodeMap<int> _level;
+ typename Digraph::template NodeMap<double> _dist;
- typename Digraph::template NodeMap<bool> _reached;
- typename Digraph::template NodeMap<double> _dist;
- typename Digraph::template NodeMap<Arc> _policy;
-
+ // Data for storing the strongly connected components
+ int _comp_num;
typename Digraph::template NodeMap<int> _comp;
- int _comp_num;
-
- std::vector<Node> _nodes;
- std::vector<Arc> _arcs;
+ std::vector<std::vector<Node> > _comp_nodes;
+ std::vector<Node>* _nodes;
+ typename Digraph::template NodeMap<std::vector<Arc> > _in_arcs;
+
+ // Queue used for BFS search
+ std::vector<Node> _queue;
+ int _qfront, _qback;
+
Tolerance<double> _tol;
public:
@@ -106,9 +112,9 @@
/// \param length The lengths (costs) of the arcs.
MinMeanCycle( const Digraph &digraph,
const LengthMap &length ) :
- _gr(digraph), _length(length), _cycle_length(0), _cycle_size(-1),
- _cycle_path(NULL), _local_path(false), _reached(digraph),
- _dist(digraph), _policy(digraph), _comp(digraph)
+ _gr(digraph), _length(length), _cycle_path(NULL), _local_path(false),
+ _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph),
+ _comp(digraph), _in_arcs(digraph)
{}
/// Destructor.
@@ -172,26 +178,28 @@
///
/// \return \c true if a directed cycle exists in the digraph.
bool findMinMean() {
- // Initialize
- _tol.epsilon(1e-6);
- if (!_cycle_path) {
- _local_path = true;
- _cycle_path = new Path;
- }
- _cycle_path->clear();
- _cycle_found = false;
-
+ // Initialize and find strongly connected components
+ init();
+ findComponents();
+
// Find the minimum cycle mean in the components
- _comp_num = stronglyConnectedComponents(_gr, _comp);
for (int comp = 0; comp < _comp_num; ++comp) {
- if (!initCurrentComponent(comp)) continue;
+ // Find the minimum mean cycle in the current component
+ if (!buildPolicyGraph(comp)) continue;
while (true) {
- if (!findPolicyCycles()) break;
- contractPolicyGraph(comp);
+ findPolicyCycle();
if (!computeNodeDistances()) break;
}
+ // Update the best cycle (global minimum mean cycle)
+ if ( !_best_found || (_curr_found &&
+ _curr_length * _best_size < _best_length * _curr_size) ) {
+ _best_found = true;
+ _best_length = _curr_length;
+ _best_size = _curr_size;
+ _best_node = _curr_node;
+ }
}
- return _cycle_found;
+ return _best_found;
}
/// \brief Find a minimum mean directed cycle.
@@ -203,10 +211,10 @@
///
/// \pre \ref findMinMean() must be called before using this function.
bool findCycle() {
- if (!_cycle_found) return false;
- _cycle_path->addBack(_policy[_cycle_node]);
- for ( Node v = _cycle_node;
- (v = _gr.target(_policy[v])) != _cycle_node; ) {
+ if (!_best_found) return false;
+ _cycle_path->addBack(_policy[_best_node]);
+ for ( Node v = _best_node;
+ (v = _gr.target(_policy[v])) != _best_node; ) {
_cycle_path->addBack(_policy[v]);
}
return true;
@@ -225,36 +233,36 @@
///
/// This function returns the total length of the found cycle.
///
- /// \pre \ref run() or \ref findCycle() must be called before
+ /// \pre \ref run() or \ref findMinMean() must be called before
/// using this function.
Value cycleLength() const {
- return _cycle_length;
+ return _best_length;
}
/// \brief Return the number of arcs on the found cycle.
///
/// This function returns the number of arcs on the found cycle.
///
- /// \pre \ref run() or \ref findCycle() must be called before
+ /// \pre \ref run() or \ref findMinMean() must be called before
/// using this function.
int cycleArcNum() const {
- return _cycle_size;
+ return _best_size;
}
/// \brief Return the mean length of the found cycle.
///
/// This function returns the mean length of the found cycle.
///
- /// \note <tt>mmc.cycleMean()</tt> is just a shortcut of the
+ /// \note <tt>alg.cycleMean()</tt> is just a shortcut of the
/// following code.
/// \code
- /// return double(mmc.cycleLength()) / mmc.cycleArcNum();
+ /// return static_cast<double>(alg.cycleLength()) / alg.cycleArcNum();
/// \endcode
///
/// \pre \ref run() or \ref findMinMean() must be called before
/// using this function.
double cycleMean() const {
- return double(_cycle_length) / _cycle_size;
+ return static_cast<double>(_best_length) / _best_size;
}
/// \brief Return the found cycle.
@@ -274,153 +282,166 @@
private:
- // Initialize the internal data structures for the current strongly
- // connected component and create the policy graph.
- // The policy graph can be represented by the _policy map because
- // the out-degree of every node is 1.
- bool initCurrentComponent(int comp) {
- // Find the nodes of the current component
- _nodes.clear();
- for (NodeIt n(_gr); n != INVALID; ++n) {
- if (_comp[n] == comp) _nodes.push_back(n);
+ // Initialize
+ void init() {
+ _tol.epsilon(1e-6);
+ if (!_cycle_path) {
+ _local_path = true;
+ _cycle_path = new Path;
}
- if (_nodes.size() <= 1) return false;
- // Find the arcs of the current component
- _arcs.clear();
- for (ArcIt e(_gr); e != INVALID; ++e) {
- if ( _comp[_gr.source(e)] == comp &&
- _comp[_gr.target(e)] == comp )
- _arcs.push_back(e);
+ _queue.resize(countNodes(_gr));
+ _best_found = false;
+ _best_length = 0;
+ _best_size = 1;
+ _cycle_path->clear();
+ }
+
+ // Find strongly connected components and initialize _comp_nodes
+ // and _in_arcs
+ void findComponents() {
+ _comp_num = stronglyConnectedComponents(_gr, _comp);
+ _comp_nodes.resize(_comp_num);
+ if (_comp_num == 1) {
+ _comp_nodes[0].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ _comp_nodes[0].push_back(n);
+ _in_arcs[n].clear();
+ for (InArcIt a(_gr, n); a != INVALID; ++a) {
+ _in_arcs[n].push_back(a);
+ }
+ }
+ } else {
+ for (int i = 0; i < _comp_num; ++i)
+ _comp_nodes[i].clear();
+ for (NodeIt n(_gr); n != INVALID; ++n) {
+ int k = _comp[n];
+ _comp_nodes[k].push_back(n);
+ _in_arcs[n].clear();
+ for (InArcIt a(_gr, n); a != INVALID; ++a) {
+ if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a);
+ }
+ }
}
- // Initialize _reached, _dist, _policy maps
- for (int i = 0; i < int(_nodes.size()); ++i) {
- _reached[_nodes[i]] = false;
- _policy[_nodes[i]] = INVALID;
+ }
+
+ // Build the policy graph in the given strongly connected component
+ // (the out-degree of every node is 1)
+ bool buildPolicyGraph(int comp) {
+ _nodes = &(_comp_nodes[comp]);
+ if (_nodes->size() < 1 ||
+ (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) {
+ return false;
}
- Node u; Arc e;
- for (int j = 0; j < int(_arcs.size()); ++j) {
- e = _arcs[j];
- u = _gr.source(e);
- if (!_reached[u] || _length[e] < _dist[u]) {
- _dist[u] = _length[e];
- _policy[u] = e;
- _reached[u] = true;
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ _dist[(*_nodes)[i]] = std::numeric_limits<double>::max();
+ }
+ Node u, v;
+ Arc e;
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ v = (*_nodes)[i];
+ for (int j = 0; j < int(_in_arcs[v].size()); ++j) {
+ e = _in_arcs[v][j];
+ u = _gr.source(e);
+ if (_length[e] < _dist[u]) {
+ _dist[u] = _length[e];
+ _policy[u] = e;
+ }
}
}
return true;
}
- // Find all cycles in the policy graph.
- // Set _cycle_found to true if a cycle is found and set
- // _cycle_length, _cycle_size, _cycle_node to represent the minimum
- // mean cycle in the policy graph.
- bool findPolicyCycles() {
- typename Digraph::template NodeMap<int> level(_gr, -1);
- bool curr_cycle_found = false;
+ // Find the minimum mean cycle in the policy graph
+ void findPolicyCycle() {
+ for (int i = 0; i < int(_nodes->size()); ++i) {
+ _level[(*_nodes)[i]] = -1;
+ }
Value clength;
int csize;
- int path_cnt = 0;
Node u, v;
- // Searching for cycles
- for (int i = 0; i < int(_nodes.size()); ++i) {
- if (level[_nodes[i]] < 0) {
- u = _nodes[i];
- level[u] = path_cnt;
- while (level[u = _gr.target(_policy[u])] < 0)
- level[u] = path_cnt;
- if (level[u] == path_cnt) {
- // A cycle is found
- curr_cycle_found = true;
- clength = _length[_policy[u]];
- csize = 1;
- for (v = u; (v = _gr.target(_policy[v])) != u; ) {
- clength += _length[_policy[v]];
- ++csize;
- }
More information about the Lemon-commits
mailing list