[Lemon-commits] kpeter: r3456 - lemon/trunk/lemon
Lemon SVN
svn at lemon.cs.elte.hu
Mon Feb 18 04:30:14 CET 2008
Author: kpeter
Date: Mon Feb 18 04:30:12 2008
New Revision: 3456
Modified:
lemon/trunk/lemon/cycle_canceling.h
Log:
Improvements in CycleCanceling.
Main changes:
- Use function parameter instead of #define commands to select negative
cycle detection method.
- Change the name of private members to start with "_".
- Change the name of function parameters not to start with "_".
- Remove unnecessary documentation for private members.
- Doc improvements.
Modified: lemon/trunk/lemon/cycle_canceling.h
==============================================================================
--- lemon/trunk/lemon/cycle_canceling.h (original)
+++ lemon/trunk/lemon/cycle_canceling.h Mon Feb 18 04:30:12 2008
@@ -22,37 +22,15 @@
/// \ingroup min_cost_flow
///
/// \file
-/// \brief A cycle-canceling algorithm for finding a minimum cost flow.
+/// \brief Cycle-canceling algorithm for finding a minimum cost flow.
#include <vector>
#include <lemon/graph_adaptor.h>
-#include <lemon/circulation.h>
-
-/// \brief The used cycle-canceling method.
-#define LIMITED_CYCLE_CANCELING
-//#define MIN_MEAN_CYCLE_CANCELING
-
-#ifdef LIMITED_CYCLE_CANCELING
- #include <lemon/bellman_ford.h>
- // The maximum number of iterations for the first execution of the
- // Bellman-Ford algorithm. It should be at least 2.
- #define STARTING_LIMIT 2
- // The iteration limit for the Bellman-Ford algorithm is multiplied by
- // <tt>ALPHA_MUL / ALPHA_DIV</tt> in every round.
- // <tt>ALPHA_MUL / ALPHA_DIV</tt> must be greater than 1.
- #define ALPHA_MUL 3
- #define ALPHA_DIV 2
-
-//#define _ONLY_ONE_CYCLE_
-//#define _NO_BACK_STEP_
-#endif
-
-#ifdef MIN_MEAN_CYCLE_CANCELING
- #include <lemon/min_mean_cycle.h>
- #include <lemon/path.h>
-#endif
+#include <lemon/path.h>
-//#define _DEBUG_ITER_
+#include <lemon/circulation.h>
+#include <lemon/bellman_ford.h>
+#include <lemon/min_mean_cycle.h>
namespace lemon {
@@ -65,33 +43,40 @@
/// \ref CycleCanceling implements a cycle-canceling algorithm for
/// finding a minimum cost flow.
///
- /// \param Graph The directed graph type the algorithm runs on.
- /// \param LowerMap The type of the lower bound map.
- /// \param CapacityMap The type of the capacity (upper bound) map.
- /// \param CostMap The type of the cost (length) map.
- /// \param SupplyMap The type of the supply map.
+ /// \tparam Graph The directed graph type the algorithm runs on.
+ /// \tparam LowerMap The type of the lower bound map.
+ /// \tparam CapacityMap The type of the capacity (upper bound) map.
+ /// \tparam CostMap The type of the cost (length) map.
+ /// \tparam SupplyMap The type of the supply map.
///
/// \warning
- /// - Edge capacities and costs should be non-negative integers.
- /// However \c CostMap::Value should be signed type.
- /// - Supply values should be signed integers.
- /// - \c LowerMap::Value must be convertible to
- /// \c CapacityMap::Value and \c CapacityMap::Value must be
- /// convertible to \c SupplyMap::Value.
+ /// - Edge capacities and costs should be \e non-negative \e integers.
+ /// - Supply values should be \e signed \e integers.
+ /// - \c LowerMap::Value must be convertible to \c CapacityMap::Value.
+ /// - \c CapacityMap::Value and \c SupplyMap::Value must be
+ /// convertible to each other.
+ /// - All value types must be convertible to \c CostMap::Value, which
+ /// must be signed type.
+ ///
+ /// \note By default the \ref BellmanFord "Bellman-Ford" algorithm is
+ /// used for negative cycle detection with limited iteration number.
+ /// However \ref CycleCanceling also provides the "Minimum Mean
+ /// Cycle-Canceling" algorithm, which is \e strongly \e polynomial,
+ /// but rather slower in practice.
+ /// To use this version of the algorithm, call \ref run() with \c true
+ /// parameter.
///
/// \author Peter Kovacs
template < typename Graph,
typename LowerMap = typename Graph::template EdgeMap<int>,
- typename CapacityMap = LowerMap,
+ typename CapacityMap = typename Graph::template EdgeMap<int>,
typename CostMap = typename Graph::template EdgeMap<int>,
- typename SupplyMap = typename Graph::template NodeMap
- <typename CapacityMap::Value> >
+ typename SupplyMap = typename Graph::template NodeMap<int> >
class CycleCanceling
{
GRAPH_TYPEDEFS(typename Graph);
- typedef typename LowerMap::Value Lower;
typedef typename CapacityMap::Value Capacity;
typedef typename CostMap::Value Cost;
typedef typename SupplyMap::Value Supply;
@@ -110,180 +95,200 @@
/// The type of the flow map.
typedef typename Graph::template EdgeMap<Capacity> FlowMap;
- protected:
+ private:
- /// Map adaptor class for handling residual edge costs.
- class ResCostMap : public MapBase<ResEdge, Cost>
+ /// \brief Map adaptor class for handling residual edge costs.
+ ///
+ /// \ref ResidualCostMap is a map adaptor class for handling
+ /// residual edge costs.
+ class ResidualCostMap : public MapBase<ResEdge, Cost>
{
private:
- const CostMap &cost_map;
+ const CostMap &_cost_map;
public:
- ResCostMap(const CostMap &_cost) : cost_map(_cost) {}
+ ///\e
+ ResidualCostMap(const CostMap &cost_map) : _cost_map(cost_map) {}
+ ///\e
Cost operator[](const ResEdge &e) const {
- return ResGraph::forward(e) ? cost_map[e] : -cost_map[e];
+ return ResGraph::forward(e) ? _cost_map[e] : -_cost_map[e];
}
- }; //class ResCostMap
+ }; //class ResidualCostMap
- protected:
+ private:
- /// The directed graph the algorithm runs on.
- const Graph &graph;
- /// The original lower bound map.
- const LowerMap *lower;
- /// The modified capacity map.
- CapacityEdgeMap capacity;
- /// The cost map.
- const CostMap &cost;
- /// The modified supply map.
- SupplyNodeMap supply;
- bool valid_supply;
-
- /// The current flow.
- FlowMap flow;
- /// The residual graph.
- ResGraph res_graph;
- /// The residual cost map.
- ResCostMap res_cost;
+ // The maximum number of iterations for the first execution of the
+ // Bellman-Ford algorithm. It should be at least 2.
+ static const int BF_FIRST_LIMIT = 2;
+ // The iteration limit for the Bellman-Ford algorithm is multiplied
+ // by BF_ALPHA in every round.
+ static const double BF_ALPHA = 1.5;
+
+ private:
+
+ // The directed graph the algorithm runs on
+ const Graph &_graph;
+ // The original lower bound map
+ const LowerMap *_lower;
+ // The modified capacity map
+ CapacityEdgeMap _capacity;
+ // The original cost map
+ const CostMap &_cost;
+ // The modified supply map
+ SupplyNodeMap _supply;
+ bool _valid_supply;
+
+ // Edge map of the current flow
+ FlowMap _flow;
+
+ // The residual graph
+ ResGraph _res_graph;
+ // The residual cost map
+ ResidualCostMap _res_cost;
- public :
+ public:
/// \brief General constructor of the class (with lower bounds).
///
/// General constructor of the class (with lower bounds).
///
- /// \param _graph The directed graph the algorithm runs on.
- /// \param _lower The lower bounds of the edges.
- /// \param _capacity The capacities (upper bounds) of the edges.
- /// \param _cost The cost (length) values of the edges.
- /// \param _supply The supply values of the nodes (signed).
- CycleCanceling( const Graph &_graph,
- const LowerMap &_lower,
- const CapacityMap &_capacity,
- const CostMap &_cost,
- const SupplyMap &_supply ) :
- graph(_graph), lower(&_lower), capacity(_graph), cost(_cost),
- supply(_graph), flow(_graph, 0),
- res_graph(_graph, capacity, flow), res_cost(cost)
+ /// \param graph The directed graph the algorithm runs on.
+ /// \param lower The lower bounds of the edges.
+ /// \param capacity The capacities (upper bounds) of the edges.
+ /// \param cost The cost (length) values of the edges.
+ /// \param supply The supply values of the nodes (signed).
+ CycleCanceling( const Graph &graph,
+ const LowerMap &lower,
+ const CapacityMap &capacity,
+ const CostMap &cost,
+ const SupplyMap &supply ) :
+ _graph(graph), _lower(&lower), _capacity(graph), _cost(cost),
+ _supply(graph), _flow(graph, 0),
+ _res_graph(graph, _capacity, _flow), _res_cost(_cost)
{
// Removing non-zero lower bounds
- capacity = subMap(_capacity, _lower);
+ _capacity = subMap(capacity, lower);
Supply sum = 0;
- for (NodeIt n(graph); n != INVALID; ++n) {
- Supply s = _supply[n];
- for (InEdgeIt e(graph, n); e != INVALID; ++e)
- s += _lower[e];
- for (OutEdgeIt e(graph, n); e != INVALID; ++e)
- s -= _lower[e];
- sum += (supply[n] = s);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Supply s = supply[n];
+ for (InEdgeIt e(_graph, n); e != INVALID; ++e)
+ s += lower[e];
+ for (OutEdgeIt e(_graph, n); e != INVALID; ++e)
+ s -= lower[e];
+ sum += (_supply[n] = s);
}
- valid_supply = sum == 0;
+ _valid_supply = sum == 0;
}
/// \brief General constructor of the class (without lower bounds).
///
/// General constructor of the class (without lower bounds).
///
- /// \param _graph The directed graph the algorithm runs on.
- /// \param _capacity The capacities (upper bounds) of the edges.
- /// \param _cost The cost (length) values of the edges.
- /// \param _supply The supply values of the nodes (signed).
- CycleCanceling( const Graph &_graph,
- const CapacityMap &_capacity,
- const CostMap &_cost,
- const SupplyMap &_supply ) :
- graph(_graph), lower(NULL), capacity(_capacity), cost(_cost),
- supply(_supply), flow(_graph, 0),
- res_graph(_graph, capacity, flow), res_cost(cost)
+ /// \param graph The directed graph the algorithm runs on.
+ /// \param capacity The capacities (upper bounds) of the edges.
+ /// \param cost The cost (length) values of the edges.
+ /// \param supply The supply values of the nodes (signed).
+ CycleCanceling( const Graph &graph,
+ const CapacityMap &capacity,
+ const CostMap &cost,
+ const SupplyMap &supply ) :
+ _graph(graph), _lower(NULL), _capacity(capacity), _cost(cost),
+ _supply(supply), _flow(graph, 0),
+ _res_graph(graph, _capacity, _flow), _res_cost(_cost)
{
// Checking the sum of supply values
Supply sum = 0;
- for (NodeIt n(graph); n != INVALID; ++n) sum += supply[n];
- valid_supply = sum == 0;
+ for (NodeIt n(_graph); n != INVALID; ++n) sum += _supply[n];
+ _valid_supply = sum == 0;
}
/// \brief Simple constructor of the class (with lower bounds).
///
/// Simple constructor of the class (with lower bounds).
///
- /// \param _graph The directed graph the algorithm runs on.
- /// \param _lower The lower bounds of the edges.
- /// \param _capacity The capacities (upper bounds) of the edges.
- /// \param _cost The cost (length) values of the edges.
- /// \param _s The source node.
- /// \param _t The target node.
- /// \param _flow_value The required amount of flow from node \c _s
- /// to node \c _t (i.e. the supply of \c _s and the demand of \c _t).
- CycleCanceling( const Graph &_graph,
- const LowerMap &_lower,
- const CapacityMap &_capacity,
- const CostMap &_cost,
- Node _s, Node _t,
- Supply _flow_value ) :
- graph(_graph), lower(&_lower), capacity(_graph), cost(_cost),
- supply(_graph), flow(_graph, 0),
- res_graph(_graph, capacity, flow), res_cost(cost)
+ /// \param graph The directed graph the algorithm runs on.
+ /// \param lower The lower bounds of the edges.
+ /// \param capacity The capacities (upper bounds) of the edges.
+ /// \param cost The cost (length) values of the edges.
+ /// \param s The source node.
+ /// \param t The target node.
+ /// \param flow_value The required amount of flow from node \c s
+ /// to node \c t (i.e. the supply of \c s and the demand of \c t).
+ CycleCanceling( const Graph &graph,
+ const LowerMap &lower,
+ const CapacityMap &capacity,
+ const CostMap &cost,
+ Node s, Node t,
+ Supply flow_value ) :
+ _graph(graph), _lower(&lower), _capacity(graph), _cost(cost),
+ _supply(graph), _flow(graph, 0),
+ _res_graph(graph, _capacity, _flow), _res_cost(_cost)
{
// Removing non-zero lower bounds
- capacity = subMap(_capacity, _lower);
- for (NodeIt n(graph); n != INVALID; ++n) {
- Supply s = 0;
- if (n == _s) s = _flow_value;
- if (n == _t) s = -_flow_value;
- for (InEdgeIt e(graph, n); e != INVALID; ++e)
- s += _lower[e];
- for (OutEdgeIt e(graph, n); e != INVALID; ++e)
- s -= _lower[e];
- supply[n] = s;
+ _capacity = subMap(capacity, lower);
+ for (NodeIt n(_graph); n != INVALID; ++n) {
+ Supply sum = 0;
+ if (n == s) sum = flow_value;
+ if (n == t) sum = -flow_value;
+ for (InEdgeIt e(_graph, n); e != INVALID; ++e)
+ sum += lower[e];
+ for (OutEdgeIt e(_graph, n); e != INVALID; ++e)
+ sum -= lower[e];
+ _supply[n] = sum;
}
- valid_supply = true;
+ _valid_supply = true;
}
/// \brief Simple constructor of the class (without lower bounds).
///
/// Simple constructor of the class (without lower bounds).
///
- /// \param _graph The directed graph the algorithm runs on.
- /// \param _capacity The capacities (upper bounds) of the edges.
- /// \param _cost The cost (length) values of the edges.
- /// \param _s The source node.
- /// \param _t The target node.
- /// \param _flow_value The required amount of flow from node \c _s
- /// to node \c _t (i.e. the supply of \c _s and the demand of \c _t).
- CycleCanceling( const Graph &_graph,
- const CapacityMap &_capacity,
- const CostMap &_cost,
- Node _s, Node _t,
- Supply _flow_value ) :
- graph(_graph), lower(NULL), capacity(_capacity), cost(_cost),
- supply(_graph, 0), flow(_graph, 0),
- res_graph(_graph, capacity, flow), res_cost(cost)
+ /// \param graph The directed graph the algorithm runs on.
+ /// \param capacity The capacities (upper bounds) of the edges.
+ /// \param cost The cost (length) values of the edges.
+ /// \param s The source node.
+ /// \param t The target node.
+ /// \param flow_value The required amount of flow from node \c s
+ /// to node \c t (i.e. the supply of \c s and the demand of \c t).
+ CycleCanceling( const Graph &graph,
+ const CapacityMap &capacity,
+ const CostMap &cost,
+ Node s, Node t,
+ Supply flow_value ) :
+ _graph(graph), _lower(NULL), _capacity(capacity), _cost(cost),
+ _supply(graph, 0), _flow(graph, 0),
+ _res_graph(graph, _capacity, _flow), _res_cost(_cost)
{
- supply[_s] = _flow_value;
- supply[_t] = -_flow_value;
- valid_supply = true;
+ _supply[s] = flow_value;
+ _supply[t] = -flow_value;
+ _valid_supply = true;
}
/// \brief Runs the algorithm.
///
/// Runs the algorithm.
///
+ /// \param min_mean_cc Set this parameter to \c true to run the
+ /// "Minimum Mean Cycle-Canceling" algorithm, which is strongly
+ /// polynomial, but rather slower in practice.
+ ///
/// \return \c true if a feasible flow can be found.
- bool run() {
- return init() && start();
+ bool run(bool min_mean_cc = false) {
+ return init() && start(min_mean_cc);
}
- /// \brief Returns a const reference to the flow map.
+ /// \brief Returns a const reference to the edge map storing the
+ /// found flow.
///
- /// Returns a const reference to the flow map.
+ /// Returns 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;
+ return _flow;
}
/// \brief Returns the total cost of the found flow.
@@ -294,57 +299,54 @@
/// \pre \ref run() must be called before using this function.
Cost totalCost() const {
Cost c = 0;
- for (EdgeIt e(graph); e != INVALID; ++e)
- c += flow[e] * cost[e];
+ for (EdgeIt e(_graph); e != INVALID; ++e)
+ c += _flow[e] * _cost[e];
return c;
}
- protected:
+ private:
/// Initializes the algorithm.
bool init() {
- // Checking the sum of supply values
- Supply sum = 0;
- for (NodeIt n(graph); n != INVALID; ++n) sum += supply[n];
- if (sum != 0) return false;
+ if (!_valid_supply) return false;
- // Finding a feasible flow
+ // Finding a feasible flow using Circulation
Circulation< Graph, ConstMap<Edge, Capacity>, CapacityEdgeMap,
SupplyMap >
- circulation( graph, constMap<Edge>((Capacity)0), capacity,
- supply );
- circulation.flowMap(flow);
- return circulation.run();
+ circulation( _graph, constMap<Edge>((Capacity)0), _capacity,
+ _supply );
+ return circulation.flowMap(_flow).run();
}
-#ifdef LIMITED_CYCLE_CANCELING
- /// \brief Executes a cycle-canceling algorithm using
- /// \ref Bellman-Ford algorithm with limited iteration count.
+ bool start(bool min_mean_cc) {
+ if (min_mean_cc)
+ return startMinMean();
+ else
+ return start();
+ }
+
+ /// \brief Executes the algorithm using \ref BellmanFord.
+ ///
+ /// Executes the algorithm using the \ref BellmanFord
+ /// "Bellman-Ford" algorithm for negative cycle detection with
+ /// successively larger limit for the number of iterations.
bool start() {
- typename BellmanFord<ResGraph, ResCostMap>::PredMap pred(res_graph);
- typename ResGraph::template NodeMap<int> visited(res_graph);
+ typename BellmanFord<ResGraph, ResidualCostMap>::PredMap pred(_res_graph);
+ typename ResGraph::template NodeMap<int> visited(_res_graph);
std::vector<ResEdge> cycle;
- int node_num = countNodes(graph);
+ int node_num = countNodes(_graph);
-#ifdef _DEBUG_ITER_
- int cycle_num = 0;
-#endif
- int length_bound = STARTING_LIMIT;
+ int length_bound = BF_FIRST_LIMIT;
bool optimal = false;
while (!optimal) {
- BellmanFord<ResGraph, ResCostMap> bf(res_graph, res_cost);
+ BellmanFord<ResGraph, ResidualCostMap> bf(_res_graph, _res_cost);
bf.predMap(pred);
bf.init(0);
int iter_num = 0;
bool cycle_found = false;
while (!cycle_found) {
-#ifdef _NO_BACK_STEP_
- int curr_iter_num = length_bound <= node_num ?
- length_bound - iter_num : node_num - iter_num;
-#else
int curr_iter_num = iter_num + length_bound <= node_num ?
length_bound : node_num - iter_num;
-#endif
iter_num += curr_iter_num;
int real_iter_num = curr_iter_num;
for (int i = 0; i < curr_iter_num; ++i) {
@@ -358,18 +360,18 @@
break;
} else {
// Searching for node disjoint negative cycles
- for (ResNodeIt n(res_graph); n != INVALID; ++n)
+ for (ResNodeIt n(_res_graph); n != INVALID; ++n)
visited[n] = 0;
int id = 0;
- for (ResNodeIt n(res_graph); n != INVALID; ++n) {
+ for (ResNodeIt n(_res_graph); n != INVALID; ++n) {
if (visited[n] > 0) continue;
visited[n] = ++id;
ResNode u = pred[n] == INVALID ?
- INVALID : res_graph.source(pred[n]);
+ INVALID : _res_graph.source(pred[n]);
while (u != INVALID && visited[u] == 0) {
visited[u] = id;
u = pred[u] == INVALID ?
- INVALID : res_graph.source(pred[u]);
+ INVALID : _res_graph.source(pred[u]);
}
if (u != INVALID && visited[u] == id) {
// Finding the negative cycle
@@ -377,62 +379,45 @@
cycle.clear();
ResEdge e = pred[u];
cycle.push_back(e);
- Capacity d = res_graph.rescap(e);
- while (res_graph.source(e) != u) {
- cycle.push_back(e = pred[res_graph.source(e)]);
- if (res_graph.rescap(e) < d)
- d = res_graph.rescap(e);
+ Capacity d = _res_graph.rescap(e);
+ while (_res_graph.source(e) != u) {
+ cycle.push_back(e = pred[_res_graph.source(e)]);
+ if (_res_graph.rescap(e) < d)
+ d = _res_graph.rescap(e);
}
-#ifdef _DEBUG_ITER_
- ++cycle_num;
-#endif
+
// Augmenting along the cycle
- for (int i = 0; i < cycle.size(); ++i)
- res_graph.augment(cycle[i], d);
-#ifdef _ONLY_ONE_CYCLE_
- break;
-#endif
+ for (int i = 0; i < int(cycle.size()); ++i)
+ _res_graph.augment(cycle[i], d);
}
}
}
if (!cycle_found)
- length_bound = length_bound * ALPHA_MUL / ALPHA_DIV;
+ length_bound = int(length_bound * BF_ALPHA);
}
}
-#ifdef _DEBUG_ITER_
- std::cout << "Limited cycle-canceling algorithm finished. "
- << "Found " << cycle_num << " negative cycles."
- << std::endl;
-#endif
-
// Handling non-zero lower bounds
- if (lower) {
- for (EdgeIt e(graph); e != INVALID; ++e)
- flow[e] += (*lower)[e];
+ if (_lower) {
+ for (EdgeIt e(_graph); e != INVALID; ++e)
+ _flow[e] += (*_lower)[e];
}
return true;
}
-#endif
-#ifdef MIN_MEAN_CYCLE_CANCELING
- /// \brief Executes the minimum mean cycle-canceling algorithm
- /// using \ref MinMeanCycle.
- bool start() {
+ /// \brief Executes the algorithm using \ref MinMeanCycle.
+ ///
+ /// Executes the algorithm using \ref MinMeanCycle for negative
+ /// cycle detection.
+ bool startMinMean() {
typedef Path<ResGraph> ResPath;
- MinMeanCycle<ResGraph, ResCostMap> mmc(res_graph, res_cost);
+ MinMeanCycle<ResGraph, ResidualCostMap> mmc(_res_graph, _res_cost);
ResPath cycle;
-#ifdef _DEBUG_ITER_
- int cycle_num = 0;
-#endif
mmc.cyclePath(cycle).init();
if (mmc.findMinMean()) {
while (mmc.cycleLength() < 0) {
-#ifdef _DEBUG_ITER_
- ++cycle_num;
-#endif
// Finding the cycle
mmc.findCycle();
@@ -440,13 +425,13 @@
// along the cycle
Capacity delta = 0;
for (typename ResPath::EdgeIt e(cycle); e != INVALID; ++e) {
- if (delta == 0 || res_graph.rescap(e) < delta)
- delta = res_graph.rescap(e);
+ if (delta == 0 || _res_graph.rescap(e) < delta)
+ delta = _res_graph.rescap(e);
}
// Augmenting along the cycle
for (typename ResPath::EdgeIt e(cycle); e != INVALID; ++e)
- res_graph.augment(e, delta);
+ _res_graph.augment(e, delta);
// Finding the minimum cycle mean for the modified residual
// graph
@@ -455,20 +440,13 @@
}
}
-#ifdef _DEBUG_ITER_
- std::cout << "Minimum mean cycle-canceling algorithm finished. "
- << "Found " << cycle_num << " negative cycles."
- << std::endl;
-#endif
-
// Handling non-zero lower bounds
- if (lower) {
- for (EdgeIt e(graph); e != INVALID; ++e)
- flow[e] += (*lower)[e];
+ if (_lower) {
+ for (EdgeIt e(_graph); e != INVALID; ++e)
+ _flow[e] += (*_lower)[e];
}
return true;
}
-#endif
}; //class CycleCanceling
More information about the Lemon-commits
mailing list