diff --git a/lemon/network_simplex.h b/lemon/network_simplex.h
--- a/lemon/network_simplex.h
+++ b/lemon/network_simplex.h
@@ -19,7 +19,7 @@
#ifndef LEMON_NETWORK_SIMPLEX_H
#define LEMON_NETWORK_SIMPLEX_H
-/// \ingroup min_cost_flow
+/// \ingroup min_cost_flow_algs
///
/// \file
/// \brief Network Simplex algorithm for finding a minimum cost flow.
@@ -33,7 +33,7 @@
namespace lemon {
- /// \addtogroup min_cost_flow
+ /// \addtogroup min_cost_flow_algs
/// @{
/// \brief Implementation of the primal Network Simplex algorithm
@@ -102,50 +102,16 @@
/// i.e. the direction of the inequalities in the supply/demand
/// constraints of the \ref min_cost_flow "minimum cost flow problem".
///
- /// The default supply type is \c GEQ, since this form is supported
- /// by other minimum cost flow algorithms and the \ref Circulation
- /// algorithm, as well.
- /// The \c LEQ problem type can be selected using the \ref supplyType()
- /// function.
- ///
- /// Note that the equality form is a special case of both supply types.
+ /// The default supply type is \c GEQ, the \c LEQ type can be
+ /// selected using \ref supplyType().
+ /// The equality form is a special case of both supply types.
enum SupplyType {
-
/// This option means that there are "greater or equal"
- /// supply/demand constraints in the definition, i.e. the exact
- /// formulation of the problem is the following.
- /**
- \f[ \min\sum_{uv\in A} f(uv) \cdot cost(uv) \f]
- \f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu) \geq
- sup(u) \quad \forall u\in V \f]
- \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A \f]
- */
- /// It means that the total demand must be greater or equal to the
- /// total supply (i.e. \f$\sum_{u\in V} sup(u)\f$ must be zero or
- /// negative) and all the supplies have to be carried out from
- /// the supply nodes, but there could be demands that are not
- /// satisfied.
+ /// supply/demand constraints in the definition of the problem.
GEQ,
- /// It is just an alias for the \c GEQ option.
- CARRY_SUPPLIES = GEQ,
-
/// This option means that there are "less or equal"
- /// supply/demand constraints in the definition, i.e. the exact
- /// formulation of the problem is the following.
- /**
- \f[ \min\sum_{uv\in A} f(uv) \cdot cost(uv) \f]
- \f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu) \leq
- sup(u) \quad \forall u\in V \f]
- \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A \f]
- */
- /// It means that the total demand must be less or equal to the
- /// total supply (i.e. \f$\sum_{u\in V} sup(u)\f$ must be zero or
- /// positive) and all the demands have to be satisfied, but there
- /// could be supplies that are not carried out from the supply
- /// nodes.
- LEQ,
- /// It is just an alias for the \c LEQ option.
- SATISFY_DEMANDS = LEQ
+ /// supply/demand constraints in the definition of the problem.
+ LEQ
};
/// \brief Constants for selecting the pivot rule.
@@ -215,6 +181,8 @@
const GR &_graph;
int _node_num;
int _arc_num;
+ int _all_arc_num;
+ int _search_arc_num;
// Parameters of the problem
bool _have_lower;
@@ -277,7 +245,7 @@
const IntVector &_state;
const CostVector &_pi;
int &_in_arc;
- int _arc_num;
+ int _search_arc_num;
// Pivot rule data
int _next_arc;
@@ -288,13 +256,14 @@
FirstEligiblePivotRule(NetworkSimplex &ns) :
_source(ns._source), _target(ns._target),
_cost(ns._cost), _state(ns._state), _pi(ns._pi),
- _in_arc(ns.in_arc), _arc_num(ns._arc_num), _next_arc(0)
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0)
{}
// Find next entering arc
bool findEnteringArc() {
Cost c;
- for (int e = _next_arc; e < _arc_num; ++e) {
+ for (int e = _next_arc; e < _search_arc_num; ++e) {
c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
if (c < 0) {
_in_arc = e;
@@ -328,7 +297,7 @@
const IntVector &_state;
const CostVector &_pi;
int &_in_arc;
- int _arc_num;
+ int _search_arc_num;
public:
@@ -336,13 +305,13 @@
BestEligiblePivotRule(NetworkSimplex &ns) :
_source(ns._source), _target(ns._target),
_cost(ns._cost), _state(ns._state), _pi(ns._pi),
- _in_arc(ns.in_arc), _arc_num(ns._arc_num)
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num)
{}
// Find next entering arc
bool findEnteringArc() {
Cost c, min = 0;
- for (int e = 0; e < _arc_num; ++e) {
+ for (int e = 0; e < _search_arc_num; ++e) {
c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
if (c < min) {
min = c;
@@ -367,7 +336,7 @@
const IntVector &_state;
const CostVector &_pi;
int &_in_arc;
- int _arc_num;
+ int _search_arc_num;
// Pivot rule data
int _block_size;
@@ -379,14 +348,15 @@
BlockSearchPivotRule(NetworkSimplex &ns) :
_source(ns._source), _target(ns._target),
_cost(ns._cost), _state(ns._state), _pi(ns._pi),
- _in_arc(ns.in_arc), _arc_num(ns._arc_num), _next_arc(0)
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0)
{
// The main parameters of the pivot rule
- const double BLOCK_SIZE_FACTOR = 2.0;
+ const double BLOCK_SIZE_FACTOR = 0.5;
const int MIN_BLOCK_SIZE = 10;
_block_size = std::max( int(BLOCK_SIZE_FACTOR *
- std::sqrt(double(_arc_num))),
+ std::sqrt(double(_search_arc_num))),
MIN_BLOCK_SIZE );
}
@@ -395,7 +365,7 @@
Cost c, min = 0;
int cnt = _block_size;
int e, min_arc = _next_arc;
- for (e = _next_arc; e < _arc_num; ++e) {
+ for (e = _next_arc; e < _search_arc_num; ++e) {
c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
if (c < min) {
min = c;
@@ -440,7 +410,7 @@
const IntVector &_state;
const CostVector &_pi;
int &_in_arc;
- int _arc_num;
+ int _search_arc_num;
// Pivot rule data
IntVector _candidates;
@@ -454,7 +424,8 @@
CandidateListPivotRule(NetworkSimplex &ns) :
_source(ns._source), _target(ns._target),
_cost(ns._cost), _state(ns._state), _pi(ns._pi),
- _in_arc(ns.in_arc), _arc_num(ns._arc_num), _next_arc(0)
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0)
{
// The main parameters of the pivot rule
const double LIST_LENGTH_FACTOR = 1.0;
@@ -463,7 +434,7 @@
const int MIN_MINOR_LIMIT = 3;
_list_length = std::max( int(LIST_LENGTH_FACTOR *
- std::sqrt(double(_arc_num))),
+ std::sqrt(double(_search_arc_num))),
MIN_LIST_LENGTH );
_minor_limit = std::max( int(MINOR_LIMIT_FACTOR * _list_length),
MIN_MINOR_LIMIT );
@@ -500,7 +471,7 @@
// Major iteration: build a new candidate list
min = 0;
_curr_length = 0;
- for (e = _next_arc; e < _arc_num; ++e) {
+ for (e = _next_arc; e < _search_arc_num; ++e) {
c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
if (c < 0) {
_candidates[_curr_length++] = e;
@@ -546,7 +517,7 @@
const IntVector &_state;
const CostVector &_pi;
int &_in_arc;
- int _arc_num;
+ int _search_arc_num;
// Pivot rule data
int _block_size, _head_length, _curr_length;
@@ -574,8 +545,8 @@
AlteringListPivotRule(NetworkSimplex &ns) :
_source(ns._source), _target(ns._target),
_cost(ns._cost), _state(ns._state), _pi(ns._pi),
- _in_arc(ns.in_arc), _arc_num(ns._arc_num),
- _next_arc(0), _cand_cost(ns._arc_num), _sort_func(_cand_cost)
+ _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num),
+ _next_arc(0), _cand_cost(ns._search_arc_num), _sort_func(_cand_cost)
{
// The main parameters of the pivot rule
const double BLOCK_SIZE_FACTOR = 1.5;
@@ -584,7 +555,7 @@
const int MIN_HEAD_LENGTH = 3;
_block_size = std::max( int(BLOCK_SIZE_FACTOR *
- std::sqrt(double(_arc_num))),
+ std::sqrt(double(_search_arc_num))),
MIN_BLOCK_SIZE );
_head_length = std::max( int(HEAD_LENGTH_FACTOR * _block_size),
MIN_HEAD_LENGTH );
@@ -610,7 +581,7 @@
int last_arc = 0;
int limit = _head_length;
- for (int e = _next_arc; e < _arc_num; ++e) {
+ for (int e = _next_arc; e < _search_arc_num; ++e) {
_cand_cost[e] = _state[e] *
(_cost[e] + _pi[_source[e]] - _pi[_target[e]]);
if (_cand_cost[e] < 0) {
@@ -678,17 +649,17 @@
_node_num = countNodes(_graph);
_arc_num = countArcs(_graph);
int all_node_num = _node_num + 1;
- int all_arc_num = _arc_num + _node_num;
+ int max_arc_num = _arc_num + 2 * _node_num;
- _source.resize(all_arc_num);
- _target.resize(all_arc_num);
+ _source.resize(max_arc_num);
+ _target.resize(max_arc_num);
- _lower.resize(all_arc_num);
- _upper.resize(all_arc_num);
- _cap.resize(all_arc_num);
- _cost.resize(all_arc_num);
+ _lower.resize(_arc_num);
+ _upper.resize(_arc_num);
+ _cap.resize(max_arc_num);
+ _cost.resize(max_arc_num);
_supply.resize(all_node_num);
- _flow.resize(all_arc_num);
+ _flow.resize(max_arc_num);
_pi.resize(all_node_num);
_parent.resize(all_node_num);
@@ -698,7 +669,7 @@
_rev_thread.resize(all_node_num);
_succ_num.resize(all_node_num);
_last_succ.resize(all_node_num);
- _state.resize(all_arc_num);
+ _state.resize(max_arc_num);
// Copy the graph (store the arcs in a mixed order)
int i = 0;
@@ -1069,7 +1040,7 @@
// Initialize artifical cost
Cost ART_COST;
if (std::numeric_limits::is_exact) {
- ART_COST = std::numeric_limits::max() / 4 + 1;
+ ART_COST = std::numeric_limits::max() / 2 + 1;
} else {
ART_COST = std::numeric_limits::min();
for (int i = 0; i != _arc_num; ++i) {
@@ -1093,29 +1064,121 @@
_succ_num[_root] = _node_num + 1;
_last_succ[_root] = _root - 1;
_supply[_root] = -_sum_supply;
- _pi[_root] = _sum_supply < 0 ? -ART_COST : ART_COST;
+ _pi[_root] = 0;
// Add artificial arcs and initialize the spanning tree data structure
- for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
- _parent[u] = _root;
- _pred[u] = e;
- _thread[u] = u + 1;
- _rev_thread[u + 1] = u;
- _succ_num[u] = 1;
- _last_succ[u] = u;
- _cost[e] = ART_COST;
- _cap[e] = INF;
- _state[e] = STATE_TREE;
- if (_supply[u] > 0 || (_supply[u] == 0 && _sum_supply <= 0)) {
- _flow[e] = _supply[u];
- _forward[u] = true;
- _pi[u] = -ART_COST + _pi[_root];
- } else {
- _flow[e] = -_supply[u];
- _forward[u] = false;
- _pi[u] = ART_COST + _pi[_root];
+ if (_sum_supply == 0) {
+ // EQ supply constraints
+ _search_arc_num = _arc_num;
+ _all_arc_num = _arc_num + _node_num;
+ for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
+ _parent[u] = _root;
+ _pred[u] = e;
+ _thread[u] = u + 1;
+ _rev_thread[u + 1] = u;
+ _succ_num[u] = 1;
+ _last_succ[u] = u;
+ _cap[e] = INF;
+ _state[e] = STATE_TREE;
+ if (_supply[u] >= 0) {
+ _forward[u] = true;
+ _pi[u] = 0;
+ _source[e] = u;
+ _target[e] = _root;
+ _flow[e] = _supply[u];
+ _cost[e] = 0;
+ } else {
+ _forward[u] = false;
+ _pi[u] = ART_COST;
+ _source[e] = _root;
+ _target[e] = u;
+ _flow[e] = -_supply[u];
+ _cost[e] = ART_COST;
+ }
}
}
+ else if (_sum_supply > 0) {
+ // LEQ supply constraints
+ _search_arc_num = _arc_num + _node_num;
+ int f = _arc_num + _node_num;
+ for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
+ _parent[u] = _root;
+ _thread[u] = u + 1;
+ _rev_thread[u + 1] = u;
+ _succ_num[u] = 1;
+ _last_succ[u] = u;
+ if (_supply[u] >= 0) {
+ _forward[u] = true;
+ _pi[u] = 0;
+ _pred[u] = e;
+ _source[e] = u;
+ _target[e] = _root;
+ _cap[e] = INF;
+ _flow[e] = _supply[u];
+ _cost[e] = 0;
+ _state[e] = STATE_TREE;
+ } else {
+ _forward[u] = false;
+ _pi[u] = ART_COST;
+ _pred[u] = f;
+ _source[f] = _root;
+ _target[f] = u;
+ _cap[f] = INF;
+ _flow[f] = -_supply[u];
+ _cost[f] = ART_COST;
+ _state[f] = STATE_TREE;
+ _source[e] = u;
+ _target[e] = _root;
+ _cap[e] = INF;
+ _flow[e] = 0;
+ _cost[e] = 0;
+ _state[e] = STATE_LOWER;
+ ++f;
+ }
+ }
+ _all_arc_num = f;
+ }
+ else {
+ // GEQ supply constraints
+ _search_arc_num = _arc_num + _node_num;
+ int f = _arc_num + _node_num;
+ for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
+ _parent[u] = _root;
+ _thread[u] = u + 1;
+ _rev_thread[u + 1] = u;
+ _succ_num[u] = 1;
+ _last_succ[u] = u;
+ if (_supply[u] <= 0) {
+ _forward[u] = false;
+ _pi[u] = 0;
+ _pred[u] = e;
+ _source[e] = _root;
+ _target[e] = u;
+ _cap[e] = INF;
+ _flow[e] = -_supply[u];
+ _cost[e] = 0;
+ _state[e] = STATE_TREE;
+ } else {
+ _forward[u] = true;
+ _pi[u] = -ART_COST;
+ _pred[u] = f;
+ _source[f] = u;
+ _target[f] = _root;
+ _cap[f] = INF;
+ _flow[f] = _supply[u];
+ _state[f] = STATE_TREE;
+ _cost[f] = ART_COST;
+ _source[e] = _root;
+ _target[e] = u;
+ _cap[e] = INF;
+ _flow[e] = 0;
+ _cost[e] = 0;
+ _state[e] = STATE_LOWER;
+ ++f;
+ }
+ }
+ _all_arc_num = f;
+ }
return true;
}
@@ -1374,20 +1437,8 @@
}
// Check feasibility
- if (_sum_supply < 0) {
- for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
- if (_supply[u] >= 0 && _flow[e] != 0) return INFEASIBLE;
- }
- }
- else if (_sum_supply > 0) {
- for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
- if (_supply[u] <= 0 && _flow[e] != 0) return INFEASIBLE;
- }
- }
- else {
- for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) {
- if (_flow[e] != 0) return INFEASIBLE;
- }
+ for (int e = _search_arc_num; e != _all_arc_num; ++e) {
+ if (_flow[e] != 0) return INFEASIBLE;
}
// Transform the solution and the supply map to the original form
@@ -1401,6 +1452,30 @@
}
}
}
+
+ // Shift potentials to meet the requirements of the GEQ/LEQ type
+ // optimality conditions
+ if (_sum_supply == 0) {
+ if (_stype == GEQ) {
+ Cost max_pot = std::numeric_limits::min();
+ for (int i = 0; i != _node_num; ++i) {
+ if (_pi[i] > max_pot) max_pot = _pi[i];
+ }
+ if (max_pot > 0) {
+ for (int i = 0; i != _node_num; ++i)
+ _pi[i] -= max_pot;
+ }
+ } else {
+ Cost min_pot = std::numeric_limits::max();
+ for (int i = 0; i != _node_num; ++i) {
+ if (_pi[i] < min_pot) min_pot = _pi[i];
+ }
+ if (min_pot < 0) {
+ for (int i = 0; i != _node_num; ++i)
+ _pi[i] -= min_pot;
+ }
+ }
+ }
return OPTIMAL;
}