Ticket #219: ns-geq-cf49ce98b6a4.patch

File ns-geq-cf49ce98b6a4.patch, 20.0 KB (added by Peter Kovacs, 10 years ago)
• doc/groups.dox

# HG changeset patch
# User Peter Kovacs <kpeter@inf.elte.hu>
# Date 1238030755 -3600
# Node ID cf49ce98b6a4e25e6dfb263baf306d76a837324e
# Parent  c7d160f73d52e2d3f1ab1236cb0b440daf5f7a85
Support <= supply constraints in NetworkSimplex (#219 and #234)

The same inequality constraints are supported as by Circulation.
The documentation of the modules and the classes NetworkSimplex,
Circulation are also improved and extended with important notes and
explanations.

diff --git a/doc/groups.dox b/doc/groups.dox
 a The \e maximum \e flow \e problem is to find a flow of maximum value between a single source and a single target. Formally, there is a \f$G=(V,A)\f$ digraph, a \f$cap:A\rightarrow\mathbf{R}^+_0\f$ capacity function and digraph, a \f$cap: A\rightarrow\mathbf{R}^+_0\f$ capacity function and \f$s, t \in V\f$ source and target nodes. A maximum flow is an \f$f:A\rightarrow\mathbf{R}^+_0\f$ solution of the A maximum flow is an \f$f: A\rightarrow\mathbf{R}^+_0\f$ solution of the following optimization problem. \f[ \max\sum_{a\in\delta_{out}(s)}f(a) - \sum_{a\in\delta_{in}(s)}f(a) \f] \f[ \sum_{a\in\delta_{out}(v)} f(a) = \sum_{a\in\delta_{in}(v)} f(a) \qquad \forall v\in V\setminus\{s,t\} \f] \f[ 0 \leq f(a) \leq cap(a) \qquad \forall a\in A \f] \f[ \max\sum_{sv\in A} f(sv) - \sum_{vs\in A} f(vs) \f] \f[ \sum_{uv\in A} f(uv) = \sum_{vu\in A} f(vu) \quad \forall u\in V\setminus\{s,t\} \f] \f[ 0 \leq f(uv) \leq cap(uv) \quad \forall uv\in A \f] LEMON contains several algorithms for solving maximum flow problems: - \ref EdmondsKarp Edmonds-Karp algorithm. The \e minimum \e cost \e flow \e problem is to find a feasible flow of minimum total cost from a set of supply nodes to a set of demand nodes in a network with capacity constraints and arc costs. in a network with capacity constraints (lower and upper bounds) and arc costs. Formally, let \f$G=(V,A)\f$ be a digraph, \f$lower, upper: A\rightarrow\mathbf{Z}^+_0\f$ denote the lower and upper bounds for the flow values on the arcs, upper bounds for the flow values on the arcs, for which \f$0 \leq lower(uv) \leq upper(uv)\f$ holds for all \f$uv\in A\f$. \f$cost: A\rightarrow\mathbf{Z}^+_0\f$ denotes the cost per unit flow on the arcs, and \f$supply: V\rightarrow\mathbf{Z}\f$ denotes the supply/demand values of the nodes. A minimum cost flow is an \f$f:A\rightarrow\mathbf{R}^+_0\f$ solution of the following optimization problem. on the arcs, and \f$sup: V\rightarrow\mathbf{Z}\f$ denotes the signed supply values of the nodes. If \f$sup(u)>0\f$, then \f$u\f$ is a supply node with \f$sup(u)\f$ supply, if \f$sup(u)<0\f$, then \f$u\f$ is a demand node with \f$-sup(u)\f$ demand. A minimum cost flow is an \f$f: A\rightarrow\mathbf{Z}^+_0\f$ solution of the following optimization problem. \f[ \min\sum_{a\in A} f(a) cost(a) \f] \f[ \sum_{a\in\delta_{out}(v)} f(a) - \sum_{a\in\delta_{in}(v)} f(a) = supply(v) \qquad \forall v\in V \f] \f[ lower(a) \leq f(a) \leq upper(a) \qquad \forall a\in A \f] \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) = sup(u) \quad \forall u\in V \f] \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A \f] LEMON contains several algorithms for solving minimum cost flow problems: - \ref CycleCanceling Cycle-canceling algorithms. - \ref CapacityScaling Successive shortest path algorithm with optional Note that \f$\sum_{u\in V} sup(u)\f$ must be zero in order to have a feasible solution. NetworkSimplex, which provides the most efficient solution method, supports a more general form of the problem, in which the supply/demand constraints (mass balance constraints) are inequalities (just like the \ref Circulation "network circulation problem"). A feasible solution for the minimum cost flow problem can be found using \ref Circulation. LEMON contains several algorithms for solving minimum cost flow problems. - \ref CycleCanceling Cycle-Canceling algorithms. - \ref CancelAndTighten The Cancel and Tighten algorithm. - \ref CapacityScaling Successive Shortest %Path algorithm with optional capacity scaling. - \ref CostScaling Push-relabel and augment-relabel algorithms based on - \ref CostScaling Push-Relabel and Augment-Relabel algorithms based on cost scaling. - \ref NetworkSimplex Primal network simplex algorithm with various - \ref NetworkSimplex Primal Network Simplex algorithm with various pivot strategies. In general NetworkSimplex is the most efficient implementation, but in special cases other algorithms could be faster. For example, if the capacities are very small, CapacityScaling is usually the fastest algorithm (without effective scaling). */ /**
• lemon/circulation.h

diff --git a/lemon/circulation.h b/lemon/circulation.h
 a ///\ingroup max_flow ///\file ///\brief Push-relabel algorithm for finding a feasible circulation. ///\brief Push-relabel algorithm for the network circulation problem. /// namespace lemon { The exact formulation of this problem is the following. Let \f$G=(V,A)\f$ be a digraph, \f$lower, upper: A\rightarrow\mathbf{R}^+_0\f$, \f$delta: V\rightarrow\mathbf{R}\f$. Find a feasible circulation \f$lower, upper: A\rightarrow\mathbf{R}^+_0\f$ denote the lower and upper bounds for the flow values on the arcs, for which \f$0 \leq lower(uv) \leq upper(uv)\f$ holds for all \f$uv\in A\f$, and \f$delta: V\rightarrow\mathbf{R}\f$ denotes signed lower bounds for the actual supply of the nodes. Find a feasible circulation \f$f: A\rightarrow\mathbf{R}^+_0\f$ so that \f[ \sum_{a\in\delta_{out}(v)} f(a) - \sum_{a\in\delta_{in}(v)} f(a) \geq delta(v) \quad \forall v\in V, \f] \f[ lower(a)\leq f(a) \leq upper(a) \quad \forall a\in A. \f] \note \f$delta(v)\f$ specifies a lower bound for the supply of node \f$v\f$. It can be either positive or negative, however note that \f$\sum_{v\in V}delta(v)\f$ should be zero or negative in order to have a feasible solution. \note A special case of this problem is when \f$\sum_{v\in V}delta(v) = 0\f$. Then the supply of each node \f$v\f$ will be \e equal \e to \f$delta(v)\f$, if a circulation can be found. Thus a feasible solution for the \ref min_cost_flow "minimum cost flow" problem can be calculated in this way. \f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu) \geq delta(u) \quad \forall u\in V, \f] \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A. \f] Note that \f$\sum_{u\in V} delta(u)\f$ must be zero or negative in order to have a feasible solution (since the sum of the expressions on the left side of the inequalities are zero). A special case of this problem is when the sum of the supply values (\f$\sum_{u\in V} delta(u)\f$) is zero. Then all the inequalities will be equality, i.e. the supply of each node \f$u\f$ will be \e equal \e to \f$delta(u)\f$ if a feasible flow can be found. Thus a feasible solution for the \ref min_cost_flow "minimum cost flow problem" can be calculated with this algorithm. \note If you need the opposite inequality in the supply/demand constraints (i.e. the total supply is greater than the total demand), then you could easily transform the problem to this form by reversing the direction of the arcs and taking the negative of the supply values (e.g. using \ref ReverseDigraph and \ref NegMap adaptors). \tparam GR The type of the digraph the algorithm runs on. \tparam LM The type of the lower bound capacity map. The default
• lemon/network_simplex.h

diff --git a/lemon/network_simplex.h b/lemon/network_simplex.h
 a #include #include #include namespace lemon { /// \ref NetworkSimplex implements the primal Network Simplex algorithm /// for finding a \ref min_cost_flow "minimum cost flow". /// This algorithm is a specialized version of the linear programming /// simplex method directly for the minimum cost flow problem. /// It is one of the most efficient solution methods. /// simplex method directly for the minimum cost flow problem, /// and it is one of the most efficient solution methods. /// /// In general this class is the fastest implementation available /// in LEMON for the minimum cost flow problem. /// /// In fact, this algorithm supports a more general form of the /// \ref min_cost_flow "minimum cost flow problem", in which the /// supply/demand constraints are inequalities, just like the /// \ref Circulation "network circulation problem". /// The exact formulation of this problem is the following /// (using the same notations as in the minimum cost flow problem). /** \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] */ /// In this form \f$sup(u)\f$ specifies a lower bound for the actual /// supply of node \f$u\f$. /// It can be either positive or negative, however note that /// \f$\sum_{u\in V} sup(u)\f$ must be zero or negative in order to /// have a feasible solution (since the sum of the expressions on the /// left side of the inequalities are zero). /// /// A special case of this problem is when the sum of the supply /// values (\f$\sum_{u\in V} sup(u)\f$) is zero. /// Then all the inequalities will be equality, i.e. the supply of each /// node \f$u\f$ will be \e equal \e to \f$sup(u)\f$ if a feasible flow /// can be found. /// Thus this special case is exactly the same as the \ref min_cost_flow /// "minimum cost flow problem". /// /// \note If you need the opposite inequality in the supply/demand /// constraints (i.e. the total supply is greater than the total demand), /// then you could easily transform the problem to this form by reversing /// the direction of the arcs and taking the negative of the supply values /// (e.g. using \ref ReverseDigraph and \ref NegMap adaptors). /// /// \tparam GR The digraph type the algorithm runs on. /// \tparam V The value type used in the algorithm. /// By default it is \c int. // Parameters of the problem ValueArcMap *_plower; ValueArcMap *_pupper; ValueArcMap *_pcap; ValueArcMap *_pcost; ValueNodeMap *_psupply; bool _pstsup; /// \param graph The digraph the algorithm runs on. NetworkSimplex(const GR& graph) : _graph(graph), _plower(NULL), _pupper(NULL), _pcost(NULL), _plower(NULL), _pcap(NULL), _pcost(NULL), _psupply(NULL), _pstsup(false), _flow_map(NULL), _potential_map(NULL), _local_flow(false), _local_potential(false), /// \return (*this) template NetworkSimplex& upperMap(const UPPER& map) { delete _pupper; _pupper = new ValueArcMap(_graph); delete _pcap; _pcap = new ValueArcMap(_graph); for (ArcIt a(_graph); a != INVALID; ++a) { (*_pupper)[a] = map[a]; (*_pcap)[a] = map[a]; } return *this; } /// \return (*this) NetworkSimplex& reset() { delete _plower; delete _pupper; delete _pcap; delete _pcost; delete _psupply; _plower = NULL; _pupper = NULL; _pcap = NULL; _pcost = NULL; _psupply = NULL; _pstsup = false; // Initialize node related data bool valid_supply = true; if (!_pstsup && !_psupply) { Value total_supply = 0; if (!_psupply && !_pstsup) { _pstsup = true; _psource = _ptarget = NodeIt(_graph); _pstflow = 0; } if (_psupply) { Value sum = 0; int i = 0; for (NodeIt n(_graph); n != INVALID; ++n, ++i) { _node_id[n] = i; _supply[i] = (*_psupply)[n]; sum += _supply[i]; total_supply += _supply[i]; } valid_supply = (sum == 0); valid_supply = (total_supply <= 0); } else { int i = 0; for (NodeIt n(_graph); n != INVALID; ++n, ++i) { _supply[i] = 0; } _supply[_node_id[_psource]] =  _pstflow; _supply[_node_id[_ptarget]]   = -_pstflow; _supply[_node_id[_ptarget]] = -_pstflow; } if (!valid_supply) return false; const Value max_cap = std::numeric_limits::max(); const Value max_cost = std::numeric_limits::max() / 4; // Run Circulation to check if a feasible solution exists typedef ConstMap ConstArcMap; ValueNodeMap *csup = NULL; bool local_csup = false; if (_psupply) { csup = _psupply; } else { csup = new ValueNodeMap(_graph, 0); (*csup)[_psource] =  _pstflow; (*csup)[_ptarget] = -_pstflow; local_csup = true; } bool circ_result = false; if (_plower) { if (_pcap) { Circulation circ(_graph, *_plower, *_pcap, *csup); circ_result = circ.run(); } else { Circulation circ(_graph, *_plower, ConstArcMap(max_cap), *csup); circ_result = circ.run(); } } else { if (_pcap) { Circulation circ(_graph, ConstArcMap(0), *_pcap, *csup); circ_result = circ.run(); } else { Circulation circ(_graph, ConstArcMap(0), ConstArcMap(max_cap), *csup); circ_result = circ.run(); } } if (local_csup) delete csup; if (!circ_result) return false; // Set data for the artificial root node _root = _node_num; _parent[_root] = -1; _rev_thread[0] = _root; _succ_num[_root] = all_node_num; _last_succ[_root] = _root - 1; _supply[_root] = 0; _supply[_root] = -total_supply; _pi[_root] = 0; // Store the arcs in a mixed order } // Initialize arc maps if (_pupper && _pcost) { if (_pcap && _pcost) { for (int i = 0; i != _arc_num; ++i) { Arc e = _arc_ref[i]; _source[i] = _node_id[_graph.source(e)]; _target[i] = _node_id[_graph.target(e)]; _cap[i] = (*_pupper)[e]; _cap[i] = (*_pcap)[e]; _cost[i] = (*_pcost)[e]; _flow[i] = 0; _state[i] = STATE_LOWER; _flow[i] = 0; _state[i] = STATE_LOWER; } if (_pupper) { if (_pcap) { for (int i = 0; i != _arc_num; ++i) _cap[i] = (*_pupper)[_arc_ref[i]]; _cap[i] = (*_pcap)[_arc_ref[i]]; } else { Value val = std::numeric_limits::max(); Value val = max_cap; for (int i = 0; i != _arc_num; ++i) _cap[i] = val; } } // Add artificial arcs and initialize the spanning tree data structure Value max_cap = std::numeric_limits::max(); Value max_cost = std::numeric_limits::max() / 4; for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { _thread[u] = u + 1; _rev_thread[u + 1] = u; _cost[e] = max_cost; _cap[e] = max_cap; _state[e] = STATE_TREE; if (_supply[u] >= 0) { if (_supply[u] > 0 || (_supply[u] == 0 && total_supply == 0)) { _flow[e] = _supply[u]; _forward[u] = true; _pi[u] = -max_cost; } } // Check if the flow amount equals zero on all the artificial arcs for (int e = _arc_num; e != _arc_num + _node_num; ++e) { if (_flow[e] > 0) return false; } // Copy flow values to _flow_map if (_plower) { for (int i = 0; i != _arc_num; ++i) {
• test/min_cost_flow_test.cc

diff --git a/test/min_cost_flow_test.cc b/test/min_cost_flow_test.cc
 a char test_lgf[] = "@nodes\n" "label  sup1 sup2 sup3\n" "    1    20   27    0\n" "    2    -4    0    0\n" "    3     0    0    0\n" "    4     0    0    0\n" "    5     9    0    0\n" "    6    -6    0    0\n" "    7     0    0    0\n" "    8     0    0    0\n" "    9     3    0    0\n" "   10    -2    0    0\n" "   11     0    0    0\n" "   12   -20  -27    0\n" "label  sup1 sup2 sup3 sup4\n" "    1    20   27    0   20\n" "    2    -4    0    0   -8\n" "    3     0    0    0    0\n" "    4     0    0    0    0\n" "    5     9    0    0    6\n" "    6    -6    0    0   -5\n" "    7     0    0    0    0\n" "    8     0    0    0    0\n" "    9     3    0    0    0\n" "   10    -2    0    0   -7\n" "   11     0    0    0  -10\n" "   12   -20  -27    0  -30\n" "\n" "@arcs\n" "       cost  cap low1 low2\n" template < typename GR, typename LM, typename UM, typename SM, typename FM > bool checkFlow( const GR& gr, const LM& lower, const UM& upper, const SM& supply, const FM& flow ) const SM& supply, const FM& flow, bool geq = false ) { TEMPLATE_DIGRAPH_TYPEDEFS(GR); sum += flow[e]; for (InArcIt e(gr, n); e != INVALID; ++e) sum -= flow[e]; if (sum != supply[n]) return false; if ( (!geq && sum != supply[n]) || (geq && sum < supply[n]) ) return false; } return true; const GR& gr, const LM& lower, const UM& upper, const CM& cost, const SM& supply, bool result, typename CM::Value total, const std::string &test_id = "" ) const std::string &test_id = "", bool geq = false ) { check(mcf_result == result, "Wrong result " + test_id); if (result) { check(checkFlow(gr, lower, upper, supply, mcf.flowMap()), check(checkFlow(gr, lower, upper, supply, mcf.flowMap(), geq), "The flow is not feasible " + test_id); check(mcf.totalCost() == total, "The flow is not optimal " + test_id); check(checkPotential(gr, lower, upper, cost, mcf.flowMap(), // Read the test digraph Digraph gr; Digraph::ArcMap c(gr), l1(gr), l2(gr), u(gr); Digraph::NodeMap s1(gr), s2(gr), s3(gr); Digraph::NodeMap s1(gr), s2(gr), s3(gr), s4(gr); ConstMap cc(1), cu(std::numeric_limits::max()); Node v, w; .nodeMap("sup1", s1) .nodeMap("sup2", s2) .nodeMap("sup3", s3) .nodeMap("sup4", s4) .node("source", v) .node("target", w) .run(); { NetworkSimplex mcf(gr); // Check the equality form mcf.upperMap(u).costMap(c); checkMcf(mcf, mcf.supplyMap(s1).run(), gr, l1, u, c, s1, true,  5240, "#A1"); gr, l1, cu, cc, s3, true,   0, "#A7"); checkMcf(mcf, mcf.boundMaps(l2, u).run(), gr, l2, u, cc, s3, false,   0, "#A8"); // Check the inequality form mcf.reset().upperMap(u).costMap(c).supplyMap(s4); checkMcf(mcf, mcf.run(), gr, l1, u, c, s4, true,  3530, "#A9", true); checkMcf(mcf, mcf.lowerMap(l2).run(), gr, l2, u, c, s4, true,  4540, "#A10", true); } // B. Test NetworkSimplex with each pivot rule