mincost.py 13 KB

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