mincost.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. """
  2. Minimum cost flow algorithms on directed connected graphs.
  3. """
  4. __all__ = ["min_cost_flow_cost", "min_cost_flow", "cost_of_flow", "max_flow_min_cost"]
  5. import networkx as nx
  6. def min_cost_flow_cost(G, demand="demand", capacity="capacity", weight="weight"):
  7. r"""Find the cost of a minimum cost flow satisfying all demands in digraph G.
  8. G is a digraph with edge costs and capacities and in which nodes
  9. have demand, i.e., they want to send or receive some amount of
  10. flow. A negative demand means that the node wants to send flow, a
  11. positive demand means that the node want to receive flow. A flow on
  12. the digraph G satisfies all demand if the net flow into each node
  13. is equal to the demand of that node.
  14. Parameters
  15. ----------
  16. G : NetworkX graph
  17. DiGraph on which a minimum cost flow satisfying all demands is
  18. to be found.
  19. demand : string
  20. Nodes of the graph G are expected to have an attribute demand
  21. that indicates how much flow a node wants to send (negative
  22. demand) or receive (positive demand). Note that the sum of the
  23. demands should be 0 otherwise the problem in not feasible. If
  24. this attribute is not present, a node is considered to have 0
  25. demand. Default value: 'demand'.
  26. capacity : string
  27. Edges of the graph G are expected to have an attribute capacity
  28. that indicates how much flow the edge can support. If this
  29. attribute is not present, the edge is considered to have
  30. infinite capacity. Default value: 'capacity'.
  31. weight : string
  32. Edges of the graph G are expected to have an attribute weight
  33. that indicates the cost incurred by sending one unit of flow on
  34. that edge. If not present, the weight is considered to be 0.
  35. Default value: 'weight'.
  36. Returns
  37. -------
  38. flowCost : integer, float
  39. Cost of a minimum cost flow satisfying all demands.
  40. Raises
  41. ------
  42. NetworkXError
  43. This exception is raised if the input graph is not directed or
  44. not connected.
  45. NetworkXUnfeasible
  46. This exception is raised in the following situations:
  47. * The sum of the demands is not zero. Then, there is no
  48. flow satisfying all demands.
  49. * There is no flow satisfying all demand.
  50. NetworkXUnbounded
  51. This exception is raised if the digraph G has a cycle of
  52. negative cost and infinite capacity. Then, the cost of a flow
  53. satisfying all demands is unbounded below.
  54. See also
  55. --------
  56. cost_of_flow, max_flow_min_cost, min_cost_flow, network_simplex
  57. Notes
  58. -----
  59. This algorithm is not guaranteed to work if edge weights or demands
  60. are floating point numbers (overflows and roundoff errors can
  61. cause problems). As a workaround you can use integer numbers by
  62. multiplying the relevant edge attributes by a convenient
  63. constant factor (eg 100).
  64. Examples
  65. --------
  66. A simple example of a min cost flow problem.
  67. >>> G = nx.DiGraph()
  68. >>> G.add_node("a", demand=-5)
  69. >>> G.add_node("d", demand=5)
  70. >>> G.add_edge("a", "b", weight=3, capacity=4)
  71. >>> G.add_edge("a", "c", weight=6, capacity=10)
  72. >>> G.add_edge("b", "d", weight=1, capacity=9)
  73. >>> G.add_edge("c", "d", weight=2, capacity=5)
  74. >>> flowCost = nx.min_cost_flow_cost(G)
  75. >>> flowCost
  76. 24
  77. """
  78. return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[0]
  79. def min_cost_flow(G, demand="demand", capacity="capacity", weight="weight"):
  80. r"""Returns a minimum cost flow satisfying all demands in digraph G.
  81. G is a digraph with edge costs and capacities and in which nodes
  82. have demand, i.e., they want to send or receive some amount of
  83. flow. A negative demand means that the node wants to send flow, a
  84. positive demand means that the node want to receive flow. A flow on
  85. the digraph G satisfies all demand if the net flow into each node
  86. is equal to the demand of that node.
  87. Parameters
  88. ----------
  89. G : NetworkX graph
  90. DiGraph on which a minimum cost flow satisfying all demands is
  91. to be found.
  92. demand : string
  93. Nodes of the graph G are expected to have an attribute demand
  94. that indicates how much flow a node wants to send (negative
  95. demand) or receive (positive demand). Note that the sum of the
  96. demands should be 0 otherwise the problem in not feasible. If
  97. this attribute is not present, a node is considered to have 0
  98. demand. Default value: 'demand'.
  99. capacity : string
  100. Edges of the graph G are expected to have an attribute capacity
  101. that indicates how much flow the edge can support. If this
  102. attribute is not present, the edge is considered to have
  103. infinite capacity. Default value: 'capacity'.
  104. weight : string
  105. Edges of the graph G are expected to have an attribute weight
  106. that indicates the cost incurred by sending one unit of flow on
  107. that edge. If not present, the weight is considered to be 0.
  108. Default value: 'weight'.
  109. Returns
  110. -------
  111. flowDict : dictionary
  112. Dictionary of dictionaries keyed by nodes such that
  113. flowDict[u][v] is the flow edge (u, v).
  114. Raises
  115. ------
  116. NetworkXError
  117. This exception is raised if the input graph is not directed or
  118. not connected.
  119. NetworkXUnfeasible
  120. This exception is raised in the following situations:
  121. * The sum of the demands is not zero. Then, there is no
  122. flow satisfying all demands.
  123. * There is no flow satisfying all demand.
  124. NetworkXUnbounded
  125. This exception is raised if the digraph G has a cycle of
  126. negative cost and infinite capacity. Then, the cost of a flow
  127. satisfying all demands is unbounded below.
  128. See also
  129. --------
  130. cost_of_flow, max_flow_min_cost, min_cost_flow_cost, network_simplex
  131. Notes
  132. -----
  133. This algorithm is not guaranteed to work if edge weights or demands
  134. are floating point numbers (overflows and roundoff errors can
  135. cause problems). As a workaround you can use integer numbers by
  136. multiplying the relevant edge attributes by a convenient
  137. constant factor (eg 100).
  138. Examples
  139. --------
  140. A simple example of a min cost flow problem.
  141. >>> G = nx.DiGraph()
  142. >>> G.add_node("a", demand=-5)
  143. >>> G.add_node("d", demand=5)
  144. >>> G.add_edge("a", "b", weight=3, capacity=4)
  145. >>> G.add_edge("a", "c", weight=6, capacity=10)
  146. >>> G.add_edge("b", "d", weight=1, capacity=9)
  147. >>> G.add_edge("c", "d", weight=2, capacity=5)
  148. >>> flowDict = nx.min_cost_flow(G)
  149. """
  150. return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[1]
  151. def cost_of_flow(G, flowDict, weight="weight"):
  152. """Compute the cost of the flow given by flowDict on graph G.
  153. Note that this function does not check for the validity of the
  154. flow flowDict. This function will fail if the graph G and the
  155. flow don't have the same edge set.
  156. Parameters
  157. ----------
  158. G : NetworkX graph
  159. DiGraph on which a minimum cost flow satisfying all demands is
  160. to be found.
  161. weight : string
  162. Edges of the graph G are expected to have an attribute weight
  163. that indicates the cost incurred by sending one unit of flow on
  164. that edge. If not present, the weight is considered to be 0.
  165. Default value: 'weight'.
  166. flowDict : dictionary
  167. Dictionary of dictionaries keyed by nodes such that
  168. flowDict[u][v] is the flow edge (u, v).
  169. Returns
  170. -------
  171. cost : Integer, float
  172. The total cost of the flow. This is given by the sum over all
  173. edges of the product of the edge's flow and the edge's weight.
  174. See also
  175. --------
  176. max_flow_min_cost, min_cost_flow, min_cost_flow_cost, network_simplex
  177. Notes
  178. -----
  179. This algorithm is not guaranteed to work if edge weights or demands
  180. are floating point numbers (overflows and roundoff errors can
  181. cause problems). As a workaround you can use integer numbers by
  182. multiplying the relevant edge attributes by a convenient
  183. constant factor (eg 100).
  184. """
  185. return sum((flowDict[u][v] * d.get(weight, 0) for u, v, d in G.edges(data=True)))
  186. def max_flow_min_cost(G, s, t, capacity="capacity", weight="weight"):
  187. """Returns a maximum (s, t)-flow of minimum cost.
  188. G is a digraph with edge costs and capacities. There is a source
  189. node s and a sink node t. This function finds a maximum flow from
  190. s to t whose total cost is minimized.
  191. Parameters
  192. ----------
  193. G : NetworkX graph
  194. DiGraph on which a minimum cost flow satisfying all demands is
  195. to be found.
  196. s: node label
  197. Source of the flow.
  198. t: node label
  199. Destination of the flow.
  200. capacity: string
  201. Edges of the graph G are expected to have an attribute capacity
  202. that indicates how much flow the edge can support. If this
  203. attribute is not present, the edge is considered to have
  204. infinite capacity. Default value: 'capacity'.
  205. weight: string
  206. Edges of the graph G are expected to have an attribute weight
  207. that indicates the cost incurred by sending one unit of flow on
  208. that edge. If not present, the weight is considered to be 0.
  209. Default value: 'weight'.
  210. Returns
  211. -------
  212. flowDict: dictionary
  213. Dictionary of dictionaries keyed by nodes such that
  214. flowDict[u][v] is the flow edge (u, v).
  215. Raises
  216. ------
  217. NetworkXError
  218. This exception is raised if the input graph is not directed or
  219. not connected.
  220. NetworkXUnbounded
  221. This exception is raised if there is an infinite capacity path
  222. from s to t in G. In this case there is no maximum flow. This
  223. exception is also raised if the digraph G has a cycle of
  224. negative cost and infinite capacity. Then, the cost of a flow
  225. is unbounded below.
  226. See also
  227. --------
  228. cost_of_flow, min_cost_flow, min_cost_flow_cost, network_simplex
  229. Notes
  230. -----
  231. This algorithm is not guaranteed to work if edge weights or demands
  232. are floating point numbers (overflows and roundoff errors can
  233. cause problems). As a workaround you can use integer numbers by
  234. multiplying the relevant edge attributes by a convenient
  235. constant factor (eg 100).
  236. Examples
  237. --------
  238. >>> G = nx.DiGraph()
  239. >>> G.add_edges_from(
  240. ... [
  241. ... (1, 2, {"capacity": 12, "weight": 4}),
  242. ... (1, 3, {"capacity": 20, "weight": 6}),
  243. ... (2, 3, {"capacity": 6, "weight": -3}),
  244. ... (2, 6, {"capacity": 14, "weight": 1}),
  245. ... (3, 4, {"weight": 9}),
  246. ... (3, 5, {"capacity": 10, "weight": 5}),
  247. ... (4, 2, {"capacity": 19, "weight": 13}),
  248. ... (4, 5, {"capacity": 4, "weight": 0}),
  249. ... (5, 7, {"capacity": 28, "weight": 2}),
  250. ... (6, 5, {"capacity": 11, "weight": 1}),
  251. ... (6, 7, {"weight": 8}),
  252. ... (7, 4, {"capacity": 6, "weight": 6}),
  253. ... ]
  254. ... )
  255. >>> mincostFlow = nx.max_flow_min_cost(G, 1, 7)
  256. >>> mincost = nx.cost_of_flow(G, mincostFlow)
  257. >>> mincost
  258. 373
  259. >>> from networkx.algorithms.flow import maximum_flow
  260. >>> maxFlow = maximum_flow(G, 1, 7)[1]
  261. >>> nx.cost_of_flow(G, maxFlow) >= mincost
  262. True
  263. >>> mincostFlowValue = sum((mincostFlow[u][7] for u in G.predecessors(7))) - sum(
  264. ... (mincostFlow[7][v] for v in G.successors(7))
  265. ... )
  266. >>> mincostFlowValue == nx.maximum_flow_value(G, 1, 7)
  267. True
  268. """
  269. maxFlow = nx.maximum_flow_value(G, s, t, capacity=capacity)
  270. H = nx.DiGraph(G)
  271. H.add_node(s, demand=-maxFlow)
  272. H.add_node(t, demand=maxFlow)
  273. return min_cost_flow(H, capacity=capacity, weight=weight)