[Lemon-commits] kpeter: r3505 - lemon/trunk/lemon
Lemon SVN
svn at lemon.cs.elte.hu
Sun Oct 5 15:36:44 CEST 2008
Author: kpeter
Date: Sun Oct 5 15:36:43 2008
New Revision: 3505
Modified:
lemon/trunk/lemon/network_simplex.h
Log:
Improve network simplex algorithm
- Remove "Limited Search" and "Combined" pivot rules.
- Add a new pivot rule "Altering Candidate List".
- Make the edge selection faster in every pivot rule.
- Set the default rule to "Block Search".
- Doc improvements.
The algorithm became about 15-35 percent faster on various input files.
"Block Search" pivot rule proved to be by far the fastest on all inputs.
Modified: lemon/trunk/lemon/network_simplex.h
==============================================================================
--- lemon/trunk/lemon/network_simplex.h (original)
+++ lemon/trunk/lemon/network_simplex.h Sun Oct 5 15:36:43 2008
@@ -32,16 +32,18 @@
#include <lemon/smart_graph.h>
#include <lemon/math.h>
+#define _DEBUG_
+
namespace lemon {
/// \addtogroup min_cost_flow
/// @{
- /// \brief Implementation of the network simplex algorithm for
- /// finding a minimum cost flow.
+ /// \brief Implementation of the primal network simplex algorithm
+ /// for finding a minimum cost flow.
///
- /// \ref NetworkSimplex implements the network simplex algorithm for
- /// finding a minimum cost flow.
+ /// \ref NetworkSimplex implements the primal network simplex algorithm
+ /// for finding a minimum cost flow.
///
/// \tparam Graph The directed graph type the algorithm runs on.
/// \tparam LowerMap The type of the lower bound map.
@@ -55,16 +57,15 @@
/// - The value types of the maps should be convertible to each other.
/// - \c CostMap::Value must be signed type.
///
- /// \note \ref NetworkSimplex provides six different pivot rule
+ /// \note \ref NetworkSimplex provides five different pivot rule
/// implementations that significantly affect the efficiency of the
/// algorithm.
- /// By default a combined pivot rule is used, which is the fastest
- /// implementation according to our benchmark tests.
- /// Another pivot rule can be selected using \ref run() function
- /// with the proper parameter.
+ /// By default "Block Search" pivot rule is used, which proved to be
+ /// by far the most efficient according to our benchmark tests.
+ /// However another pivot rule can be selected using \ref run()
+ /// function with the proper parameter.
///
/// \author Peter Kovacs
-
template < typename Graph,
typename LowerMap = typename Graph::template EdgeMap<int>,
typename CapacityMap = typename Graph::template EdgeMap<int>,
@@ -89,10 +90,13 @@
typedef typename SGraph::template NodeMap<Node> NodeNodeMap;
typedef typename SGraph::template NodeMap<Edge> EdgeNodeMap;
typedef typename SGraph::template EdgeMap<int> IntEdgeMap;
+ typedef typename SGraph::template EdgeMap<bool> BoolEdgeMap;
typedef typename Graph::template NodeMap<Node> NodeRefMap;
typedef typename Graph::template EdgeMap<Edge> EdgeRefMap;
+ typedef std::vector<Edge> EdgeVector;
+
public:
/// The type of the flow map.
@@ -107,9 +111,8 @@
FIRST_ELIGIBLE_PIVOT,
BEST_ELIGIBLE_PIVOT,
BLOCK_SEARCH_PIVOT,
- LIMITED_SEARCH_PIVOT,
CANDIDATE_LIST_PIVOT,
- COMBINED_PIVOT
+ ALTERING_LIST_PIVOT
};
private:
@@ -148,32 +151,40 @@
///
/// This class implements the "First Eligible" pivot rule
/// for the \ref NetworkSimplex "network simplex" algorithm.
+ ///
+ /// For more information see \ref NetworkSimplex::run().
class FirstEligiblePivotRule
{
private:
+ // References to the NetworkSimplex class
NetworkSimplex &_ns;
- EdgeIt _next_edge;
+ EdgeVector &_edges;
+
+ int _next_edge;
public:
- /// Constructor.
- FirstEligiblePivotRule(NetworkSimplex &ns) :
- _ns(ns), _next_edge(ns._graph) {}
-
- /// Finds the next entering edge.
- bool findEnteringEdge() {
- for (EdgeIt e = _next_edge; e != INVALID; ++e) {
+ /// Constructor
+ FirstEligiblePivotRule(NetworkSimplex &ns, EdgeVector &edges) :
+ _ns(ns), _edges(edges), _next_edge(0) {}
+
+ /// Find next entering edge
+ inline bool findEnteringEdge() {
+ Edge e;
+ for (int i = _next_edge; i < int(_edges.size()); ++i) {
+ e = _edges[i];
if (_ns._state[e] * _ns._red_cost[e] < 0) {
_ns._in_edge = e;
- _next_edge = ++e;
+ _next_edge = i + 1;
return true;
}
}
- for (EdgeIt e(_ns._graph); e != _next_edge; ++e) {
+ for (int i = 0; i < _next_edge; ++i) {
+ e = _edges[i];
if (_ns._state[e] * _ns._red_cost[e] < 0) {
_ns._in_edge = e;
- _next_edge = ++e;
+ _next_edge = i + 1;
return true;
}
}
@@ -186,21 +197,28 @@
///
/// This class implements the "Best Eligible" pivot rule
/// for the \ref NetworkSimplex "network simplex" algorithm.
+ ///
+ /// For more information see \ref NetworkSimplex::run().
class BestEligiblePivotRule
{
private:
+ // References to the NetworkSimplex class
NetworkSimplex &_ns;
+ EdgeVector &_edges;
public:
- /// Constructor.
- BestEligiblePivotRule(NetworkSimplex &ns) : _ns(ns) {}
+ /// Constructor
+ BestEligiblePivotRule(NetworkSimplex &ns, EdgeVector &edges) :
+ _ns(ns), _edges(edges) {}
- /// Finds the next entering edge.
- bool findEnteringEdge() {
+ /// Find next entering edge
+ inline bool findEnteringEdge() {
Cost min = 0;
- for (EdgeIt e(_ns._graph); e != INVALID; ++e) {
+ Edge e;
+ for (int i = 0; i < int(_edges.size()); ++i) {
+ e = _edges[i];
if (_ns._state[e] * _ns._red_cost[e] < min) {
min = _ns._state[e] * _ns._red_cost[e];
_ns._in_edge = e;
@@ -215,206 +233,291 @@
///
/// This class implements the "Block Search" pivot rule
/// for the \ref NetworkSimplex "network simplex" algorithm.
+ ///
+ /// For more information see \ref NetworkSimplex::run().
class BlockSearchPivotRule
{
private:
+ // References to the NetworkSimplex class
NetworkSimplex &_ns;
- EdgeIt _next_edge, _min_edge;
- int _block_size;
+ EdgeVector &_edges;
- static const int MIN_BLOCK_SIZE = 10;
+ int _block_size;
+ int _next_edge, _min_edge;
public:
- /// Constructor.
- BlockSearchPivotRule(NetworkSimplex &ns) :
- _ns(ns), _next_edge(ns._graph), _min_edge(ns._graph)
+ /// Constructor
+ BlockSearchPivotRule(NetworkSimplex &ns, EdgeVector &edges) :
+ _ns(ns), _edges(edges), _next_edge(0), _min_edge(0)
{
- _block_size = 2 * int(sqrt(countEdges(_ns._graph)));
- if (_block_size < MIN_BLOCK_SIZE) _block_size = MIN_BLOCK_SIZE;
+ // The main parameters of the pivot rule
+ const double BLOCK_SIZE_FACTOR = 2.0;
+ const int MIN_BLOCK_SIZE = 10;
+
+ _block_size = std::max( int(BLOCK_SIZE_FACTOR * sqrt(_edges.size())),
+ MIN_BLOCK_SIZE );
}
- /// Finds the next entering edge.
- bool findEnteringEdge() {
+ /// Find next entering edge
+ inline bool findEnteringEdge() {
Cost curr, min = 0;
- int cnt = 0;
- for (EdgeIt e = _next_edge; e != INVALID; ++e) {
+ Edge e;
+ int cnt = _block_size;
+ int i;
+ for (i = _next_edge; i < int(_edges.size()); ++i) {
+ e = _edges[i];
if ((curr = _ns._state[e] * _ns._red_cost[e]) < min) {
min = curr;
- _min_edge = e;
+ _min_edge = i;
}
- if (++cnt == _block_size) {
+ if (--cnt == 0) {
if (min < 0) break;
- cnt = 0;
+ cnt = _block_size;
}
}
- if (min == 0) {
- for (EdgeIt e(_ns._graph); e != _next_edge; ++e) {
+ if (min == 0 || cnt > 0) {
+ for (i = 0; i < _next_edge; ++i) {
+ e = _edges[i];
if ((curr = _ns._state[e] * _ns._red_cost[e]) < min) {
min = curr;
- _min_edge = e;
+ _min_edge = i;
}
- if (++cnt == _block_size) {
+ if (--cnt == 0) {
if (min < 0) break;
- cnt = 0;
+ cnt = _block_size;
}
}
}
- _ns._in_edge = _min_edge;
- _next_edge = ++_min_edge;
- return min < 0;
+ if (min >= 0) return false;
+ _ns._in_edge = _edges[_min_edge];
+ _next_edge = i;
+ return true;
}
}; //class BlockSearchPivotRule
- /// \brief Implementation of the "Limited Search" pivot rule for the
- /// \ref NetworkSimplex "network simplex" algorithm.
- ///
- /// This class implements the "Limited Search" pivot rule
- /// for the \ref NetworkSimplex "network simplex" algorithm.
- class LimitedSearchPivotRule
- {
- private:
-
- NetworkSimplex &_ns;
- EdgeIt _next_edge, _min_edge;
- int _sample_size;
-
- static const int SAMPLE_SIZE_FACTOR = 15;
- static const int MIN_SAMPLE_SIZE = 10;
-
- public:
-
- /// Constructor.
- LimitedSearchPivotRule(NetworkSimplex &ns) :
- _ns(ns), _next_edge(ns._graph), _min_edge(ns._graph)
- {
- _sample_size = countEdges(_ns._graph) *
- SAMPLE_SIZE_FACTOR / 10000;
- if (_sample_size < MIN_SAMPLE_SIZE)
- _sample_size = MIN_SAMPLE_SIZE;
- }
-
- /// Finds the next entering edge.
- bool findEnteringEdge() {
- Cost curr, min = 0;
- int cnt = 0;
- for (EdgeIt e = _next_edge; e != INVALID; ++e) {
- if ((curr = _ns._state[e] * _ns._red_cost[e]) < min) {
- min = curr;
- _min_edge = e;
- }
- if (curr < 0 && ++cnt == _sample_size) break;
- }
- if (min == 0) {
- for (EdgeIt e(_ns._graph); e != _next_edge; ++e) {
- if ((curr = _ns._state[e] * _ns._red_cost[e]) < min) {
- min = curr;
- _min_edge = e;
- }
- if (curr < 0 && ++cnt == _sample_size) break;
- }
- }
- _ns._in_edge = _min_edge;
- _next_edge = ++_min_edge;
- return min < 0;
- }
- }; //class LimitedSearchPivotRule
-
/// \brief Implementation of the "Candidate List" pivot rule for the
/// \ref NetworkSimplex "network simplex" algorithm.
///
/// This class implements the "Candidate List" pivot rule
/// for the \ref NetworkSimplex "network simplex" algorithm.
+ ///
+ /// For more information see \ref NetworkSimplex::run().
class CandidateListPivotRule
{
private:
+ // References to the NetworkSimplex class
NetworkSimplex &_ns;
+ EdgeVector &_edges;
- // The list of candidate edges.
- std::vector<Edge> _candidates;
- // The maximum length of the edge list.
- int _list_length;
- // The maximum number of minor iterations between two major
- // itarations.
- int _minor_limit;
-
- int _minor_count;
- EdgeIt _next_edge;
-
- static const int LIST_LENGTH_FACTOR = 20;
- static const int MINOR_LIMIT_FACTOR = 10;
- static const int MIN_LIST_LENGTH = 10;
- static const int MIN_MINOR_LIMIT = 2;
+ EdgeVector _candidates;
+ int _list_length, _minor_limit;
+ int _curr_length, _minor_count;
+ int _next_edge, _min_edge;
public:
- /// Constructor.
- CandidateListPivotRule(NetworkSimplex &ns) :
- _ns(ns), _next_edge(ns._graph)
+ /// Constructor
+ CandidateListPivotRule(NetworkSimplex &ns, EdgeVector &edges) :
+ _ns(ns), _edges(edges), _next_edge(0), _min_edge(0)
{
- int edge_num = countEdges(_ns._graph);
- _minor_count = 0;
- _list_length = edge_num * LIST_LENGTH_FACTOR / 10000;
- if (_list_length < MIN_LIST_LENGTH)
- _list_length = MIN_LIST_LENGTH;
- _minor_limit = _list_length * MINOR_LIMIT_FACTOR / 100;
- if (_minor_limit < MIN_MINOR_LIMIT)
- _minor_limit = MIN_MINOR_LIMIT;
+ // The main parameters of the pivot rule
+ const double LIST_LENGTH_FACTOR = 1.0;
+ const int MIN_LIST_LENGTH = 10;
+ const double MINOR_LIMIT_FACTOR = 0.1;
+ const int MIN_MINOR_LIMIT = 3;
+
+ _list_length = std::max( int(LIST_LENGTH_FACTOR * sqrt(_edges.size())),
+ MIN_LIST_LENGTH );
+ _minor_limit = std::max( int(MINOR_LIMIT_FACTOR * _list_length),
+ MIN_MINOR_LIMIT );
+ _curr_length = _minor_count = 0;
+ _candidates.resize(_list_length);
}
- /// Finds the next entering edge.
- bool findEnteringEdge() {
+ /// Find next entering edge
+ inline bool findEnteringEdge() {
Cost min, curr;
- if (_minor_count < _minor_limit && _candidates.size() > 0) {
- // Minor iteration
+ if (_curr_length > 0 && _minor_count < _minor_limit) {
+ // Minor iteration: selecting the best eligible edge from
+ // the current candidate list
++_minor_count;
Edge e;
min = 0;
- for (int i = 0; i < int(_candidates.size()); ++i) {
+ for (int i = 0; i < _curr_length; ++i) {
e = _candidates[i];
- if ((curr = _ns._state[e] * _ns._red_cost[e]) < min) {
+ curr = _ns._state[e] * _ns._red_cost[e];
+ if (curr < min) {
min = curr;
_ns._in_edge = e;
}
+ if (curr >= 0) {
+ _candidates[i--] = _candidates[--_curr_length];
+ }
}
if (min < 0) return true;
}
- // Major iteration
- _candidates.clear();
- EdgeIt e = _next_edge;
+ // Major iteration: building a new candidate list
+ Edge e;
min = 0;
- for ( ; e != INVALID; ++e) {
+ _curr_length = 0;
+ int i;
+ for (i = _next_edge; i < int(_edges.size()); ++i) {
+ e = _edges[i];
if ((curr = _ns._state[e] * _ns._red_cost[e]) < 0) {
- _candidates.push_back(e);
+ _candidates[_curr_length++] = e;
if (curr < min) {
min = curr;
- _ns._in_edge = e;
+ _min_edge = i;
}
- if (int(_candidates.size()) == _list_length) break;
+ if (_curr_length == _list_length) break;
}
}
- if (int(_candidates.size()) < _list_length) {
- for (e = EdgeIt(_ns._graph); e != _next_edge; ++e) {
+ if (_curr_length < _list_length) {
+ for (i = 0; i < _next_edge; ++i) {
+ e = _edges[i];
if ((curr = _ns._state[e] * _ns._red_cost[e]) < 0) {
- _candidates.push_back(e);
+ _candidates[_curr_length++] = e;
if (curr < min) {
min = curr;
- _ns._in_edge = e;
+ _min_edge = i;
}
- if (int(_candidates.size()) == _list_length) break;
+ if (_curr_length == _list_length) break;
}
}
}
- if (_candidates.size() == 0) return false;
+ if (_curr_length == 0) return false;
_minor_count = 1;
- _next_edge = ++e;
+ _ns._in_edge = _edges[_min_edge];
+ _next_edge = i;
return true;
}
}; //class CandidateListPivotRule
+ /// \brief Implementation of the "Altering Candidate List" pivot rule
+ /// for the \ref NetworkSimplex "network simplex" algorithm.
+ ///
+ /// This class implements the "Altering Candidate List" pivot rule
+ /// for the \ref NetworkSimplex "network simplex" algorithm.
+ ///
+ /// For more information see \ref NetworkSimplex::run().
+ class AlteringListPivotRule
+ {
+ private:
+
+ // References to the NetworkSimplex class
+ NetworkSimplex &_ns;
+ EdgeVector &_edges;
+
+ EdgeVector _candidates;
+ SCostMap _cand_cost;
+ int _block_size, _head_length, _curr_length;
+ int _next_edge;
+
+ // Functor class to compare edges during sort of the candidate list
+ class SortFunc
+ {
+ private:
+ const SCostMap &_map;
+ public:
+ SortFunc(const SCostMap &map) : _map(map) {}
+ bool operator()(const Edge &e1, const Edge &e2) {
+ return _map[e1] < _map[e2];
+ }
+ };
+
+ SortFunc _sort_func;
+
+ public:
+
+ /// Constructor
+ AlteringListPivotRule(NetworkSimplex &ns, EdgeVector &edges) :
+ _ns(ns), _edges(edges), _cand_cost(_ns._graph),
+ _next_edge(0), _sort_func(_cand_cost)
+ {
+ // The main parameters of the pivot rule
+ const double BLOCK_SIZE_FACTOR = 1.0;
+ const int MIN_BLOCK_SIZE = 10;
+ const double HEAD_LENGTH_FACTOR = 0.1;
+ const int MIN_HEAD_LENGTH = 5;
+
+ _block_size = std::max( int(BLOCK_SIZE_FACTOR * sqrt(_edges.size())),
+ MIN_BLOCK_SIZE );
+ _head_length = std::max( int(HEAD_LENGTH_FACTOR * _block_size),
+ MIN_HEAD_LENGTH );
+ _candidates.resize(_head_length + _block_size);
+ _curr_length = 0;
+ }
+
+ /// Find next entering edge
+ inline bool findEnteringEdge() {
+ // Checking the current candidate list
+ Edge e;
+ for (int idx = 0; idx < _curr_length; ++idx) {
+ e = _candidates[idx];
+ if ((_cand_cost[e] = _ns._state[e] * _ns._red_cost[e]) >= 0) {
+ _candidates[idx--] = _candidates[--_curr_length];
+ }
+ }
+
+ // Extending the list
+ int cnt = _block_size;
+ int last_edge = 0;
+ int limit = _head_length;
+ for (int i = _next_edge; i < int(_edges.size()); ++i) {
+ e = _edges[i];
+ if ((_cand_cost[e] = _ns._state[e] * _ns._red_cost[e]) < 0) {
+ _candidates[_curr_length++] = e;
+ last_edge = i;
+ }
+ if (--cnt == 0) {
+ if (_curr_length > limit) break;
+ limit = 0;
+ cnt = _block_size;
+ }
+ }
+ if (_curr_length <= limit) {
+ for (int i = 0; i < _next_edge; ++i) {
+ e = _edges[i];
+ if ((_cand_cost[e] = _ns._state[e] * _ns._red_cost[e]) < 0) {
+ _candidates[_curr_length++] = e;
+ last_edge = i;
+ }
+ if (--cnt == 0) {
+ if (_curr_length > limit) break;
+ limit = 0;
+ cnt = _block_size;
+ }
+ }
+ }
+ if (_curr_length == 0) return false;
+ _next_edge = last_edge + 1;
+
+ // Sorting the list partially
+ EdgeVector::iterator sort_end = _candidates.begin();
+ EdgeVector::iterator vector_end = _candidates.begin();
+ for (int idx = 0; idx < _curr_length; ++idx) {
+ ++vector_end;
+ if (idx <= _head_length) ++sort_end;
+ }
+ partial_sort(_candidates.begin(), sort_end, vector_end, _sort_func);
+
+ _ns._in_edge = _candidates[0];
+ if (_curr_length > _head_length) {
+ _candidates[0] = _candidates[_head_length - 1];
+ _curr_length = _head_length - 1;
+ } else {
+ _candidates[0] = _candidates[_curr_length - 1];
+ --_curr_length;
+ }
+
+ return true;
+ }
+ }; //class AlteringListPivotRule
+
private:
// State constants for edges
@@ -424,9 +527,6 @@
STATE_LOWER = 1
};
- // Constant for the combined pivot rule.
- static const int COMBINED_PIVOT_MAX_DEG = 5;
-
private:
// The directed graph the algorithm runs on
@@ -466,6 +566,9 @@
// The reduced cost map
ReducedCostMap _red_cost;
+ // The non-artifical edges
+ EdgeVector _edges;
+
// Members for handling the original graph
FlowMap *_flow_result;
PotentialMap *_potential_result;
@@ -672,9 +775,9 @@
if (_local_potential) delete _potential_result;
}
- /// \brief Sets the flow map.
+ /// \brief Set the flow map.
///
- /// Sets the flow map.
+ /// Set the flow map.
///
/// \return \c (*this)
NetworkSimplex& flowMap(FlowMap &map) {
@@ -686,9 +789,9 @@
return *this;
}
- /// \brief Sets the potential map.
+ /// \brief Set the potential map.
///
- /// Sets the potential map.
+ /// Set the potential map.
///
/// \return \c (*this)
NetworkSimplex& potentialMap(PotentialMap &map) {
@@ -701,8 +804,6 @@
}
/// \name Execution control
- /// The only way to execute the algorithm is to call the run()
- /// function.
/// @{
@@ -726,50 +827,49 @@
/// every iteration in a wraparound fashion and the best eligible
/// edge is selected from this block (\ref BlockSearchPivotRule).
///
- /// - LIMITED_SEARCH_PIVOT A specified number of eligible edges are
- /// examined in every iteration in a wraparound fashion and the best
- /// one is selected from them (\ref LimitedSearchPivotRule).
- ///
- /// - CANDIDATE_LIST_PIVOT In major iterations a candidate list is
- /// built from eligible edges and it is used for edge selection in
- /// the following minor iterations (\ref CandidateListPivotRule).
- ///
- /// - COMBINED_PIVOT This is a combined version of the two fastest
- /// pivot rules.
- /// For rather sparse graphs \ref LimitedSearchPivotRule
- /// "Limited Search" implementation is used, otherwise
- /// \ref BlockSearchPivotRule "Block Search" pivot rule is used.
- /// According to our benchmark tests this combined method is the
- /// most efficient.
+ /// - CANDIDATE_LIST_PIVOT In a major iteration a candidate list is
+ /// built from eligible edges in a wraparound fashion and in the
+ /// following minor iterations the best eligible edge is selected
+ /// from this list (\ref CandidateListPivotRule).
+ ///
+ /// - ALTERING_LIST_PIVOT It is a modified version of the
+ /// "Candidate List" pivot rule. It keeps only the several best
+ /// eligible edges from the former candidate list and extends this
+ /// list in every iteration (\ref AlteringListPivotRule).
+ ///
+ /// According to our comprehensive benchmark tests the "Block Search"
+ /// pivot rule proved to be by far the fastest and the most robust
+ /// on various test inputs. Thus it is the default option.
///
/// \return \c true if a feasible flow can be found.
- bool run(PivotRuleEnum pivot_rule = COMBINED_PIVOT) {
+ bool run(PivotRuleEnum pivot_rule = BLOCK_SEARCH_PIVOT) {
return init() && start(pivot_rule);
}
/// @}
/// \name Query Functions
- /// The result of the algorithm can be obtained using these
- /// functions.
- /// \n run() must be called before using them.
+ /// The results of the algorithm can be obtained using these
+ /// functions.\n
+ /// \ref lemon::NetworkSimplex::run() "run()" must be called before
+ /// using them.
/// @{
- /// \brief Returns a const reference to the edge map storing the
+ /// \brief Return a const reference to the edge map storing the
/// found flow.
///
- /// Returns a const reference to the edge map storing the found flow.
+ /// Return a const reference to the edge map storing the found flow.
///
/// \pre \ref run() must be called before using this function.
const FlowMap& flowMap() const {
return *_flow_result;
}
- /// \brief Returns a const reference to the node map storing the
+ /// \brief Return a const reference to the node map storing the
/// found potentials (the dual solution).
///
- /// Returns a const reference to the node map storing the found
+ /// Return a const reference to the node map storing the found
/// potentials (the dual solution).
///
/// \pre \ref run() must be called before using this function.
@@ -777,27 +877,27 @@
return *_potential_result;
}
- /// \brief Returns the flow on the given edge.
+ /// \brief Return the flow on the given edge.
///
- /// Returns the flow on the given edge.
+ /// Return the flow on the given edge.
///
/// \pre \ref run() must be called before using this function.
Capacity flow(const typename Graph::Edge& edge) const {
return (*_flow_result)[edge];
}
- /// \brief Returns the potential of the given node.
+ /// \brief Return the potential of the given node.
///
- /// Returns the potential of the given node.
+ /// Return the potential of the given node.
///
/// \pre \ref run() must be called before using this function.
Cost potential(const typename Graph::Node& node) const {
return (*_potential_result)[node];
}
- /// \brief Returns the total cost of the found flow.
+ /// \brief Return the total cost of the found flow.
///
- /// Returns the total cost of the found flow. The complexity of the
+ /// Return the total cost of the found flow. The complexity of the
/// function is \f$ O(e) \f$.
///
/// \pre \ref run() must be called before using this function.
@@ -812,7 +912,7 @@
private:
- /// \brief Extends the underlaying graph and initializes all the
+ /// \brief Extend the underlying graph and initialize all the
/// node and edge maps.
bool init() {
if (!_valid_supply) return false;
@@ -827,8 +927,10 @@
_local_potential = true;
}
- // Initializing state and flow maps
+ // Initializing the edge vector and the edge maps
+ _edges.reserve(countEdges(_graph));
for (EdgeIt e(_graph); e != INVALID; ++e) {
+ _edges.push_back(e);
_flow[e] = 0;
_state[e] = STATE_LOWER;
}
@@ -873,8 +975,8 @@
return true;
}
- /// Finds the join node.
- Node findJoinNode() {
+ /// Find the join node.
+ inline Node findJoinNode() {
Node u = _graph.source(_in_edge);
Node v = _graph.target(_in_edge);
while (u != v) {
@@ -888,9 +990,10 @@
return u;
}
- /// \brief Finds the leaving edge of the cycle. Returns \c true if
- /// the leaving edge is not the same as the entering edge.
- bool findLeavingEdge() {
+ /// \brief Find the leaving edge of the cycle.
+ /// \return \c true if the leaving edge is not the same as the
+ /// entering edge.
+ inline bool findLeavingEdge() {
// Initializing first and second nodes according to the direction
// of the cycle
if (_state[_in_edge] == STATE_LOWER) {
@@ -934,8 +1037,8 @@
return result;
}
- /// Changes \c flow and \c state edge maps.
- void changeFlows(bool change) {
+ /// Change \c flow and \c state edge maps.
+ inline void changeFlows(bool change) {
// Augmenting along the cycle
if (delta > 0) {
Capacity val = _state[_in_edge] * delta;
@@ -957,8 +1060,8 @@
}
}
- /// Updates \c thread and \c parent node maps.
- void updateThreadParent() {
+ /// Update \c thread and \c parent node maps.
+ inline void updateThreadParent() {
Node u;
v_out = _parent[u_out];
@@ -1016,8 +1119,8 @@
}
}
- /// Updates \c pred_edge and \c forward node maps.
- void updatePredEdge() {
+ /// Update \c pred_edge and \c forward node maps.
+ inline void updatePredEdge() {
Node u = u_out, v;
while (u != u_in) {
v = _parent[u];
@@ -1029,8 +1132,8 @@
_forward[u_in] = (u_in == _graph.source(_in_edge));
}
- /// Updates \c depth and \c potential node maps.
- void updateDepthPotential() {
+ /// Update \c depth and \c potential node maps.
+ inline void updateDepthPotential() {
_depth[u_in] = _depth[v_in] + 1;
_potential[u_in] = _forward[u_in] ?
_potential[v_in] - _cost[_pred_edge[u_in]] :
@@ -1049,8 +1152,9 @@
}
}
- /// Executes the algorithm.
+ /// Execute the algorithm.
bool start(PivotRuleEnum pivot_rule) {
+ // Selecting the pivot rule implementation
switch (pivot_rule) {
case FIRST_ELIGIBLE_PIVOT:
return start<FirstEligiblePivotRule>();
@@ -1058,23 +1162,17 @@
return start<BestEligiblePivotRule>();
case BLOCK_SEARCH_PIVOT:
return start<BlockSearchPivotRule>();
- case LIMITED_SEARCH_PIVOT:
- return start<LimitedSearchPivotRule>();
case CANDIDATE_LIST_PIVOT:
return start<CandidateListPivotRule>();
- case COMBINED_PIVOT:
- if ( countEdges(_graph) / countNodes(_graph) <=
- COMBINED_PIVOT_MAX_DEG )
- return start<LimitedSearchPivotRule>();
- else
- return start<BlockSearchPivotRule>();
+ case ALTERING_LIST_PIVOT:
+ return start<AlteringListPivotRule>();
}
return false;
}
template<class PivotRuleImplementation>
bool start() {
- PivotRuleImplementation pivot(*this);
+ PivotRuleImplementation pivot(*this, _edges);
// Executing the network simplex algorithm
while (pivot.findEnteringEdge()) {
More information about the Lemon-commits
mailing list