networksimplex.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. """
  2. Minimum cost flow algorithms on directed connected graphs.
  3. """
  4. __all__ = ["network_simplex"]
  5. from itertools import chain, islice, repeat
  6. from math import ceil, sqrt
  7. import networkx as nx
  8. from networkx.utils import not_implemented_for
  9. class _DataEssentialsAndFunctions:
  10. def __init__(
  11. self, G, multigraph, demand="demand", capacity="capacity", weight="weight"
  12. ):
  13. # Number all nodes and edges and hereafter reference them using ONLY their numbers
  14. self.node_list = list(G) # nodes
  15. self.node_indices = {u: i for i, u in enumerate(self.node_list)} # node indices
  16. self.node_demands = [
  17. G.nodes[u].get(demand, 0) for u in self.node_list
  18. ] # node demands
  19. self.edge_sources = [] # edge sources
  20. self.edge_targets = [] # edge targets
  21. if multigraph:
  22. self.edge_keys = [] # edge keys
  23. self.edge_indices = {} # edge indices
  24. self.edge_capacities = [] # edge capacities
  25. self.edge_weights = [] # edge weights
  26. if not multigraph:
  27. edges = G.edges(data=True)
  28. else:
  29. edges = G.edges(data=True, keys=True)
  30. inf = float("inf")
  31. edges = (e for e in edges if e[0] != e[1] and e[-1].get(capacity, inf) != 0)
  32. for i, e in enumerate(edges):
  33. self.edge_sources.append(self.node_indices[e[0]])
  34. self.edge_targets.append(self.node_indices[e[1]])
  35. if multigraph:
  36. self.edge_keys.append(e[2])
  37. self.edge_indices[e[:-1]] = i
  38. self.edge_capacities.append(e[-1].get(capacity, inf))
  39. self.edge_weights.append(e[-1].get(weight, 0))
  40. # spanning tree specific data to be initialized
  41. self.edge_count = None # number of edges
  42. self.edge_flow = None # edge flows
  43. self.node_potentials = None # node potentials
  44. self.parent = None # parent nodes
  45. self.parent_edge = None # edges to parents
  46. self.subtree_size = None # subtree sizes
  47. self.next_node_dft = None # next nodes in depth-first thread
  48. self.prev_node_dft = None # previous nodes in depth-first thread
  49. self.last_descendent_dft = None # last descendants in depth-first thread
  50. self._spanning_tree_initialized = (
  51. False # False until initialize_spanning_tree() is called
  52. )
  53. def initialize_spanning_tree(self, n, faux_inf):
  54. self.edge_count = len(self.edge_indices) # number of edges
  55. self.edge_flow = list(
  56. chain(repeat(0, self.edge_count), (abs(d) for d in self.node_demands))
  57. ) # edge flows
  58. self.node_potentials = [
  59. faux_inf if d <= 0 else -faux_inf for d in self.node_demands
  60. ] # node potentials
  61. self.parent = list(chain(repeat(-1, n), [None])) # parent nodes
  62. self.parent_edge = list(
  63. range(self.edge_count, self.edge_count + n)
  64. ) # edges to parents
  65. self.subtree_size = list(chain(repeat(1, n), [n + 1])) # subtree sizes
  66. self.next_node_dft = list(
  67. chain(range(1, n), [-1, 0])
  68. ) # next nodes in depth-first thread
  69. self.prev_node_dft = list(range(-1, n)) # previous nodes in depth-first thread
  70. self.last_descendent_dft = list(
  71. chain(range(n), [n - 1])
  72. ) # last descendants in depth-first thread
  73. self._spanning_tree_initialized = True # True only if all the assignments pass
  74. def find_apex(self, p, q):
  75. """
  76. Find the lowest common ancestor of nodes p and q in the spanning tree.
  77. """
  78. size_p = self.subtree_size[p]
  79. size_q = self.subtree_size[q]
  80. while True:
  81. while size_p < size_q:
  82. p = self.parent[p]
  83. size_p = self.subtree_size[p]
  84. while size_p > size_q:
  85. q = self.parent[q]
  86. size_q = self.subtree_size[q]
  87. if size_p == size_q:
  88. if p != q:
  89. p = self.parent[p]
  90. size_p = self.subtree_size[p]
  91. q = self.parent[q]
  92. size_q = self.subtree_size[q]
  93. else:
  94. return p
  95. def trace_path(self, p, w):
  96. """
  97. Returns the nodes and edges on the path from node p to its ancestor w.
  98. """
  99. Wn = [p]
  100. We = []
  101. while p != w:
  102. We.append(self.parent_edge[p])
  103. p = self.parent[p]
  104. Wn.append(p)
  105. return Wn, We
  106. def find_cycle(self, i, p, q):
  107. """
  108. Returns the nodes and edges on the cycle containing edge i == (p, q)
  109. when the latter is added to the spanning tree.
  110. The cycle is oriented in the direction from p to q.
  111. """
  112. w = self.find_apex(p, q)
  113. Wn, We = self.trace_path(p, w)
  114. Wn.reverse()
  115. We.reverse()
  116. if We != [i]:
  117. We.append(i)
  118. WnR, WeR = self.trace_path(q, w)
  119. del WnR[-1]
  120. Wn += WnR
  121. We += WeR
  122. return Wn, We
  123. def augment_flow(self, Wn, We, f):
  124. """
  125. Augment f units of flow along a cycle represented by Wn and We.
  126. """
  127. for i, p in zip(We, Wn):
  128. if self.edge_sources[i] == p:
  129. self.edge_flow[i] += f
  130. else:
  131. self.edge_flow[i] -= f
  132. def trace_subtree(self, p):
  133. """
  134. Yield the nodes in the subtree rooted at a node p.
  135. """
  136. yield p
  137. l = self.last_descendent_dft[p]
  138. while p != l:
  139. p = self.next_node_dft[p]
  140. yield p
  141. def remove_edge(self, s, t):
  142. """
  143. Remove an edge (s, t) where parent[t] == s from the spanning tree.
  144. """
  145. size_t = self.subtree_size[t]
  146. prev_t = self.prev_node_dft[t]
  147. last_t = self.last_descendent_dft[t]
  148. next_last_t = self.next_node_dft[last_t]
  149. # Remove (s, t).
  150. self.parent[t] = None
  151. self.parent_edge[t] = None
  152. # Remove the subtree rooted at t from the depth-first thread.
  153. self.next_node_dft[prev_t] = next_last_t
  154. self.prev_node_dft[next_last_t] = prev_t
  155. self.next_node_dft[last_t] = t
  156. self.prev_node_dft[t] = last_t
  157. # Update the subtree sizes and last descendants of the (old) acenstors
  158. # of t.
  159. while s is not None:
  160. self.subtree_size[s] -= size_t
  161. if self.last_descendent_dft[s] == last_t:
  162. self.last_descendent_dft[s] = prev_t
  163. s = self.parent[s]
  164. def make_root(self, q):
  165. """
  166. Make a node q the root of its containing subtree.
  167. """
  168. ancestors = []
  169. while q is not None:
  170. ancestors.append(q)
  171. q = self.parent[q]
  172. ancestors.reverse()
  173. for p, q in zip(ancestors, islice(ancestors, 1, None)):
  174. size_p = self.subtree_size[p]
  175. last_p = self.last_descendent_dft[p]
  176. prev_q = self.prev_node_dft[q]
  177. last_q = self.last_descendent_dft[q]
  178. next_last_q = self.next_node_dft[last_q]
  179. # Make p a child of q.
  180. self.parent[p] = q
  181. self.parent[q] = None
  182. self.parent_edge[p] = self.parent_edge[q]
  183. self.parent_edge[q] = None
  184. self.subtree_size[p] = size_p - self.subtree_size[q]
  185. self.subtree_size[q] = size_p
  186. # Remove the subtree rooted at q from the depth-first thread.
  187. self.next_node_dft[prev_q] = next_last_q
  188. self.prev_node_dft[next_last_q] = prev_q
  189. self.next_node_dft[last_q] = q
  190. self.prev_node_dft[q] = last_q
  191. if last_p == last_q:
  192. self.last_descendent_dft[p] = prev_q
  193. last_p = prev_q
  194. # Add the remaining parts of the subtree rooted at p as a subtree
  195. # of q in the depth-first thread.
  196. self.prev_node_dft[p] = last_q
  197. self.next_node_dft[last_q] = p
  198. self.next_node_dft[last_p] = q
  199. self.prev_node_dft[q] = last_p
  200. self.last_descendent_dft[q] = last_p
  201. def add_edge(self, i, p, q):
  202. """
  203. Add an edge (p, q) to the spanning tree where q is the root of a subtree.
  204. """
  205. last_p = self.last_descendent_dft[p]
  206. next_last_p = self.next_node_dft[last_p]
  207. size_q = self.subtree_size[q]
  208. last_q = self.last_descendent_dft[q]
  209. # Make q a child of p.
  210. self.parent[q] = p
  211. self.parent_edge[q] = i
  212. # Insert the subtree rooted at q into the depth-first thread.
  213. self.next_node_dft[last_p] = q
  214. self.prev_node_dft[q] = last_p
  215. self.prev_node_dft[next_last_p] = last_q
  216. self.next_node_dft[last_q] = next_last_p
  217. # Update the subtree sizes and last descendants of the (new) ancestors
  218. # of q.
  219. while p is not None:
  220. self.subtree_size[p] += size_q
  221. if self.last_descendent_dft[p] == last_p:
  222. self.last_descendent_dft[p] = last_q
  223. p = self.parent[p]
  224. def update_potentials(self, i, p, q):
  225. """
  226. Update the potentials of the nodes in the subtree rooted at a node
  227. q connected to its parent p by an edge i.
  228. """
  229. if q == self.edge_targets[i]:
  230. d = self.node_potentials[p] - self.edge_weights[i] - self.node_potentials[q]
  231. else:
  232. d = self.node_potentials[p] + self.edge_weights[i] - self.node_potentials[q]
  233. for q in self.trace_subtree(q):
  234. self.node_potentials[q] += d
  235. def reduced_cost(self, i):
  236. """Returns the reduced cost of an edge i."""
  237. c = (
  238. self.edge_weights[i]
  239. - self.node_potentials[self.edge_sources[i]]
  240. + self.node_potentials[self.edge_targets[i]]
  241. )
  242. return c if self.edge_flow[i] == 0 else -c
  243. def find_entering_edges(self):
  244. """Yield entering edges until none can be found."""
  245. if self.edge_count == 0:
  246. return
  247. # Entering edges are found by combining Dantzig's rule and Bland's
  248. # rule. The edges are cyclically grouped into blocks of size B. Within
  249. # each block, Dantzig's rule is applied to find an entering edge. The
  250. # blocks to search is determined following Bland's rule.
  251. B = int(ceil(sqrt(self.edge_count))) # pivot block size
  252. M = (self.edge_count + B - 1) // B # number of blocks needed to cover all edges
  253. m = 0 # number of consecutive blocks without eligible
  254. # entering edges
  255. f = 0 # first edge in block
  256. while m < M:
  257. # Determine the next block of edges.
  258. l = f + B
  259. if l <= self.edge_count:
  260. edges = range(f, l)
  261. else:
  262. l -= self.edge_count
  263. edges = chain(range(f, self.edge_count), range(l))
  264. f = l
  265. # Find the first edge with the lowest reduced cost.
  266. i = min(edges, key=self.reduced_cost)
  267. c = self.reduced_cost(i)
  268. if c >= 0:
  269. # No entering edge found in the current block.
  270. m += 1
  271. else:
  272. # Entering edge found.
  273. if self.edge_flow[i] == 0:
  274. p = self.edge_sources[i]
  275. q = self.edge_targets[i]
  276. else:
  277. p = self.edge_targets[i]
  278. q = self.edge_sources[i]
  279. yield i, p, q
  280. m = 0
  281. # All edges have nonnegative reduced costs. The current flow is
  282. # optimal.
  283. def residual_capacity(self, i, p):
  284. """Returns the residual capacity of an edge i in the direction away
  285. from its endpoint p.
  286. """
  287. return (
  288. self.edge_capacities[i] - self.edge_flow[i]
  289. if self.edge_sources[i] == p
  290. else self.edge_flow[i]
  291. )
  292. def find_leaving_edge(self, Wn, We):
  293. """Returns the leaving edge in a cycle represented by Wn and We."""
  294. j, s = min(
  295. zip(reversed(We), reversed(Wn)),
  296. key=lambda i_p: self.residual_capacity(*i_p),
  297. )
  298. t = self.edge_targets[j] if self.edge_sources[j] == s else self.edge_sources[j]
  299. return j, s, t
  300. @not_implemented_for("undirected")
  301. def network_simplex(G, demand="demand", capacity="capacity", weight="weight"):
  302. r"""Find a minimum cost flow satisfying all demands in digraph G.
  303. This is a primal network simplex algorithm that uses the leaving
  304. arc rule to prevent cycling.
  305. G is a digraph with edge costs and capacities and in which nodes
  306. have demand, i.e., they want to send or receive some amount of
  307. flow. A negative demand means that the node wants to send flow, a
  308. positive demand means that the node want to receive flow. A flow on
  309. the digraph G satisfies all demand if the net flow into each node
  310. is equal to the demand of that node.
  311. Parameters
  312. ----------
  313. G : NetworkX graph
  314. DiGraph on which a minimum cost flow satisfying all demands is
  315. to be found.
  316. demand : string
  317. Nodes of the graph G are expected to have an attribute demand
  318. that indicates how much flow a node wants to send (negative
  319. demand) or receive (positive demand). Note that the sum of the
  320. demands should be 0 otherwise the problem in not feasible. If
  321. this attribute is not present, a node is considered to have 0
  322. demand. Default value: 'demand'.
  323. capacity : string
  324. Edges of the graph G are expected to have an attribute capacity
  325. that indicates how much flow the edge can support. If this
  326. attribute is not present, the edge is considered to have
  327. infinite capacity. Default value: 'capacity'.
  328. weight : string
  329. Edges of the graph G are expected to have an attribute weight
  330. that indicates the cost incurred by sending one unit of flow on
  331. that edge. If not present, the weight is considered to be 0.
  332. Default value: 'weight'.
  333. Returns
  334. -------
  335. flowCost : integer, float
  336. Cost of a minimum cost flow satisfying all demands.
  337. flowDict : dictionary
  338. Dictionary of dictionaries keyed by nodes such that
  339. flowDict[u][v] is the flow edge (u, v).
  340. Raises
  341. ------
  342. NetworkXError
  343. This exception is raised if the input graph is not directed or
  344. not connected.
  345. NetworkXUnfeasible
  346. This exception is raised in the following situations:
  347. * The sum of the demands is not zero. Then, there is no
  348. flow satisfying all demands.
  349. * There is no flow satisfying all demand.
  350. NetworkXUnbounded
  351. This exception is raised if the digraph G has a cycle of
  352. negative cost and infinite capacity. Then, the cost of a flow
  353. satisfying all demands is unbounded below.
  354. Notes
  355. -----
  356. This algorithm is not guaranteed to work if edge weights or demands
  357. are floating point numbers (overflows and roundoff errors can
  358. cause problems). As a workaround you can use integer numbers by
  359. multiplying the relevant edge attributes by a convenient
  360. constant factor (eg 100).
  361. See also
  362. --------
  363. cost_of_flow, max_flow_min_cost, min_cost_flow, min_cost_flow_cost
  364. Examples
  365. --------
  366. A simple example of a min cost flow problem.
  367. >>> G = nx.DiGraph()
  368. >>> G.add_node("a", demand=-5)
  369. >>> G.add_node("d", demand=5)
  370. >>> G.add_edge("a", "b", weight=3, capacity=4)
  371. >>> G.add_edge("a", "c", weight=6, capacity=10)
  372. >>> G.add_edge("b", "d", weight=1, capacity=9)
  373. >>> G.add_edge("c", "d", weight=2, capacity=5)
  374. >>> flowCost, flowDict = nx.network_simplex(G)
  375. >>> flowCost
  376. 24
  377. >>> flowDict
  378. {'a': {'b': 4, 'c': 1}, 'd': {}, 'b': {'d': 4}, 'c': {'d': 1}}
  379. The mincost flow algorithm can also be used to solve shortest path
  380. problems. To find the shortest path between two nodes u and v,
  381. give all edges an infinite capacity, give node u a demand of -1 and
  382. node v a demand a 1. Then run the network simplex. The value of a
  383. min cost flow will be the distance between u and v and edges
  384. carrying positive flow will indicate the path.
  385. >>> G = nx.DiGraph()
  386. >>> G.add_weighted_edges_from(
  387. ... [
  388. ... ("s", "u", 10),
  389. ... ("s", "x", 5),
  390. ... ("u", "v", 1),
  391. ... ("u", "x", 2),
  392. ... ("v", "y", 1),
  393. ... ("x", "u", 3),
  394. ... ("x", "v", 5),
  395. ... ("x", "y", 2),
  396. ... ("y", "s", 7),
  397. ... ("y", "v", 6),
  398. ... ]
  399. ... )
  400. >>> G.add_node("s", demand=-1)
  401. >>> G.add_node("v", demand=1)
  402. >>> flowCost, flowDict = nx.network_simplex(G)
  403. >>> flowCost == nx.shortest_path_length(G, "s", "v", weight="weight")
  404. True
  405. >>> sorted([(u, v) for u in flowDict for v in flowDict[u] if flowDict[u][v] > 0])
  406. [('s', 'x'), ('u', 'v'), ('x', 'u')]
  407. >>> nx.shortest_path(G, "s", "v", weight="weight")
  408. ['s', 'x', 'u', 'v']
  409. It is possible to change the name of the attributes used for the
  410. algorithm.
  411. >>> G = nx.DiGraph()
  412. >>> G.add_node("p", spam=-4)
  413. >>> G.add_node("q", spam=2)
  414. >>> G.add_node("a", spam=-2)
  415. >>> G.add_node("d", spam=-1)
  416. >>> G.add_node("t", spam=2)
  417. >>> G.add_node("w", spam=3)
  418. >>> G.add_edge("p", "q", cost=7, vacancies=5)
  419. >>> G.add_edge("p", "a", cost=1, vacancies=4)
  420. >>> G.add_edge("q", "d", cost=2, vacancies=3)
  421. >>> G.add_edge("t", "q", cost=1, vacancies=2)
  422. >>> G.add_edge("a", "t", cost=2, vacancies=4)
  423. >>> G.add_edge("d", "w", cost=3, vacancies=4)
  424. >>> G.add_edge("t", "w", cost=4, vacancies=1)
  425. >>> flowCost, flowDict = nx.network_simplex(
  426. ... G, demand="spam", capacity="vacancies", weight="cost"
  427. ... )
  428. >>> flowCost
  429. 37
  430. >>> flowDict
  431. {'p': {'q': 2, 'a': 2}, 'q': {'d': 1}, 'a': {'t': 4}, 'd': {'w': 2}, 't': {'q': 1, 'w': 1}, 'w': {}}
  432. References
  433. ----------
  434. .. [1] Z. Kiraly, P. Kovacs.
  435. Efficient implementation of minimum-cost flow algorithms.
  436. Acta Universitatis Sapientiae, Informatica 4(1):67--118. 2012.
  437. .. [2] R. Barr, F. Glover, D. Klingman.
  438. Enhancement of spanning tree labeling procedures for network
  439. optimization.
  440. INFOR 17(1):16--34. 1979.
  441. """
  442. ###########################################################################
  443. # Problem essentials extraction and sanity check
  444. ###########################################################################
  445. if len(G) == 0:
  446. raise nx.NetworkXError("graph has no nodes")
  447. multigraph = G.is_multigraph()
  448. # extracting data essential to problem
  449. DEAF = _DataEssentialsAndFunctions(
  450. G, multigraph, demand=demand, capacity=capacity, weight=weight
  451. )
  452. ###########################################################################
  453. # Quick Error Detection
  454. ###########################################################################
  455. inf = float("inf")
  456. for u, d in zip(DEAF.node_list, DEAF.node_demands):
  457. if abs(d) == inf:
  458. raise nx.NetworkXError(f"node {u!r} has infinite demand")
  459. for e, w in zip(DEAF.edge_indices, DEAF.edge_weights):
  460. if abs(w) == inf:
  461. raise nx.NetworkXError(f"edge {e!r} has infinite weight")
  462. if not multigraph:
  463. edges = nx.selfloop_edges(G, data=True)
  464. else:
  465. edges = nx.selfloop_edges(G, data=True, keys=True)
  466. for e in edges:
  467. if abs(e[-1].get(weight, 0)) == inf:
  468. raise nx.NetworkXError(f"edge {e[:-1]!r} has infinite weight")
  469. ###########################################################################
  470. # Quick Infeasibility Detection
  471. ###########################################################################
  472. if sum(DEAF.node_demands) != 0:
  473. raise nx.NetworkXUnfeasible("total node demand is not zero")
  474. for e, c in zip(DEAF.edge_indices, DEAF.edge_capacities):
  475. if c < 0:
  476. raise nx.NetworkXUnfeasible(f"edge {e!r} has negative capacity")
  477. if not multigraph:
  478. edges = nx.selfloop_edges(G, data=True)
  479. else:
  480. edges = nx.selfloop_edges(G, data=True, keys=True)
  481. for e in edges:
  482. if e[-1].get(capacity, inf) < 0:
  483. raise nx.NetworkXUnfeasible(f"edge {e[:-1]!r} has negative capacity")
  484. ###########################################################################
  485. # Initialization
  486. ###########################################################################
  487. # Add a dummy node -1 and connect all existing nodes to it with infinite-
  488. # capacity dummy edges. Node -1 will serve as the root of the
  489. # spanning tree of the network simplex method. The new edges will used to
  490. # trivially satisfy the node demands and create an initial strongly
  491. # feasible spanning tree.
  492. for i, d in enumerate(DEAF.node_demands):
  493. # Must be greater-than here. Zero-demand nodes must have
  494. # edges pointing towards the root to ensure strong feasibility.
  495. if d > 0:
  496. DEAF.edge_sources.append(-1)
  497. DEAF.edge_targets.append(i)
  498. else:
  499. DEAF.edge_sources.append(i)
  500. DEAF.edge_targets.append(-1)
  501. faux_inf = (
  502. 3
  503. * max(
  504. chain(
  505. [
  506. sum(c for c in DEAF.edge_capacities if c < inf),
  507. sum(abs(w) for w in DEAF.edge_weights),
  508. ],
  509. (abs(d) for d in DEAF.node_demands),
  510. )
  511. )
  512. or 1
  513. )
  514. n = len(DEAF.node_list) # number of nodes
  515. DEAF.edge_weights.extend(repeat(faux_inf, n))
  516. DEAF.edge_capacities.extend(repeat(faux_inf, n))
  517. # Construct the initial spanning tree.
  518. DEAF.initialize_spanning_tree(n, faux_inf)
  519. ###########################################################################
  520. # Pivot loop
  521. ###########################################################################
  522. for i, p, q in DEAF.find_entering_edges():
  523. Wn, We = DEAF.find_cycle(i, p, q)
  524. j, s, t = DEAF.find_leaving_edge(Wn, We)
  525. DEAF.augment_flow(Wn, We, DEAF.residual_capacity(j, s))
  526. # Do nothing more if the entering edge is the same as the leaving edge.
  527. if i != j:
  528. if DEAF.parent[t] != s:
  529. # Ensure that s is the parent of t.
  530. s, t = t, s
  531. if We.index(i) > We.index(j):
  532. # Ensure that q is in the subtree rooted at t.
  533. p, q = q, p
  534. DEAF.remove_edge(s, t)
  535. DEAF.make_root(q)
  536. DEAF.add_edge(i, p, q)
  537. DEAF.update_potentials(i, p, q)
  538. ###########################################################################
  539. # Infeasibility and unboundedness detection
  540. ###########################################################################
  541. if any(DEAF.edge_flow[i] != 0 for i in range(-n, 0)):
  542. raise nx.NetworkXUnfeasible("no flow satisfies all node demands")
  543. if any(DEAF.edge_flow[i] * 2 >= faux_inf for i in range(DEAF.edge_count)) or any(
  544. e[-1].get(capacity, inf) == inf and e[-1].get(weight, 0) < 0
  545. for e in nx.selfloop_edges(G, data=True)
  546. ):
  547. raise nx.NetworkXUnbounded("negative cycle with infinite capacity found")
  548. ###########################################################################
  549. # Flow cost calculation and flow dict construction
  550. ###########################################################################
  551. del DEAF.edge_flow[DEAF.edge_count :]
  552. flow_cost = sum(w * x for w, x in zip(DEAF.edge_weights, DEAF.edge_flow))
  553. flow_dict = {n: {} for n in DEAF.node_list}
  554. def add_entry(e):
  555. """Add a flow dict entry."""
  556. d = flow_dict[e[0]]
  557. for k in e[1:-2]:
  558. try:
  559. d = d[k]
  560. except KeyError:
  561. t = {}
  562. d[k] = t
  563. d = t
  564. d[e[-2]] = e[-1]
  565. DEAF.edge_sources = (
  566. DEAF.node_list[s] for s in DEAF.edge_sources
  567. ) # Use original nodes.
  568. DEAF.edge_targets = (
  569. DEAF.node_list[t] for t in DEAF.edge_targets
  570. ) # Use original nodes.
  571. if not multigraph:
  572. for e in zip(DEAF.edge_sources, DEAF.edge_targets, DEAF.edge_flow):
  573. add_entry(e)
  574. edges = G.edges(data=True)
  575. else:
  576. for e in zip(
  577. DEAF.edge_sources, DEAF.edge_targets, DEAF.edge_keys, DEAF.edge_flow
  578. ):
  579. add_entry(e)
  580. edges = G.edges(data=True, keys=True)
  581. for e in edges:
  582. if e[0] != e[1]:
  583. if e[-1].get(capacity, inf) == 0:
  584. add_entry(e[:-1] + (0,))
  585. else:
  586. w = e[-1].get(weight, 0)
  587. if w >= 0:
  588. add_entry(e[:-1] + (0,))
  589. else:
  590. c = e[-1][capacity]
  591. flow_cost += w * c
  592. add_entry(e[:-1] + (c,))
  593. return flow_cost, flow_dict