Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/networkx/algorithms/flow/mincost.py: 58%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

19 statements  

1""" 

2Minimum cost flow algorithms on directed connected graphs. 

3""" 

4 

5__all__ = ["min_cost_flow_cost", "min_cost_flow", "cost_of_flow", "max_flow_min_cost"] 

6 

7import networkx as nx 

8 

9 

10@nx._dispatchable( 

11 node_attrs="demand", edge_attrs={"capacity": float("inf"), "weight": 0} 

12) 

13def min_cost_flow_cost(G, demand="demand", capacity="capacity", weight="weight"): 

14 r"""Find the cost of a minimum cost flow satisfying all demands in digraph G. 

15 

16 G is a digraph with edge costs and capacities and in which nodes 

17 have demand, i.e., they want to send or receive some amount of 

18 flow. A negative demand means that the node wants to send flow, a 

19 positive demand means that the node want to receive flow. A flow on 

20 the digraph G satisfies all demand if the net flow into each node 

21 is equal to the demand of that node. 

22 

23 Parameters 

24 ---------- 

25 G : NetworkX graph 

26 DiGraph on which a minimum cost flow satisfying all demands is 

27 to be found. 

28 

29 demand : string 

30 Nodes of the graph G are expected to have an attribute demand 

31 that indicates how much flow a node wants to send (negative 

32 demand) or receive (positive demand). Note that the sum of the 

33 demands should be 0 otherwise the problem in not feasible. If 

34 this attribute is not present, a node is considered to have 0 

35 demand. Default value: 'demand'. 

36 

37 capacity : string 

38 Edges of the graph G are expected to have an attribute capacity 

39 that indicates how much flow the edge can support. If this 

40 attribute is not present, the edge is considered to have 

41 infinite capacity. Default value: 'capacity'. 

42 

43 weight : string 

44 Edges of the graph G are expected to have an attribute weight 

45 that indicates the cost incurred by sending one unit of flow on 

46 that edge. If not present, the weight is considered to be 0. 

47 Default value: 'weight'. 

48 

49 Returns 

50 ------- 

51 flowCost : integer, float 

52 Cost of a minimum cost flow satisfying all demands. 

53 

54 Raises 

55 ------ 

56 NetworkXError 

57 This exception is raised if the input graph is not directed or 

58 not connected. 

59 

60 NetworkXUnfeasible 

61 This exception is raised in the following situations: 

62 

63 * The sum of the demands is not zero. Then, there is no 

64 flow satisfying all demands. 

65 * There is no flow satisfying all demand. 

66 

67 NetworkXUnbounded 

68 This exception is raised if the digraph G has a cycle of 

69 negative cost and infinite capacity. Then, the cost of a flow 

70 satisfying all demands is unbounded below. 

71 

72 See also 

73 -------- 

74 cost_of_flow, max_flow_min_cost, min_cost_flow, network_simplex 

75 

76 Notes 

77 ----- 

78 This algorithm is not guaranteed to work if edge weights or demands 

79 are floating point numbers (overflows and roundoff errors can 

80 cause problems). As a workaround you can use integer numbers by 

81 multiplying the relevant edge attributes by a convenient 

82 constant factor (eg 100). 

83 

84 Examples 

85 -------- 

86 A simple example of a min cost flow problem. 

87 

88 >>> G = nx.DiGraph() 

89 >>> G.add_node("a", demand=-5) 

90 >>> G.add_node("d", demand=5) 

91 >>> G.add_edge("a", "b", weight=3, capacity=4) 

92 >>> G.add_edge("a", "c", weight=6, capacity=10) 

93 >>> G.add_edge("b", "d", weight=1, capacity=9) 

94 >>> G.add_edge("c", "d", weight=2, capacity=5) 

95 >>> flowCost = nx.min_cost_flow_cost(G) 

96 >>> flowCost 

97 24 

98 """ 

99 return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[0] 

100 

101 

102@nx._dispatchable( 

103 node_attrs="demand", edge_attrs={"capacity": float("inf"), "weight": 0} 

104) 

105def min_cost_flow(G, demand="demand", capacity="capacity", weight="weight"): 

106 r"""Returns a minimum cost flow satisfying all demands in digraph G. 

107 

108 G is a digraph with edge costs and capacities and in which nodes 

109 have demand, i.e., they want to send or receive some amount of 

110 flow. A negative demand means that the node wants to send flow, a 

111 positive demand means that the node want to receive flow. A flow on 

112 the digraph G satisfies all demand if the net flow into each node 

113 is equal to the demand of that node. 

114 

115 Parameters 

116 ---------- 

117 G : NetworkX graph 

118 DiGraph on which a minimum cost flow satisfying all demands is 

119 to be found. 

120 

121 demand : string 

122 Nodes of the graph G are expected to have an attribute demand 

123 that indicates how much flow a node wants to send (negative 

124 demand) or receive (positive demand). Note that the sum of the 

125 demands should be 0 otherwise the problem in not feasible. If 

126 this attribute is not present, a node is considered to have 0 

127 demand. Default value: 'demand'. 

128 

129 capacity : string 

130 Edges of the graph G are expected to have an attribute capacity 

131 that indicates how much flow the edge can support. If this 

132 attribute is not present, the edge is considered to have 

133 infinite capacity. Default value: 'capacity'. 

134 

135 weight : string 

136 Edges of the graph G are expected to have an attribute weight 

137 that indicates the cost incurred by sending one unit of flow on 

138 that edge. If not present, the weight is considered to be 0. 

139 Default value: 'weight'. 

140 

141 Returns 

142 ------- 

143 flowDict : dictionary 

144 Dictionary of dictionaries keyed by nodes such that 

145 flowDict[u][v] is the flow edge (u, v). 

146 

147 Raises 

148 ------ 

149 NetworkXError 

150 This exception is raised if the input graph is not directed or 

151 not connected. 

152 

153 NetworkXUnfeasible 

154 This exception is raised in the following situations: 

155 

156 * The sum of the demands is not zero. Then, there is no 

157 flow satisfying all demands. 

158 * There is no flow satisfying all demand. 

159 

160 NetworkXUnbounded 

161 This exception is raised if the digraph G has a cycle of 

162 negative cost and infinite capacity. Then, the cost of a flow 

163 satisfying all demands is unbounded below. 

164 

165 See also 

166 -------- 

167 cost_of_flow, max_flow_min_cost, min_cost_flow_cost, network_simplex 

168 

169 Notes 

170 ----- 

171 This algorithm is not guaranteed to work if edge weights or demands 

172 are floating point numbers (overflows and roundoff errors can 

173 cause problems). As a workaround you can use integer numbers by 

174 multiplying the relevant edge attributes by a convenient 

175 constant factor (eg 100). 

176 

177 Examples 

178 -------- 

179 A simple example of a min cost flow problem. 

180 

181 >>> G = nx.DiGraph() 

182 >>> G.add_node("a", demand=-5) 

183 >>> G.add_node("d", demand=5) 

184 >>> G.add_edge("a", "b", weight=3, capacity=4) 

185 >>> G.add_edge("a", "c", weight=6, capacity=10) 

186 >>> G.add_edge("b", "d", weight=1, capacity=9) 

187 >>> G.add_edge("c", "d", weight=2, capacity=5) 

188 >>> flowDict = nx.min_cost_flow(G) 

189 >>> flowDict 

190 {'a': {'b': 4, 'c': 1}, 'd': {}, 'b': {'d': 4}, 'c': {'d': 1}} 

191 """ 

192 return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[1] 

193 

194 

195@nx._dispatchable(edge_attrs={"weight": 0}) 

196def cost_of_flow(G, flowDict, weight="weight"): 

197 """Compute the cost of the flow given by flowDict on graph G. 

198 

199 Note that this function does not check for the validity of the 

200 flow flowDict. This function will fail if the graph G and the 

201 flow don't have the same edge set. 

202 

203 Parameters 

204 ---------- 

205 G : NetworkX graph 

206 DiGraph on which a minimum cost flow satisfying all demands is 

207 to be found. 

208 

209 weight : string 

210 Edges of the graph G are expected to have an attribute weight 

211 that indicates the cost incurred by sending one unit of flow on 

212 that edge. If not present, the weight is considered to be 0. 

213 Default value: 'weight'. 

214 

215 flowDict : dictionary 

216 Dictionary of dictionaries keyed by nodes such that 

217 flowDict[u][v] is the flow edge (u, v). 

218 

219 Returns 

220 ------- 

221 cost : Integer, float 

222 The total cost of the flow. This is given by the sum over all 

223 edges of the product of the edge's flow and the edge's weight. 

224 

225 See also 

226 -------- 

227 max_flow_min_cost, min_cost_flow, min_cost_flow_cost, network_simplex 

228 

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 

237 Examples 

238 -------- 

239 >>> G = nx.DiGraph() 

240 >>> G.add_node("a", demand=-5) 

241 >>> G.add_node("d", demand=5) 

242 >>> G.add_edge("a", "b", weight=3, capacity=4) 

243 >>> G.add_edge("a", "c", weight=6, capacity=10) 

244 >>> G.add_edge("b", "d", weight=1, capacity=9) 

245 >>> G.add_edge("c", "d", weight=2, capacity=5) 

246 >>> flowDict = nx.min_cost_flow(G) 

247 >>> flowDict 

248 {'a': {'b': 4, 'c': 1}, 'd': {}, 'b': {'d': 4}, 'c': {'d': 1}} 

249 >>> nx.cost_of_flow(G, flowDict) 

250 24 

251 """ 

252 return sum((flowDict[u][v] * d.get(weight, 0) for u, v, d in G.edges(data=True))) 

253 

254 

255@nx._dispatchable(edge_attrs={"capacity": float("inf"), "weight": 0}) 

256def max_flow_min_cost(G, s, t, capacity="capacity", weight="weight"): 

257 """Returns a maximum (s, t)-flow of minimum cost. 

258 

259 G is a digraph with edge costs and capacities. There is a source 

260 node s and a sink node t. This function finds a maximum flow from 

261 s to t whose total cost is minimized. 

262 

263 Parameters 

264 ---------- 

265 G : NetworkX graph 

266 DiGraph on which a minimum cost flow satisfying all demands is 

267 to be found. 

268 

269 s: node label 

270 Source of the flow. 

271 

272 t: node label 

273 Destination of the flow. 

274 

275 capacity: string 

276 Edges of the graph G are expected to have an attribute capacity 

277 that indicates how much flow the edge can support. If this 

278 attribute is not present, the edge is considered to have 

279 infinite capacity. Default value: 'capacity'. 

280 

281 weight: string 

282 Edges of the graph G are expected to have an attribute weight 

283 that indicates the cost incurred by sending one unit of flow on 

284 that edge. If not present, the weight is considered to be 0. 

285 Default value: 'weight'. 

286 

287 Returns 

288 ------- 

289 flowDict: dictionary 

290 Dictionary of dictionaries keyed by nodes such that 

291 flowDict[u][v] is the flow edge (u, v). 

292 

293 Raises 

294 ------ 

295 NetworkXError 

296 This exception is raised if the input graph is not directed or 

297 not connected. 

298 

299 NetworkXUnbounded 

300 This exception is raised if there is an infinite capacity path 

301 from s to t in G. In this case there is no maximum flow. This 

302 exception is also raised if the digraph G has a cycle of 

303 negative cost and infinite capacity. Then, the cost of a flow 

304 is unbounded below. 

305 

306 See also 

307 -------- 

308 cost_of_flow, min_cost_flow, min_cost_flow_cost, network_simplex 

309 

310 Notes 

311 ----- 

312 This algorithm is not guaranteed to work if edge weights or demands 

313 are floating point numbers (overflows and roundoff errors can 

314 cause problems). As a workaround you can use integer numbers by 

315 multiplying the relevant edge attributes by a convenient 

316 constant factor (eg 100). 

317 

318 Examples 

319 -------- 

320 >>> G = nx.DiGraph() 

321 >>> G.add_edges_from( 

322 ... [ 

323 ... (1, 2, {"capacity": 12, "weight": 4}), 

324 ... (1, 3, {"capacity": 20, "weight": 6}), 

325 ... (2, 3, {"capacity": 6, "weight": -3}), 

326 ... (2, 6, {"capacity": 14, "weight": 1}), 

327 ... (3, 4, {"weight": 9}), 

328 ... (3, 5, {"capacity": 10, "weight": 5}), 

329 ... (4, 2, {"capacity": 19, "weight": 13}), 

330 ... (4, 5, {"capacity": 4, "weight": 0}), 

331 ... (5, 7, {"capacity": 28, "weight": 2}), 

332 ... (6, 5, {"capacity": 11, "weight": 1}), 

333 ... (6, 7, {"weight": 8}), 

334 ... (7, 4, {"capacity": 6, "weight": 6}), 

335 ... ] 

336 ... ) 

337 >>> mincostFlow = nx.max_flow_min_cost(G, 1, 7) 

338 >>> mincost = nx.cost_of_flow(G, mincostFlow) 

339 >>> mincost 

340 373 

341 >>> from networkx.algorithms.flow import maximum_flow 

342 >>> maxFlow = maximum_flow(G, 1, 7)[1] 

343 >>> nx.cost_of_flow(G, maxFlow) >= mincost 

344 True 

345 >>> mincostFlowValue = sum((mincostFlow[u][7] for u in G.predecessors(7))) - sum( 

346 ... (mincostFlow[7][v] for v in G.successors(7)) 

347 ... ) 

348 >>> mincostFlowValue == nx.maximum_flow_value(G, 1, 7) 

349 True 

350 

351 """ 

352 maxFlow = nx.maximum_flow_value(G, s, t, capacity=capacity) 

353 H = nx.DiGraph(G) 

354 H.add_node(s, demand=-maxFlow) 

355 H.add_node(t, demand=maxFlow) 

356 return min_cost_flow(H, capacity=capacity, weight=weight)