Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/networkx/algorithms/shortest_paths/weighted.py: 14%

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

443 statements  

1""" 

2Shortest path algorithms for weighted graphs. 

3""" 

4 

5from collections import deque 

6from heapq import heappop, heappush 

7from itertools import count, islice 

8 

9import networkx as nx 

10from networkx.algorithms.shortest_paths.generic import _build_paths_from_predecessors 

11 

12__all__ = [ 

13 "dijkstra_path", 

14 "dijkstra_path_length", 

15 "bidirectional_dijkstra", 

16 "single_source_dijkstra", 

17 "single_source_dijkstra_path", 

18 "single_source_dijkstra_path_length", 

19 "multi_source_dijkstra", 

20 "multi_source_dijkstra_path", 

21 "multi_source_dijkstra_path_length", 

22 "all_pairs_dijkstra", 

23 "all_pairs_dijkstra_path", 

24 "all_pairs_dijkstra_path_length", 

25 "dijkstra_predecessor_and_distance", 

26 "bellman_ford_path", 

27 "bellman_ford_path_length", 

28 "single_source_bellman_ford", 

29 "single_source_bellman_ford_path", 

30 "single_source_bellman_ford_path_length", 

31 "all_pairs_bellman_ford_path", 

32 "all_pairs_bellman_ford_path_length", 

33 "bellman_ford_predecessor_and_distance", 

34 "negative_edge_cycle", 

35 "find_negative_cycle", 

36 "goldberg_radzik", 

37 "johnson", 

38] 

39 

40 

41def _weight_function(G, weight): 

42 """Returns a function that returns the weight of an edge. 

43 

44 The returned function is specifically suitable for input to 

45 functions :func:`_dijkstra` and :func:`_bellman_ford_relaxation`. 

46 

47 Parameters 

48 ---------- 

49 G : NetworkX graph. 

50 

51 weight : string or function 

52 If it is callable, `weight` itself is returned. If it is a string, 

53 it is assumed to be the name of the edge attribute that represents 

54 the weight of an edge. In that case, a function is returned that 

55 gets the edge weight according to the specified edge attribute. 

56 

57 Returns 

58 ------- 

59 function 

60 This function returns a callable that accepts exactly three inputs: 

61 a node, an node adjacent to the first one, and the edge attribute 

62 dictionary for the eedge joining those nodes. That function returns 

63 a number representing the weight of an edge. 

64 

65 If `G` is a multigraph, and `weight` is not callable, the 

66 minimum edge weight over all parallel edges is returned. If any edge 

67 does not have an attribute with key `weight`, it is assumed to 

68 have weight one. 

69 

70 """ 

71 if callable(weight): 

72 return weight 

73 # If the weight keyword argument is not callable, we assume it is a 

74 # string representing the edge attribute containing the weight of 

75 # the edge. 

76 if G.is_multigraph(): 

77 return lambda u, v, d: min(attr.get(weight, 1) for attr in d.values()) 

78 return lambda u, v, data: data.get(weight, 1) 

79 

80 

81@nx._dispatchable(edge_attrs="weight") 

82def dijkstra_path(G, source, target, weight="weight"): 

83 """Returns the shortest weighted path from source to target in G. 

84 

85 Uses Dijkstra's Method to compute the shortest weighted path 

86 between two nodes in a graph. 

87 

88 Parameters 

89 ---------- 

90 G : NetworkX graph 

91 

92 source : node 

93 Starting node 

94 

95 target : node 

96 Ending node 

97 

98 weight : string or function 

99 If this is a string, then edge weights will be accessed via the 

100 edge attribute with this key (that is, the weight of the edge 

101 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

102 such edge attribute exists, the weight of the edge is assumed to 

103 be one. 

104 

105 If this is a function, the weight of an edge is the value 

106 returned by the function. The function must accept exactly three 

107 positional arguments: the two endpoints of an edge and the 

108 dictionary of edge attributes for that edge. The function must 

109 return a number or None to indicate a hidden edge. 

110 

111 Returns 

112 ------- 

113 path : list 

114 List of nodes in a shortest path. 

115 

116 Raises 

117 ------ 

118 NodeNotFound 

119 If `source` is not in `G`. 

120 

121 NetworkXNoPath 

122 If no path exists between source and target. 

123 

124 Examples 

125 -------- 

126 >>> G = nx.path_graph(5) 

127 >>> print(nx.dijkstra_path(G, 0, 4)) 

128 [0, 1, 2, 3, 4] 

129 

130 Find edges of shortest path in Multigraph 

131 

132 >>> G = nx.MultiDiGraph() 

133 >>> G.add_weighted_edges_from([(1, 2, 0.75), (1, 2, 0.5), (2, 3, 0.5), (1, 3, 1.5)]) 

134 >>> nodes = nx.dijkstra_path(G, 1, 3) 

135 >>> edges = nx.utils.pairwise(nodes) 

136 >>> list( 

137 ... (u, v, min(G[u][v], key=lambda k: G[u][v][k].get("weight", 1))) 

138 ... for u, v in edges 

139 ... ) 

140 [(1, 2, 1), (2, 3, 0)] 

141 

142 Notes 

143 ----- 

144 Edge weight attributes must be numerical. 

145 Distances are calculated as sums of weighted edges traversed. 

146 

147 The weight function can be used to hide edges by returning None. 

148 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

149 will find the shortest red path. 

150 

151 The weight function can be used to include node weights. 

152 

153 >>> def func(u, v, d): 

154 ... node_u_wt = G.nodes[u].get("node_weight", 1) 

155 ... node_v_wt = G.nodes[v].get("node_weight", 1) 

156 ... edge_wt = d.get("weight", 1) 

157 ... return node_u_wt / 2 + node_v_wt / 2 + edge_wt 

158 

159 In this example we take the average of start and end node 

160 weights of an edge and add it to the weight of the edge. 

161 

162 The function :func:`single_source_dijkstra` computes both 

163 path and length-of-path if you need both, use that. 

164 

165 See Also 

166 -------- 

167 bidirectional_dijkstra 

168 bellman_ford_path 

169 single_source_dijkstra 

170 """ 

171 (length, path) = single_source_dijkstra(G, source, target=target, weight=weight) 

172 return path 

173 

174 

175@nx._dispatchable(edge_attrs="weight") 

176def dijkstra_path_length(G, source, target, weight="weight"): 

177 """Returns the shortest weighted path length in G from source to target. 

178 

179 Uses Dijkstra's Method to compute the shortest weighted path length 

180 between two nodes in a graph. 

181 

182 Parameters 

183 ---------- 

184 G : NetworkX graph 

185 

186 source : node label 

187 starting node for path 

188 

189 target : node label 

190 ending node for path 

191 

192 weight : string or function 

193 If this is a string, then edge weights will be accessed via the 

194 edge attribute with this key (that is, the weight of the edge 

195 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

196 such edge attribute exists, the weight of the edge is assumed to 

197 be one. 

198 

199 If this is a function, the weight of an edge is the value 

200 returned by the function. The function must accept exactly three 

201 positional arguments: the two endpoints of an edge and the 

202 dictionary of edge attributes for that edge. The function must 

203 return a number or None to indicate a hidden edge. 

204 

205 Returns 

206 ------- 

207 length : number 

208 Shortest path length. 

209 

210 Raises 

211 ------ 

212 NodeNotFound 

213 If `source` is not in `G`. 

214 

215 NetworkXNoPath 

216 If no path exists between source and target. 

217 

218 Examples 

219 -------- 

220 >>> G = nx.path_graph(5) 

221 >>> nx.dijkstra_path_length(G, 0, 4) 

222 4 

223 

224 Notes 

225 ----- 

226 Edge weight attributes must be numerical. 

227 Distances are calculated as sums of weighted edges traversed. 

228 

229 The weight function can be used to hide edges by returning None. 

230 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

231 will find the shortest red path. 

232 

233 The function :func:`single_source_dijkstra` computes both 

234 path and length-of-path if you need both, use that. 

235 

236 See Also 

237 -------- 

238 bidirectional_dijkstra 

239 bellman_ford_path_length 

240 single_source_dijkstra 

241 

242 """ 

243 if source not in G: 

244 raise nx.NodeNotFound(f"Node {source} not found in graph") 

245 if source == target: 

246 return 0 

247 weight = _weight_function(G, weight) 

248 length = _dijkstra(G, source, weight, target=target) 

249 try: 

250 return length[target] 

251 except KeyError as err: 

252 raise nx.NetworkXNoPath(f"Node {target} not reachable from {source}") from err 

253 

254 

255@nx._dispatchable(edge_attrs="weight") 

256def single_source_dijkstra_path(G, source, cutoff=None, weight="weight"): 

257 """Find shortest weighted paths in G from a source node. 

258 

259 Compute shortest path between source and all other reachable 

260 nodes for a weighted graph. 

261 

262 Parameters 

263 ---------- 

264 G : NetworkX graph 

265 

266 source : node 

267 Starting node for path. 

268 

269 cutoff : integer or float, optional 

270 Length (sum of edge weights) at which the search is stopped. 

271 If cutoff is provided, only return paths with summed weight <= cutoff. 

272 

273 weight : string or function 

274 If this is a string, then edge weights will be accessed via the 

275 edge attribute with this key (that is, the weight of the edge 

276 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

277 such edge attribute exists, the weight of the edge is assumed to 

278 be one. 

279 

280 If this is a function, the weight of an edge is the value 

281 returned by the function. The function must accept exactly three 

282 positional arguments: the two endpoints of an edge and the 

283 dictionary of edge attributes for that edge. The function must 

284 return a number or None to indicate a hidden edge. 

285 

286 Returns 

287 ------- 

288 paths : dictionary 

289 Dictionary of shortest path lengths keyed by target. 

290 

291 Raises 

292 ------ 

293 NodeNotFound 

294 If `source` is not in `G`. 

295 

296 Examples 

297 -------- 

298 >>> G = nx.path_graph(5) 

299 >>> path = nx.single_source_dijkstra_path(G, 0) 

300 >>> path[4] 

301 [0, 1, 2, 3, 4] 

302 

303 Notes 

304 ----- 

305 Edge weight attributes must be numerical. 

306 Distances are calculated as sums of weighted edges traversed. 

307 

308 The weight function can be used to hide edges by returning None. 

309 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

310 will find the shortest red path. 

311 

312 See Also 

313 -------- 

314 single_source_dijkstra, single_source_bellman_ford 

315 

316 """ 

317 return multi_source_dijkstra_path(G, {source}, cutoff=cutoff, weight=weight) 

318 

319 

320@nx._dispatchable(edge_attrs="weight") 

321def single_source_dijkstra_path_length(G, source, cutoff=None, weight="weight"): 

322 """Find shortest weighted path lengths in G from a source node. 

323 

324 Compute the shortest path length between source and all other 

325 reachable nodes for a weighted graph. 

326 

327 Parameters 

328 ---------- 

329 G : NetworkX graph 

330 

331 source : node label 

332 Starting node for path 

333 

334 cutoff : integer or float, optional 

335 Length (sum of edge weights) at which the search is stopped. 

336 If cutoff is provided, only return paths with summed weight <= cutoff. 

337 

338 weight : string or function 

339 If this is a string, then edge weights will be accessed via the 

340 edge attribute with this key (that is, the weight of the edge 

341 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

342 such edge attribute exists, the weight of the edge is assumed to 

343 be one. 

344 

345 If this is a function, the weight of an edge is the value 

346 returned by the function. The function must accept exactly three 

347 positional arguments: the two endpoints of an edge and the 

348 dictionary of edge attributes for that edge. The function must 

349 return a number or None to indicate a hidden edge. 

350 

351 Returns 

352 ------- 

353 length : dict 

354 Dict keyed by node to shortest path length from source. 

355 

356 Raises 

357 ------ 

358 NodeNotFound 

359 If `source` is not in `G`. 

360 

361 Examples 

362 -------- 

363 >>> G = nx.path_graph(5) 

364 >>> length = nx.single_source_dijkstra_path_length(G, 0) 

365 >>> length[4] 

366 4 

367 >>> for node in [0, 1, 2, 3, 4]: 

368 ... print(f"{node}: {length[node]}") 

369 0: 0 

370 1: 1 

371 2: 2 

372 3: 3 

373 4: 4 

374 

375 Notes 

376 ----- 

377 Edge weight attributes must be numerical. 

378 Distances are calculated as sums of weighted edges traversed. 

379 

380 The weight function can be used to hide edges by returning None. 

381 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

382 will find the shortest red path. 

383 

384 See Also 

385 -------- 

386 single_source_dijkstra, single_source_bellman_ford_path_length 

387 

388 """ 

389 return multi_source_dijkstra_path_length(G, {source}, cutoff=cutoff, weight=weight) 

390 

391 

392@nx._dispatchable(edge_attrs="weight") 

393def single_source_dijkstra(G, source, target=None, cutoff=None, weight="weight"): 

394 """Find shortest weighted paths and lengths from a source node. 

395 

396 Compute the shortest path length between source and all other 

397 reachable nodes for a weighted graph. 

398 

399 Uses Dijkstra's algorithm to compute shortest paths and lengths 

400 between a source and all other reachable nodes in a weighted graph. 

401 

402 Parameters 

403 ---------- 

404 G : NetworkX graph 

405 

406 source : node label 

407 Starting node for path 

408 

409 target : node label, optional 

410 Ending node for path 

411 

412 cutoff : integer or float, optional 

413 Length (sum of edge weights) at which the search is stopped. 

414 If cutoff is provided, only return paths with summed weight <= cutoff. 

415 

416 

417 weight : string or function 

418 If this is a string, then edge weights will be accessed via the 

419 edge attribute with this key (that is, the weight of the edge 

420 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

421 such edge attribute exists, the weight of the edge is assumed to 

422 be one. 

423 

424 If this is a function, the weight of an edge is the value 

425 returned by the function. The function must accept exactly three 

426 positional arguments: the two endpoints of an edge and the 

427 dictionary of edge attributes for that edge. The function must 

428 return a number or None to indicate a hidden edge. 

429 

430 Returns 

431 ------- 

432 distance, path : pair of dictionaries, or numeric and list. 

433 If target is None, paths and lengths to all nodes are computed. 

434 The return value is a tuple of two dictionaries keyed by target nodes. 

435 The first dictionary stores distance to each target node. 

436 The second stores the path to each target node. 

437 If target is not None, returns a tuple (distance, path), where 

438 distance is the distance from source to target and path is a list 

439 representing the path from source to target. 

440 

441 Raises 

442 ------ 

443 NodeNotFound 

444 If `source` is not in `G`. 

445 

446 Examples 

447 -------- 

448 >>> G = nx.path_graph(5) 

449 >>> length, path = nx.single_source_dijkstra(G, 0) 

450 >>> length[4] 

451 4 

452 >>> for node in [0, 1, 2, 3, 4]: 

453 ... print(f"{node}: {length[node]}") 

454 0: 0 

455 1: 1 

456 2: 2 

457 3: 3 

458 4: 4 

459 >>> path[4] 

460 [0, 1, 2, 3, 4] 

461 >>> length, path = nx.single_source_dijkstra(G, 0, 1) 

462 >>> length 

463 1 

464 >>> path 

465 [0, 1] 

466 

467 Notes 

468 ----- 

469 Edge weight attributes must be numerical. 

470 Distances are calculated as sums of weighted edges traversed. 

471 

472 The weight function can be used to hide edges by returning None. 

473 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

474 will find the shortest red path. 

475 

476 Based on the Python cookbook recipe (119466) at 

477 https://code.activestate.com/recipes/119466/ 

478 

479 This algorithm is not guaranteed to work if edge weights 

480 are negative or are floating point numbers 

481 (overflows and roundoff errors can cause problems). 

482 

483 See Also 

484 -------- 

485 single_source_dijkstra_path 

486 single_source_dijkstra_path_length 

487 single_source_bellman_ford 

488 """ 

489 return multi_source_dijkstra( 

490 G, {source}, cutoff=cutoff, target=target, weight=weight 

491 ) 

492 

493 

494@nx._dispatchable(edge_attrs="weight") 

495def multi_source_dijkstra_path(G, sources, cutoff=None, weight="weight"): 

496 """Find shortest weighted paths in G from a given set of source 

497 nodes. 

498 

499 Compute shortest path between any of the source nodes and all other 

500 reachable nodes for a weighted graph. 

501 

502 Parameters 

503 ---------- 

504 G : NetworkX graph 

505 

506 sources : non-empty set of nodes 

507 Starting nodes for paths. If this is just a set containing a 

508 single node, then all paths computed by this function will start 

509 from that node. If there are two or more nodes in the set, the 

510 computed paths may begin from any one of the start nodes. 

511 

512 cutoff : integer or float, optional 

513 Length (sum of edge weights) at which the search is stopped. 

514 If cutoff is provided, only return paths with summed weight <= cutoff. 

515 

516 weight : string or function 

517 If this is a string, then edge weights will be accessed via the 

518 edge attribute with this key (that is, the weight of the edge 

519 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

520 such edge attribute exists, the weight of the edge is assumed to 

521 be one. 

522 

523 If this is a function, the weight of an edge is the value 

524 returned by the function. The function must accept exactly three 

525 positional arguments: the two endpoints of an edge and the 

526 dictionary of edge attributes for that edge. The function must 

527 return a number or None to indicate a hidden edge. 

528 

529 Returns 

530 ------- 

531 paths : dictionary 

532 Dictionary of shortest paths keyed by target. 

533 

534 Examples 

535 -------- 

536 >>> G = nx.path_graph(5) 

537 >>> path = nx.multi_source_dijkstra_path(G, {0, 4}) 

538 >>> path[1] 

539 [0, 1] 

540 >>> path[3] 

541 [4, 3] 

542 

543 Notes 

544 ----- 

545 Edge weight attributes must be numerical. 

546 Distances are calculated as sums of weighted edges traversed. 

547 

548 The weight function can be used to hide edges by returning None. 

549 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

550 will find the shortest red path. 

551 

552 Raises 

553 ------ 

554 ValueError 

555 If `sources` is empty. 

556 NodeNotFound 

557 If any of `sources` is not in `G`. 

558 

559 See Also 

560 -------- 

561 multi_source_dijkstra, multi_source_bellman_ford 

562 

563 """ 

564 length, path = multi_source_dijkstra(G, sources, cutoff=cutoff, weight=weight) 

565 return path 

566 

567 

568@nx._dispatchable(edge_attrs="weight") 

569def multi_source_dijkstra_path_length(G, sources, cutoff=None, weight="weight"): 

570 """Find shortest weighted path lengths in G from a given set of 

571 source nodes. 

572 

573 Compute the shortest path length between any of the source nodes and 

574 all other reachable nodes for a weighted graph. 

575 

576 Parameters 

577 ---------- 

578 G : NetworkX graph 

579 

580 sources : non-empty set of nodes 

581 Starting nodes for paths. If this is just a set containing a 

582 single node, then all paths computed by this function will start 

583 from that node. If there are two or more nodes in the set, the 

584 computed paths may begin from any one of the start nodes. 

585 

586 cutoff : integer or float, optional 

587 Length (sum of edge weights) at which the search is stopped. 

588 If cutoff is provided, only return paths with summed weight <= cutoff. 

589 

590 weight : string or function 

591 If this is a string, then edge weights will be accessed via the 

592 edge attribute with this key (that is, the weight of the edge 

593 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

594 such edge attribute exists, the weight of the edge is assumed to 

595 be one. 

596 

597 If this is a function, the weight of an edge is the value 

598 returned by the function. The function must accept exactly three 

599 positional arguments: the two endpoints of an edge and the 

600 dictionary of edge attributes for that edge. The function must 

601 return a number or None to indicate a hidden edge. 

602 

603 Returns 

604 ------- 

605 length : dict 

606 Dict keyed by node to shortest path length to nearest source. 

607 

608 Examples 

609 -------- 

610 >>> G = nx.path_graph(5) 

611 >>> length = nx.multi_source_dijkstra_path_length(G, {0, 4}) 

612 >>> for node in [0, 1, 2, 3, 4]: 

613 ... print(f"{node}: {length[node]}") 

614 0: 0 

615 1: 1 

616 2: 2 

617 3: 1 

618 4: 0 

619 

620 Notes 

621 ----- 

622 Edge weight attributes must be numerical. 

623 Distances are calculated as sums of weighted edges traversed. 

624 

625 The weight function can be used to hide edges by returning None. 

626 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

627 will find the shortest red path. 

628 

629 Raises 

630 ------ 

631 ValueError 

632 If `sources` is empty. 

633 NodeNotFound 

634 If any of `sources` is not in `G`. 

635 

636 See Also 

637 -------- 

638 multi_source_dijkstra 

639 

640 """ 

641 if not sources: 

642 raise ValueError("sources must not be empty") 

643 for s in sources: 

644 if s not in G: 

645 raise nx.NodeNotFound(f"Node {s} not found in graph") 

646 weight = _weight_function(G, weight) 

647 return _dijkstra_multisource(G, sources, weight, cutoff=cutoff) 

648 

649 

650@nx._dispatchable(edge_attrs="weight") 

651def multi_source_dijkstra(G, sources, target=None, cutoff=None, weight="weight"): 

652 """Find shortest weighted paths and lengths from a given set of 

653 source nodes. 

654 

655 Uses Dijkstra's algorithm to compute the shortest paths and lengths 

656 between one of the source nodes and the given `target`, or all other 

657 reachable nodes if not specified, for a weighted graph. 

658 

659 Parameters 

660 ---------- 

661 G : NetworkX graph 

662 

663 sources : non-empty set of nodes 

664 Starting nodes for paths. If this is just a set containing a 

665 single node, then all paths computed by this function will start 

666 from that node. If there are two or more nodes in the set, the 

667 computed paths may begin from any one of the start nodes. 

668 

669 target : node label, optional 

670 Ending node for path 

671 

672 cutoff : integer or float, optional 

673 Length (sum of edge weights) at which the search is stopped. 

674 If cutoff is provided, only return paths with summed weight <= cutoff. 

675 

676 weight : string or function 

677 If this is a string, then edge weights will be accessed via the 

678 edge attribute with this key (that is, the weight of the edge 

679 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

680 such edge attribute exists, the weight of the edge is assumed to 

681 be one. 

682 

683 If this is a function, the weight of an edge is the value 

684 returned by the function. The function must accept exactly three 

685 positional arguments: the two endpoints of an edge and the 

686 dictionary of edge attributes for that edge. The function must 

687 return a number or None to indicate a hidden edge. 

688 

689 Returns 

690 ------- 

691 distance, path : pair of dictionaries, or numeric and list 

692 If target is None, returns a tuple of two dictionaries keyed by node. 

693 The first dictionary stores distance from one of the source nodes. 

694 The second stores the path from one of the sources to that node. 

695 If target is not None, returns a tuple of (distance, path) where 

696 distance is the distance from source to target and path is a list 

697 representing the path from source to target. 

698 

699 Examples 

700 -------- 

701 >>> G = nx.path_graph(5) 

702 >>> length, path = nx.multi_source_dijkstra(G, {0, 4}) 

703 >>> for node in [0, 1, 2, 3, 4]: 

704 ... print(f"{node}: {length[node]}") 

705 0: 0 

706 1: 1 

707 2: 2 

708 3: 1 

709 4: 0 

710 >>> path[1] 

711 [0, 1] 

712 >>> path[3] 

713 [4, 3] 

714 

715 >>> length, path = nx.multi_source_dijkstra(G, {0, 4}, 1) 

716 >>> length 

717 1 

718 >>> path 

719 [0, 1] 

720 

721 Notes 

722 ----- 

723 Edge weight attributes must be numerical. 

724 Distances are calculated as sums of weighted edges traversed. 

725 

726 The weight function can be used to hide edges by returning None. 

727 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

728 will find the shortest red path. 

729 

730 Based on the Python cookbook recipe (119466) at 

731 https://code.activestate.com/recipes/119466/ 

732 

733 This algorithm is not guaranteed to work if edge weights 

734 are negative or are floating point numbers 

735 (overflows and roundoff errors can cause problems). 

736 

737 Raises 

738 ------ 

739 ValueError 

740 If `sources` is empty. 

741 NodeNotFound 

742 If any of `sources` is not in `G`. 

743 

744 See Also 

745 -------- 

746 multi_source_dijkstra_path 

747 multi_source_dijkstra_path_length 

748 

749 """ 

750 if not sources: 

751 raise ValueError("sources must not be empty") 

752 for s in sources: 

753 if s not in G: 

754 raise nx.NodeNotFound(f"Node {s} not found in graph") 

755 if target in sources: 

756 return (0, [target]) 

757 weight = _weight_function(G, weight) 

758 paths = {source: [source] for source in sources} # dictionary of paths 

759 dist = _dijkstra_multisource( 

760 G, sources, weight, paths=paths, cutoff=cutoff, target=target 

761 ) 

762 if target is None: 

763 return (dist, paths) 

764 try: 

765 return (dist[target], paths[target]) 

766 except KeyError as err: 

767 raise nx.NetworkXNoPath(f"No path to {target}.") from err 

768 

769 

770def _dijkstra(G, source, weight, pred=None, paths=None, cutoff=None, target=None): 

771 """Uses Dijkstra's algorithm to find shortest weighted paths from a 

772 single source. 

773 

774 This is a convenience function for :func:`_dijkstra_multisource` 

775 with all the arguments the same, except the keyword argument 

776 `sources` set to ``[source]``. 

777 

778 """ 

779 return _dijkstra_multisource( 

780 G, [source], weight, pred=pred, paths=paths, cutoff=cutoff, target=target 

781 ) 

782 

783 

784def _dijkstra_multisource( 

785 G, sources, weight, pred=None, paths=None, cutoff=None, target=None 

786): 

787 """Uses Dijkstra's algorithm to find shortest weighted paths 

788 

789 Parameters 

790 ---------- 

791 G : NetworkX graph 

792 

793 sources : non-empty iterable of nodes 

794 Starting nodes for paths. If this is just an iterable containing 

795 a single node, then all paths computed by this function will 

796 start from that node. If there are two or more nodes in this 

797 iterable, the computed paths may begin from any one of the start 

798 nodes. 

799 

800 weight: function 

801 Function with (u, v, data) input that returns that edge's weight 

802 or None to indicate a hidden edge 

803 

804 pred: dict of lists, optional(default=None) 

805 dict to store a list of predecessors keyed by that node 

806 If None, predecessors are not stored. 

807 

808 paths: dict, optional (default=None) 

809 dict to store the path list from source to each node, keyed by node. 

810 If None, paths are not stored. 

811 

812 target : node label, optional 

813 Ending node for path. Search is halted when target is found. 

814 

815 cutoff : integer or float, optional 

816 Length (sum of edge weights) at which the search is stopped. 

817 If cutoff is provided, only return paths with summed weight <= cutoff. 

818 

819 Returns 

820 ------- 

821 distance : dictionary 

822 A mapping from node to shortest distance to that node from one 

823 of the source nodes. 

824 

825 Raises 

826 ------ 

827 NodeNotFound 

828 If any of `sources` is not in `G`. 

829 

830 Notes 

831 ----- 

832 The optional predecessor and path dictionaries can be accessed by 

833 the caller through the original pred and paths objects passed 

834 as arguments. No need to explicitly return pred or paths. 

835 

836 """ 

837 # If `paths` is specified, we use a temporary internal dictionary (`pred_dict`) to 

838 # store predecessors, used to reconstruct paths. However, if the caller 

839 # passed in a `pred` dictionary, we must compute *all* predecessors, since the caller 

840 # expects the full predecessor structure. 

841 pred_dict = pred if paths is None or pred is not None else {} 

842 

843 G_succ = G._adj # For speed-up (and works for both directed and undirected graphs) 

844 

845 dist = {} # dictionary of final distances 

846 seen = {} 

847 # fringe is heapq with 3-tuples (distance,c,node) 

848 # use the count c to avoid comparing nodes (may not be able to) 

849 c = count() 

850 fringe = [] 

851 for source in sources: 

852 seen[source] = 0 

853 heappush(fringe, (0, next(c), source)) 

854 number_of_sources = len(seen) 

855 while fringe: 

856 (dist_v, _, v) = heappop(fringe) 

857 if v in dist: 

858 continue # already searched this node. 

859 dist[v] = dist_v 

860 if v == target: 

861 break 

862 for u, e in G_succ[v].items(): 

863 cost = weight(v, u, e) 

864 if cost is None: 

865 continue 

866 vu_dist = dist_v + cost 

867 if cutoff is not None and vu_dist > cutoff: 

868 continue 

869 if u in dist: 

870 u_dist = dist[u] 

871 if vu_dist < u_dist: 

872 raise ValueError("Contradictory paths found:", "negative weights?") 

873 elif pred is not None and vu_dist == u_dist: 

874 # Found another shortest path to u with equal distance (including zero-weight edges). 

875 # We must store *all* predecessors because `pred` was provided by the caller. 

876 pred_dict[u].append(v) 

877 elif u not in seen or vu_dist < seen[u]: 

878 seen[u] = vu_dist 

879 heappush(fringe, (vu_dist, next(c), u)) 

880 if pred_dict is not None: 

881 pred_dict[u] = [v] 

882 elif pred is not None and vu_dist == seen[u]: 

883 # Found another shortest path to u 

884 # We must store *all* predecessors because `pred` was provided by the caller. 

885 pred_dict[u].append(v) 

886 

887 if paths is not None: 

888 # Reconstruct the path from source to target using the predecessor dictionary. 

889 if target is None: 

890 # Since `dist` is in increasing distance order, each predecessor's path is 

891 # already computed by the time we process `v`. We skip the first 

892 # `number_of_sources` entries because sources already have their paths defined. 

893 for v in islice(dist, number_of_sources, None): 

894 # `v` must be in `pred_dict`: any node with a distance (and not a source) 

895 # has a predecessor. 

896 paths[v] = paths[pred_dict[v][0]] + [v] 

897 else: 

898 # Caller requested the path to a specific target node. 

899 path = paths[target] = [target] 

900 while (current_preds := pred_dict.get(path[-1])) is not None: 

901 path.append(current_preds[0]) 

902 # The path was built in reverse order, so reverse it at the end. 

903 path.reverse() 

904 

905 # The optional predecessor and path dictionaries can be accessed 

906 # by the caller via the pred and paths objects passed as arguments. 

907 return dist 

908 

909 

910@nx._dispatchable(edge_attrs="weight") 

911def dijkstra_predecessor_and_distance(G, source, cutoff=None, weight="weight"): 

912 """Compute weighted shortest path length and predecessors. 

913 

914 Uses Dijkstra's Method to obtain the shortest weighted paths 

915 and return dictionaries of predecessors for each node and 

916 distance for each node from the `source`. 

917 

918 Parameters 

919 ---------- 

920 G : NetworkX graph 

921 

922 source : node label 

923 Starting node for path 

924 

925 cutoff : integer or float, optional 

926 Length (sum of edge weights) at which the search is stopped. 

927 If cutoff is provided, only return paths with summed weight <= cutoff. 

928 

929 weight : string or function 

930 If this is a string, then edge weights will be accessed via the 

931 edge attribute with this key (that is, the weight of the edge 

932 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

933 such edge attribute exists, the weight of the edge is assumed to 

934 be one. 

935 

936 If this is a function, the weight of an edge is the value 

937 returned by the function. The function must accept exactly three 

938 positional arguments: the two endpoints of an edge and the 

939 dictionary of edge attributes for that edge. The function must 

940 return a number or None to indicate a hidden edge. 

941 

942 Returns 

943 ------- 

944 pred, distance : dictionaries 

945 Returns two dictionaries representing a list of predecessors 

946 of a node and the distance to each node. 

947 

948 Raises 

949 ------ 

950 NodeNotFound 

951 If `source` is not in `G`. 

952 

953 Notes 

954 ----- 

955 Edge weight attributes must be numerical. 

956 Distances are calculated as sums of weighted edges traversed. 

957 

958 The list of predecessors contains more than one element only when 

959 there are more than one shortest paths to the key node. 

960 

961 Examples 

962 -------- 

963 >>> G = nx.path_graph(5, create_using=nx.DiGraph()) 

964 >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0) 

965 >>> sorted(pred.items()) 

966 [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] 

967 >>> sorted(dist.items()) 

968 [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] 

969 

970 >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0, 1) 

971 >>> sorted(pred.items()) 

972 [(0, []), (1, [0])] 

973 >>> sorted(dist.items()) 

974 [(0, 0), (1, 1)] 

975 """ 

976 if source not in G: 

977 raise nx.NodeNotFound(f"Node {source} is not found in the graph") 

978 weight = _weight_function(G, weight) 

979 pred = {source: []} # dictionary of predecessors 

980 return (pred, _dijkstra(G, source, weight, pred=pred, cutoff=cutoff)) 

981 

982 

983@nx._dispatchable(edge_attrs="weight") 

984def all_pairs_dijkstra(G, cutoff=None, weight="weight"): 

985 """Find shortest weighted paths and lengths between all nodes. 

986 

987 Parameters 

988 ---------- 

989 G : NetworkX graph 

990 

991 cutoff : integer or float, optional 

992 Length (sum of edge weights) at which the search is stopped. 

993 If cutoff is provided, only return paths with summed weight <= cutoff. 

994 

995 weight : string or function 

996 If this is a string, then edge weights will be accessed via the 

997 edge attribute with this key (that is, the weight of the edge 

998 joining `u` to `v` will be ``G.edge[u][v][weight]``). If no 

999 such edge attribute exists, the weight of the edge is assumed to 

1000 be one. 

1001 

1002 If this is a function, the weight of an edge is the value 

1003 returned by the function. The function must accept exactly three 

1004 positional arguments: the two endpoints of an edge and the 

1005 dictionary of edge attributes for that edge. The function must 

1006 return a number or None to indicate a hidden edge. 

1007 

1008 Yields 

1009 ------ 

1010 (node, (distance, path)) : (node obj, (dict, dict)) 

1011 Each source node has two associated dicts. The first holds distance 

1012 keyed by target and the second holds paths keyed by target. 

1013 (See single_source_dijkstra for the source/target node terminology.) 

1014 If desired you can apply `dict()` to this function to create a dict 

1015 keyed by source node to the two dicts. 

1016 

1017 Examples 

1018 -------- 

1019 >>> G = nx.path_graph(5) 

1020 >>> len_path = dict(nx.all_pairs_dijkstra(G)) 

1021 >>> len_path[3][0][1] 

1022 2 

1023 >>> for node in [0, 1, 2, 3, 4]: 

1024 ... print(f"3 - {node}: {len_path[3][0][node]}") 

1025 3 - 0: 3 

1026 3 - 1: 2 

1027 3 - 2: 1 

1028 3 - 3: 0 

1029 3 - 4: 1 

1030 >>> len_path[3][1][1] 

1031 [3, 2, 1] 

1032 >>> for n, (dist, path) in nx.all_pairs_dijkstra(G): 

1033 ... print(path[1]) 

1034 [0, 1] 

1035 [1] 

1036 [2, 1] 

1037 [3, 2, 1] 

1038 [4, 3, 2, 1] 

1039 

1040 Notes 

1041 ----- 

1042 Edge weight attributes must be numerical. 

1043 Distances are calculated as sums of weighted edges traversed. 

1044 

1045 The yielded dicts only have keys for reachable nodes. 

1046 """ 

1047 for n in G: 

1048 dist, path = single_source_dijkstra(G, n, cutoff=cutoff, weight=weight) 

1049 yield (n, (dist, path)) 

1050 

1051 

1052@nx._dispatchable(edge_attrs="weight") 

1053def all_pairs_dijkstra_path_length(G, cutoff=None, weight="weight"): 

1054 """Compute shortest path lengths between all nodes in a weighted graph. 

1055 

1056 Parameters 

1057 ---------- 

1058 G : NetworkX graph 

1059 

1060 cutoff : integer or float, optional 

1061 Length (sum of edge weights) at which the search is stopped. 

1062 If cutoff is provided, only return paths with summed weight <= cutoff. 

1063 

1064 weight : string or function 

1065 If this is a string, then edge weights will be accessed via the 

1066 edge attribute with this key (that is, the weight of the edge 

1067 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1068 such edge attribute exists, the weight of the edge is assumed to 

1069 be one. 

1070 

1071 If this is a function, the weight of an edge is the value 

1072 returned by the function. The function must accept exactly three 

1073 positional arguments: the two endpoints of an edge and the 

1074 dictionary of edge attributes for that edge. The function must 

1075 return a number or None to indicate a hidden edge. 

1076 

1077 Returns 

1078 ------- 

1079 distance : iterator 

1080 (source, dictionary) iterator with dictionary keyed by target and 

1081 shortest path length as the key value. 

1082 

1083 Examples 

1084 -------- 

1085 >>> G = nx.path_graph(5) 

1086 >>> length = dict(nx.all_pairs_dijkstra_path_length(G)) 

1087 >>> for node in [0, 1, 2, 3, 4]: 

1088 ... print(f"1 - {node}: {length[1][node]}") 

1089 1 - 0: 1 

1090 1 - 1: 0 

1091 1 - 2: 1 

1092 1 - 3: 2 

1093 1 - 4: 3 

1094 >>> length[3][2] 

1095 1 

1096 >>> length[2][2] 

1097 0 

1098 

1099 Notes 

1100 ----- 

1101 Edge weight attributes must be numerical. 

1102 Distances are calculated as sums of weighted edges traversed. 

1103 

1104 The dictionary returned only has keys for reachable node pairs. 

1105 """ 

1106 length = single_source_dijkstra_path_length 

1107 for n in G: 

1108 yield (n, length(G, n, cutoff=cutoff, weight=weight)) 

1109 

1110 

1111@nx._dispatchable(edge_attrs="weight") 

1112def all_pairs_dijkstra_path(G, cutoff=None, weight="weight"): 

1113 """Compute shortest paths between all nodes in a weighted graph. 

1114 

1115 Parameters 

1116 ---------- 

1117 G : NetworkX graph 

1118 

1119 cutoff : integer or float, optional 

1120 Length (sum of edge weights) at which the search is stopped. 

1121 If cutoff is provided, only return paths with summed weight <= cutoff. 

1122 

1123 weight : string or function 

1124 If this is a string, then edge weights will be accessed via the 

1125 edge attribute with this key (that is, the weight of the edge 

1126 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1127 such edge attribute exists, the weight of the edge is assumed to 

1128 be one. 

1129 

1130 If this is a function, the weight of an edge is the value 

1131 returned by the function. The function must accept exactly three 

1132 positional arguments: the two endpoints of an edge and the 

1133 dictionary of edge attributes for that edge. The function must 

1134 return a number or None to indicate a hidden edge. 

1135 

1136 Returns 

1137 ------- 

1138 paths : iterator 

1139 (source, dictionary) iterator with dictionary keyed by target and 

1140 shortest path as the key value. 

1141 

1142 Examples 

1143 -------- 

1144 >>> G = nx.path_graph(5) 

1145 >>> path = dict(nx.all_pairs_dijkstra_path(G)) 

1146 >>> path[0][4] 

1147 [0, 1, 2, 3, 4] 

1148 

1149 Notes 

1150 ----- 

1151 Edge weight attributes must be numerical. 

1152 Distances are calculated as sums of weighted edges traversed. 

1153 

1154 See Also 

1155 -------- 

1156 floyd_warshall, all_pairs_bellman_ford_path 

1157 

1158 """ 

1159 path = single_source_dijkstra_path 

1160 # TODO This can be trivially parallelized. 

1161 for n in G: 

1162 yield (n, path(G, n, cutoff=cutoff, weight=weight)) 

1163 

1164 

1165@nx._dispatchable(edge_attrs="weight") 

1166def bellman_ford_predecessor_and_distance( 

1167 G, source, target=None, weight="weight", heuristic=False 

1168): 

1169 """Compute shortest path lengths and predecessors on shortest paths 

1170 in weighted graphs. 

1171 

1172 The algorithm has a running time of $O(mn)$ where $n$ is the number of 

1173 nodes and $m$ is the number of edges. It is slower than Dijkstra but 

1174 can handle negative edge weights. 

1175 

1176 If a negative cycle is detected, you can use :func:`find_negative_cycle` 

1177 to return the cycle and examine it. Shortest paths are not defined when 

1178 a negative cycle exists because once reached, the path can cycle forever 

1179 to build up arbitrarily low weights. 

1180 

1181 Parameters 

1182 ---------- 

1183 G : NetworkX graph 

1184 The algorithm works for all types of graphs, including directed 

1185 graphs and multigraphs. 

1186 

1187 source: node label 

1188 Starting node for path 

1189 

1190 target : node label, optional 

1191 Ending node for path 

1192 

1193 weight : string or function 

1194 If this is a string, then edge weights will be accessed via the 

1195 edge attribute with this key (that is, the weight of the edge 

1196 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1197 such edge attribute exists, the weight of the edge is assumed to 

1198 be one. 

1199 

1200 If this is a function, the weight of an edge is the value 

1201 returned by the function. The function must accept exactly three 

1202 positional arguments: the two endpoints of an edge and the 

1203 dictionary of edge attributes for that edge. The function must 

1204 return a number. 

1205 

1206 heuristic : bool 

1207 Determines whether to use a heuristic to early detect negative 

1208 cycles at a hopefully negligible cost. 

1209 

1210 Returns 

1211 ------- 

1212 pred, dist : dictionaries 

1213 Returns two dictionaries keyed by node to predecessor in the 

1214 path and to the distance from the source respectively. 

1215 

1216 Raises 

1217 ------ 

1218 NodeNotFound 

1219 If `source` is not in `G`. 

1220 

1221 NetworkXUnbounded 

1222 If the (di)graph contains a negative (di)cycle, the 

1223 algorithm raises an exception to indicate the presence of the 

1224 negative (di)cycle. Note: any negative weight edge in an 

1225 undirected graph is a negative cycle. 

1226 

1227 Examples 

1228 -------- 

1229 >>> G = nx.path_graph(5, create_using=nx.DiGraph()) 

1230 >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0) 

1231 >>> sorted(pred.items()) 

1232 [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] 

1233 >>> sorted(dist.items()) 

1234 [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] 

1235 

1236 >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0, 1) 

1237 >>> sorted(pred.items()) 

1238 [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] 

1239 >>> sorted(dist.items()) 

1240 [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] 

1241 

1242 >>> G = nx.cycle_graph(5, create_using=nx.DiGraph()) 

1243 >>> G[1][2]["weight"] = -7 

1244 >>> nx.bellman_ford_predecessor_and_distance(G, 0) 

1245 Traceback (most recent call last): 

1246 ... 

1247 networkx.exception.NetworkXUnbounded: Negative cycle detected. 

1248 

1249 See Also 

1250 -------- 

1251 find_negative_cycle 

1252 

1253 Notes 

1254 ----- 

1255 Edge weight attributes must be numerical. 

1256 Distances are calculated as sums of weighted edges traversed. 

1257 

1258 The dictionaries returned only have keys for nodes reachable from 

1259 the source. 

1260 

1261 In the case where the (di)graph is not connected, if a component 

1262 not containing the source contains a negative (di)cycle, it 

1263 will not be detected. 

1264 

1265 In NetworkX v2.1 and prior, the source node had predecessor `[None]`. 

1266 In NetworkX v2.2 this changed to the source node having predecessor `[]` 

1267 """ 

1268 if source not in G: 

1269 raise nx.NodeNotFound(f"Node {source} is not found in the graph") 

1270 weight = _weight_function(G, weight) 

1271 if G.is_multigraph(): 

1272 if any( 

1273 weight(u, v, {k: d}) < 0 

1274 for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True) 

1275 ): 

1276 raise nx.NetworkXUnbounded("Negative cycle detected.") 

1277 else: 

1278 if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)): 

1279 raise nx.NetworkXUnbounded("Negative cycle detected.") 

1280 

1281 dist = {source: 0} 

1282 pred = {source: []} 

1283 

1284 if len(G) == 1: 

1285 return pred, dist 

1286 

1287 weight = _weight_function(G, weight) 

1288 

1289 dist = _bellman_ford( 

1290 G, [source], weight, pred=pred, dist=dist, target=target, heuristic=heuristic 

1291 ) 

1292 return (pred, dist) 

1293 

1294 

1295def _bellman_ford( 

1296 G, 

1297 source, 

1298 weight, 

1299 pred=None, 

1300 paths=None, 

1301 dist=None, 

1302 target=None, 

1303 heuristic=True, 

1304): 

1305 """Calls relaxation loop for Bellman–Ford algorithm and builds paths 

1306 

1307 This is an implementation of the SPFA variant. 

1308 See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm 

1309 

1310 Parameters 

1311 ---------- 

1312 G : NetworkX graph 

1313 

1314 source: list 

1315 List of source nodes. The shortest path from any of the source 

1316 nodes will be found if multiple sources are provided. 

1317 

1318 weight : function 

1319 The weight of an edge is the value returned by the function. The 

1320 function must accept exactly three positional arguments: the two 

1321 endpoints of an edge and the dictionary of edge attributes for 

1322 that edge. The function must return a number. 

1323 

1324 pred: dict of lists, optional (default=None) 

1325 dict to store a list of predecessors keyed by that node 

1326 If None, predecessors are not stored 

1327 

1328 paths: dict, optional (default=None) 

1329 dict to store the path list from source to each node, keyed by node 

1330 If None, paths are not stored 

1331 

1332 dist: dict, optional (default=None) 

1333 dict to store distance from source to the keyed node 

1334 If None, returned dist dict contents default to 0 for every node in the 

1335 source list 

1336 

1337 target: node label, optional 

1338 Ending node for path. Path lengths to other destinations may (and 

1339 probably will) be incorrect. 

1340 

1341 heuristic : bool 

1342 Determines whether to use a heuristic to early detect negative 

1343 cycles at a hopefully negligible cost. 

1344 

1345 Returns 

1346 ------- 

1347 dist : dict 

1348 Returns a dict keyed by node to the distance from the source. 

1349 Dicts for paths and pred are in the mutated input dicts by those names. 

1350 

1351 Raises 

1352 ------ 

1353 NodeNotFound 

1354 If any of `source` is not in `G`. 

1355 

1356 NetworkXUnbounded 

1357 If the (di)graph contains a negative (di)cycle, the 

1358 algorithm raises an exception to indicate the presence of the 

1359 negative (di)cycle. Note: any negative weight edge in an 

1360 undirected graph is a negative cycle 

1361 """ 

1362 if pred is None: 

1363 pred = {v: [] for v in source} 

1364 

1365 if dist is None: 

1366 dist = {v: 0 for v in source} 

1367 

1368 negative_cycle_found = _inner_bellman_ford( 

1369 G, 

1370 source, 

1371 weight, 

1372 pred, 

1373 dist, 

1374 heuristic, 

1375 ) 

1376 if negative_cycle_found is not None: 

1377 raise nx.NetworkXUnbounded("Negative cycle detected.") 

1378 

1379 if paths is not None: 

1380 sources = set(source) 

1381 dsts = [target] if target is not None else pred 

1382 for dst in dsts: 

1383 gen = _build_paths_from_predecessors(sources, dst, pred) 

1384 paths[dst] = next(gen) 

1385 

1386 return dist 

1387 

1388 

1389def _inner_bellman_ford( 

1390 G, 

1391 sources, 

1392 weight, 

1393 pred, 

1394 dist=None, 

1395 heuristic=True, 

1396): 

1397 """Inner Relaxation loop for Bellman–Ford algorithm. 

1398 

1399 This is an implementation of the SPFA variant. 

1400 See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm 

1401 

1402 Parameters 

1403 ---------- 

1404 G : NetworkX graph 

1405 

1406 source: list 

1407 List of source nodes. The shortest path from any of the source 

1408 nodes will be found if multiple sources are provided. 

1409 

1410 weight : function 

1411 The weight of an edge is the value returned by the function. The 

1412 function must accept exactly three positional arguments: the two 

1413 endpoints of an edge and the dictionary of edge attributes for 

1414 that edge. The function must return a number. 

1415 

1416 pred: dict of lists 

1417 dict to store a list of predecessors keyed by that node 

1418 

1419 dist: dict, optional (default=None) 

1420 dict to store distance from source to the keyed node 

1421 If None, returned dist dict contents default to 0 for every node in the 

1422 source list 

1423 

1424 heuristic : bool 

1425 Determines whether to use a heuristic to early detect negative 

1426 cycles at a hopefully negligible cost. 

1427 

1428 Returns 

1429 ------- 

1430 node or None 

1431 Return a node `v` where processing discovered a negative cycle. 

1432 If no negative cycle found, return None. 

1433 

1434 Raises 

1435 ------ 

1436 NodeNotFound 

1437 If any of `source` is not in `G`. 

1438 """ 

1439 for s in sources: 

1440 if s not in G: 

1441 raise nx.NodeNotFound(f"Source {s} not in G") 

1442 

1443 if pred is None: 

1444 pred = {v: [] for v in sources} 

1445 

1446 if dist is None: 

1447 dist = {v: 0 for v in sources} 

1448 

1449 # Heuristic Storage setup. Note: use None because nodes cannot be None 

1450 nonexistent_edge = (None, None) 

1451 pred_edge = {v: None for v in sources} 

1452 recent_update = {v: nonexistent_edge for v in sources} 

1453 

1454 G_succ = G._adj # For speed-up (and works for both directed and undirected graphs) 

1455 inf = float("inf") 

1456 n = len(G) 

1457 

1458 count = {} 

1459 q = deque(sources) 

1460 in_q = set(sources) 

1461 while q: 

1462 u = q.popleft() 

1463 in_q.remove(u) 

1464 

1465 # Skip relaxations if any of the predecessors of u is in the queue. 

1466 if all(pred_u not in in_q for pred_u in pred[u]): 

1467 dist_u = dist[u] 

1468 for v, e in G_succ[u].items(): 

1469 dist_v = dist_u + weight(u, v, e) 

1470 

1471 if dist_v < dist.get(v, inf): 

1472 # In this conditional branch we are updating the path with v. 

1473 # If it happens that some earlier update also added node v 

1474 # that implies the existence of a negative cycle since 

1475 # after the update node v would lie on the update path twice. 

1476 # The update path is stored up to one of the source nodes, 

1477 # therefore u is always in the dict recent_update 

1478 if heuristic: 

1479 if v in recent_update[u]: 

1480 # Negative cycle found! 

1481 pred[v].append(u) 

1482 return v 

1483 

1484 # Transfer the recent update info from u to v if the 

1485 # same source node is the head of the update path. 

1486 # If the source node is responsible for the cost update, 

1487 # then clear the history and use it instead. 

1488 if v in pred_edge and pred_edge[v] == u: 

1489 recent_update[v] = recent_update[u] 

1490 else: 

1491 recent_update[v] = (u, v) 

1492 

1493 if v not in in_q: 

1494 q.append(v) 

1495 in_q.add(v) 

1496 count_v = count.get(v, 0) + 1 

1497 if count_v == n: 

1498 # Negative cycle found! 

1499 return v 

1500 

1501 count[v] = count_v 

1502 dist[v] = dist_v 

1503 pred[v] = [u] 

1504 pred_edge[v] = u 

1505 

1506 elif dist.get(v) is not None and dist_v == dist.get(v): 

1507 pred[v].append(u) 

1508 

1509 # successfully found shortest_path. No negative cycles found. 

1510 return None 

1511 

1512 

1513@nx._dispatchable(edge_attrs="weight") 

1514def bellman_ford_path(G, source, target, weight="weight"): 

1515 """Returns the shortest path from source to target in a weighted graph G. 

1516 

1517 Parameters 

1518 ---------- 

1519 G : NetworkX graph 

1520 

1521 source : node 

1522 Starting node 

1523 

1524 target : node 

1525 Ending node 

1526 

1527 weight : string or function (default="weight") 

1528 If this is a string, then edge weights will be accessed via the 

1529 edge attribute with this key (that is, the weight of the edge 

1530 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1531 such edge attribute exists, the weight of the edge is assumed to 

1532 be one. 

1533 

1534 If this is a function, the weight of an edge is the value 

1535 returned by the function. The function must accept exactly three 

1536 positional arguments: the two endpoints of an edge and the 

1537 dictionary of edge attributes for that edge. The function must 

1538 return a number. 

1539 

1540 Returns 

1541 ------- 

1542 path : list 

1543 List of nodes in a shortest path. 

1544 

1545 Raises 

1546 ------ 

1547 NodeNotFound 

1548 If `source` is not in `G`. 

1549 

1550 NetworkXNoPath 

1551 If no path exists between source and target. 

1552 

1553 Examples 

1554 -------- 

1555 >>> G = nx.path_graph(5) 

1556 >>> nx.bellman_ford_path(G, 0, 4) 

1557 [0, 1, 2, 3, 4] 

1558 

1559 Notes 

1560 ----- 

1561 Edge weight attributes must be numerical. 

1562 Distances are calculated as sums of weighted edges traversed. 

1563 

1564 See Also 

1565 -------- 

1566 dijkstra_path, bellman_ford_path_length 

1567 """ 

1568 length, path = single_source_bellman_ford(G, source, target=target, weight=weight) 

1569 return path 

1570 

1571 

1572@nx._dispatchable(edge_attrs="weight") 

1573def bellman_ford_path_length(G, source, target, weight="weight"): 

1574 """Returns the shortest path length from source to target 

1575 in a weighted graph. 

1576 

1577 Parameters 

1578 ---------- 

1579 G : NetworkX graph 

1580 

1581 source : node label 

1582 starting node for path 

1583 

1584 target : node label 

1585 ending node for path 

1586 

1587 weight : string or function (default="weight") 

1588 If this is a string, then edge weights will be accessed via the 

1589 edge attribute with this key (that is, the weight of the edge 

1590 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1591 such edge attribute exists, the weight of the edge is assumed to 

1592 be one. 

1593 

1594 If this is a function, the weight of an edge is the value 

1595 returned by the function. The function must accept exactly three 

1596 positional arguments: the two endpoints of an edge and the 

1597 dictionary of edge attributes for that edge. The function must 

1598 return a number. 

1599 

1600 Returns 

1601 ------- 

1602 length : number 

1603 Shortest path length. 

1604 

1605 Raises 

1606 ------ 

1607 NodeNotFound 

1608 If `source` is not in `G`. 

1609 

1610 NetworkXNoPath 

1611 If no path exists between source and target. 

1612 

1613 Examples 

1614 -------- 

1615 >>> G = nx.path_graph(5) 

1616 >>> nx.bellman_ford_path_length(G, 0, 4) 

1617 4 

1618 

1619 Notes 

1620 ----- 

1621 Edge weight attributes must be numerical. 

1622 Distances are calculated as sums of weighted edges traversed. 

1623 

1624 See Also 

1625 -------- 

1626 dijkstra_path_length, bellman_ford_path 

1627 """ 

1628 if source == target: 

1629 if source not in G: 

1630 raise nx.NodeNotFound(f"Node {source} not found in graph") 

1631 return 0 

1632 

1633 weight = _weight_function(G, weight) 

1634 

1635 length = _bellman_ford(G, [source], weight, target=target) 

1636 

1637 try: 

1638 return length[target] 

1639 except KeyError as err: 

1640 raise nx.NetworkXNoPath(f"node {target} not reachable from {source}") from err 

1641 

1642 

1643@nx._dispatchable(edge_attrs="weight") 

1644def single_source_bellman_ford_path(G, source, weight="weight"): 

1645 """Compute shortest path between source and all other reachable 

1646 nodes for a weighted graph. 

1647 

1648 Parameters 

1649 ---------- 

1650 G : NetworkX graph 

1651 

1652 source : node 

1653 Starting node for path. 

1654 

1655 weight : string or function (default="weight") 

1656 If this is a string, then edge weights will be accessed via the 

1657 edge attribute with this key (that is, the weight of the edge 

1658 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1659 such edge attribute exists, the weight of the edge is assumed to 

1660 be one. 

1661 

1662 If this is a function, the weight of an edge is the value 

1663 returned by the function. The function must accept exactly three 

1664 positional arguments: the two endpoints of an edge and the 

1665 dictionary of edge attributes for that edge. The function must 

1666 return a number. 

1667 

1668 Returns 

1669 ------- 

1670 paths : dictionary 

1671 Dictionary of shortest path lengths keyed by target. 

1672 

1673 Raises 

1674 ------ 

1675 NodeNotFound 

1676 If `source` is not in `G`. 

1677 

1678 Examples 

1679 -------- 

1680 >>> G = nx.path_graph(5) 

1681 >>> path = nx.single_source_bellman_ford_path(G, 0) 

1682 >>> path[4] 

1683 [0, 1, 2, 3, 4] 

1684 

1685 Notes 

1686 ----- 

1687 Edge weight attributes must be numerical. 

1688 Distances are calculated as sums of weighted edges traversed. 

1689 

1690 See Also 

1691 -------- 

1692 single_source_dijkstra, single_source_bellman_ford 

1693 

1694 """ 

1695 (length, path) = single_source_bellman_ford(G, source, weight=weight) 

1696 return path 

1697 

1698 

1699@nx._dispatchable(edge_attrs="weight") 

1700def single_source_bellman_ford_path_length(G, source, weight="weight"): 

1701 """Compute the shortest path length between source and all other 

1702 reachable nodes for a weighted graph. 

1703 

1704 Parameters 

1705 ---------- 

1706 G : NetworkX graph 

1707 

1708 source : node label 

1709 Starting node for path 

1710 

1711 weight : string or function (default="weight") 

1712 If this is a string, then edge weights will be accessed via the 

1713 edge attribute with this key (that is, the weight of the edge 

1714 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1715 such edge attribute exists, the weight of the edge is assumed to 

1716 be one. 

1717 

1718 If this is a function, the weight of an edge is the value 

1719 returned by the function. The function must accept exactly three 

1720 positional arguments: the two endpoints of an edge and the 

1721 dictionary of edge attributes for that edge. The function must 

1722 return a number. 

1723 

1724 Returns 

1725 ------- 

1726 length : dictionary 

1727 Dictionary of shortest path length keyed by target 

1728 

1729 Raises 

1730 ------ 

1731 NodeNotFound 

1732 If `source` is not in `G`. 

1733 

1734 Examples 

1735 -------- 

1736 >>> G = nx.path_graph(5) 

1737 >>> length = nx.single_source_bellman_ford_path_length(G, 0) 

1738 >>> length[4] 

1739 4 

1740 >>> for node in [0, 1, 2, 3, 4]: 

1741 ... print(f"{node}: {length[node]}") 

1742 0: 0 

1743 1: 1 

1744 2: 2 

1745 3: 3 

1746 4: 4 

1747 

1748 Notes 

1749 ----- 

1750 Edge weight attributes must be numerical. 

1751 Distances are calculated as sums of weighted edges traversed. 

1752 

1753 See Also 

1754 -------- 

1755 single_source_dijkstra, single_source_bellman_ford 

1756 

1757 """ 

1758 weight = _weight_function(G, weight) 

1759 return _bellman_ford(G, [source], weight) 

1760 

1761 

1762@nx._dispatchable(edge_attrs="weight") 

1763def single_source_bellman_ford(G, source, target=None, weight="weight"): 

1764 """Compute shortest paths and lengths in a weighted graph G. 

1765 

1766 Uses Bellman-Ford algorithm for shortest paths. 

1767 

1768 Parameters 

1769 ---------- 

1770 G : NetworkX graph 

1771 

1772 source : node label 

1773 Starting node for path 

1774 

1775 target : node label, optional 

1776 Ending node for path 

1777 

1778 weight : string or function 

1779 If this is a string, then edge weights will be accessed via the 

1780 edge attribute with this key (that is, the weight of the edge 

1781 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1782 such edge attribute exists, the weight of the edge is assumed to 

1783 be one. 

1784 

1785 If this is a function, the weight of an edge is the value 

1786 returned by the function. The function must accept exactly three 

1787 positional arguments: the two endpoints of an edge and the 

1788 dictionary of edge attributes for that edge. The function must 

1789 return a number. 

1790 

1791 Returns 

1792 ------- 

1793 distance, path : pair of dictionaries, or numeric and list 

1794 If target is None, returns a tuple of two dictionaries keyed by node. 

1795 The first dictionary stores distance from one of the source nodes. 

1796 The second stores the path from one of the sources to that node. 

1797 If target is not None, returns a tuple of (distance, path) where 

1798 distance is the distance from source to target and path is a list 

1799 representing the path from source to target. 

1800 

1801 Raises 

1802 ------ 

1803 NodeNotFound 

1804 If `source` is not in `G`. 

1805 

1806 Examples 

1807 -------- 

1808 >>> G = nx.path_graph(5) 

1809 >>> length, path = nx.single_source_bellman_ford(G, 0) 

1810 >>> length[4] 

1811 4 

1812 >>> for node in [0, 1, 2, 3, 4]: 

1813 ... print(f"{node}: {length[node]}") 

1814 0: 0 

1815 1: 1 

1816 2: 2 

1817 3: 3 

1818 4: 4 

1819 >>> path[4] 

1820 [0, 1, 2, 3, 4] 

1821 >>> length, path = nx.single_source_bellman_ford(G, 0, 1) 

1822 >>> length 

1823 1 

1824 >>> path 

1825 [0, 1] 

1826 

1827 Notes 

1828 ----- 

1829 Edge weight attributes must be numerical. 

1830 Distances are calculated as sums of weighted edges traversed. 

1831 

1832 See Also 

1833 -------- 

1834 single_source_dijkstra 

1835 single_source_bellman_ford_path 

1836 single_source_bellman_ford_path_length 

1837 """ 

1838 if source == target: 

1839 if source not in G: 

1840 raise nx.NodeNotFound(f"Node {source} is not found in the graph") 

1841 return (0, [source]) 

1842 

1843 weight = _weight_function(G, weight) 

1844 

1845 paths = {source: [source]} # dictionary of paths 

1846 dist = _bellman_ford(G, [source], weight, paths=paths, target=target) 

1847 if target is None: 

1848 return (dist, paths) 

1849 try: 

1850 return (dist[target], paths[target]) 

1851 except KeyError as err: 

1852 msg = f"Node {target} not reachable from {source}" 

1853 raise nx.NetworkXNoPath(msg) from err 

1854 

1855 

1856@nx._dispatchable(edge_attrs="weight") 

1857def all_pairs_bellman_ford_path_length(G, weight="weight"): 

1858 """Compute shortest path lengths between all nodes in a weighted graph. 

1859 

1860 Parameters 

1861 ---------- 

1862 G : NetworkX graph 

1863 

1864 weight : string or function (default="weight") 

1865 If this is a string, then edge weights will be accessed via the 

1866 edge attribute with this key (that is, the weight of the edge 

1867 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1868 such edge attribute exists, the weight of the edge is assumed to 

1869 be one. 

1870 

1871 If this is a function, the weight of an edge is the value 

1872 returned by the function. The function must accept exactly three 

1873 positional arguments: the two endpoints of an edge and the 

1874 dictionary of edge attributes for that edge. The function must 

1875 return a number. 

1876 

1877 Returns 

1878 ------- 

1879 distance : iterator 

1880 (source, dictionary) iterator with dictionary keyed by target and 

1881 shortest path length as the key value. 

1882 

1883 Examples 

1884 -------- 

1885 >>> G = nx.path_graph(5) 

1886 >>> length = dict(nx.all_pairs_bellman_ford_path_length(G)) 

1887 >>> for node in [0, 1, 2, 3, 4]: 

1888 ... print(f"1 - {node}: {length[1][node]}") 

1889 1 - 0: 1 

1890 1 - 1: 0 

1891 1 - 2: 1 

1892 1 - 3: 2 

1893 1 - 4: 3 

1894 >>> length[3][2] 

1895 1 

1896 >>> length[2][2] 

1897 0 

1898 

1899 Notes 

1900 ----- 

1901 Edge weight attributes must be numerical. 

1902 Distances are calculated as sums of weighted edges traversed. 

1903 

1904 The dictionary returned only has keys for reachable node pairs. 

1905 """ 

1906 length = single_source_bellman_ford_path_length 

1907 for n in G: 

1908 yield (n, dict(length(G, n, weight=weight))) 

1909 

1910 

1911@nx._dispatchable(edge_attrs="weight") 

1912def all_pairs_bellman_ford_path(G, weight="weight"): 

1913 """Compute shortest paths between all nodes in a weighted graph. 

1914 

1915 Parameters 

1916 ---------- 

1917 G : NetworkX graph 

1918 

1919 weight : string or function (default="weight") 

1920 If this is a string, then edge weights will be accessed via the 

1921 edge attribute with this key (that is, the weight of the edge 

1922 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1923 such edge attribute exists, the weight of the edge is assumed to 

1924 be one. 

1925 

1926 If this is a function, the weight of an edge is the value 

1927 returned by the function. The function must accept exactly three 

1928 positional arguments: the two endpoints of an edge and the 

1929 dictionary of edge attributes for that edge. The function must 

1930 return a number. 

1931 

1932 Returns 

1933 ------- 

1934 paths : iterator 

1935 (source, dictionary) iterator with dictionary keyed by target and 

1936 shortest path as the key value. 

1937 

1938 Examples 

1939 -------- 

1940 >>> G = nx.path_graph(5) 

1941 >>> path = dict(nx.all_pairs_bellman_ford_path(G)) 

1942 >>> path[0][4] 

1943 [0, 1, 2, 3, 4] 

1944 

1945 Notes 

1946 ----- 

1947 Edge weight attributes must be numerical. 

1948 Distances are calculated as sums of weighted edges traversed. 

1949 

1950 See Also 

1951 -------- 

1952 floyd_warshall, all_pairs_dijkstra_path 

1953 

1954 """ 

1955 path = single_source_bellman_ford_path 

1956 for n in G: 

1957 yield (n, path(G, n, weight=weight)) 

1958 

1959 

1960@nx._dispatchable(edge_attrs="weight") 

1961def goldberg_radzik(G, source, weight="weight"): 

1962 """Compute shortest path lengths and predecessors on shortest paths 

1963 in weighted graphs. 

1964 

1965 The algorithm has a running time of $O(mn)$ where $n$ is the number of 

1966 nodes and $m$ is the number of edges. It is slower than Dijkstra but 

1967 can handle negative edge weights. 

1968 

1969 Parameters 

1970 ---------- 

1971 G : NetworkX graph 

1972 The algorithm works for all types of graphs, including directed 

1973 graphs and multigraphs. 

1974 

1975 source: node label 

1976 Starting node for path 

1977 

1978 weight : string or function 

1979 If this is a string, then edge weights will be accessed via the 

1980 edge attribute with this key (that is, the weight of the edge 

1981 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

1982 such edge attribute exists, the weight of the edge is assumed to 

1983 be one. 

1984 

1985 If this is a function, the weight of an edge is the value 

1986 returned by the function. The function must accept exactly three 

1987 positional arguments: the two endpoints of an edge and the 

1988 dictionary of edge attributes for that edge. The function must 

1989 return a number. 

1990 

1991 Returns 

1992 ------- 

1993 pred, dist : dictionaries 

1994 Returns two dictionaries keyed by node to predecessor in the 

1995 path and to the distance from the source respectively. 

1996 

1997 Raises 

1998 ------ 

1999 NodeNotFound 

2000 If `source` is not in `G`. 

2001 

2002 NetworkXUnbounded 

2003 If the (di)graph contains a negative (di)cycle, the 

2004 algorithm raises an exception to indicate the presence of the 

2005 negative (di)cycle. Note: any negative weight edge in an 

2006 undirected graph is a negative cycle. 

2007 

2008 As of NetworkX v3.2, a zero weight cycle is no longer 

2009 incorrectly reported as a negative weight cycle. 

2010 

2011 

2012 Examples 

2013 -------- 

2014 >>> G = nx.path_graph(5, create_using=nx.DiGraph()) 

2015 >>> pred, dist = nx.goldberg_radzik(G, 0) 

2016 >>> sorted(pred.items()) 

2017 [(0, None), (1, 0), (2, 1), (3, 2), (4, 3)] 

2018 >>> sorted(dist.items()) 

2019 [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] 

2020 

2021 >>> G = nx.cycle_graph(5, create_using=nx.DiGraph()) 

2022 >>> G[1][2]["weight"] = -7 

2023 >>> nx.goldberg_radzik(G, 0) 

2024 Traceback (most recent call last): 

2025 ... 

2026 networkx.exception.NetworkXUnbounded: Negative cycle detected. 

2027 

2028 Notes 

2029 ----- 

2030 Edge weight attributes must be numerical. 

2031 Distances are calculated as sums of weighted edges traversed. 

2032 

2033 The dictionaries returned only have keys for nodes reachable from 

2034 the source. 

2035 

2036 In the case where the (di)graph is not connected, if a component 

2037 not containing the source contains a negative (di)cycle, it 

2038 will not be detected. 

2039 

2040 """ 

2041 if source not in G: 

2042 raise nx.NodeNotFound(f"Node {source} is not found in the graph") 

2043 weight = _weight_function(G, weight) 

2044 if G.is_multigraph(): 

2045 if any( 

2046 weight(u, v, {k: d}) < 0 

2047 for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True) 

2048 ): 

2049 raise nx.NetworkXUnbounded("Negative cycle detected.") 

2050 else: 

2051 if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)): 

2052 raise nx.NetworkXUnbounded("Negative cycle detected.") 

2053 

2054 if len(G) == 1: 

2055 return {source: None}, {source: 0} 

2056 

2057 G_succ = G._adj # For speed-up (and works for both directed and undirected graphs) 

2058 

2059 inf = float("inf") 

2060 d = {u: inf for u in G} 

2061 d[source] = 0 

2062 pred = {source: None} 

2063 

2064 def topo_sort(relabeled): 

2065 """Topologically sort nodes relabeled in the previous round and detect 

2066 negative cycles. 

2067 """ 

2068 # List of nodes to scan in this round. Denoted by A in Goldberg and 

2069 # Radzik's paper. 

2070 to_scan = [] 

2071 # In the DFS in the loop below, neg_count records for each node the 

2072 # number of edges of negative reduced costs on the path from a DFS root 

2073 # to the node in the DFS forest. The reduced cost of an edge (u, v) is 

2074 # defined as d[u] + weight[u][v] - d[v]. 

2075 # 

2076 # neg_count also doubles as the DFS visit marker array. 

2077 neg_count = {} 

2078 for u in relabeled - neg_count.keys(): 

2079 d_u = d[u] 

2080 # Skip nodes without out-edges of negative reduced costs. 

2081 if all(d_u + weight(u, v, e) >= d[v] for v, e in G_succ[u].items()): 

2082 continue 

2083 # Nonrecursive DFS that inserts nodes reachable from u via edges of 

2084 # nonpositive reduced costs into to_scan in (reverse) topological 

2085 # order. 

2086 stack = [(u, iter(G_succ[u].items()))] 

2087 in_stack = {u} 

2088 neg_count[u] = 0 

2089 while stack: 

2090 u, it = stack[-1] 

2091 try: 

2092 v, e = next(it) 

2093 except StopIteration: 

2094 to_scan.append(u) 

2095 stack.pop() 

2096 in_stack.remove(u) 

2097 continue 

2098 t = d[u] + weight(u, v, e) 

2099 d_v = d[v] 

2100 if t < d_v: 

2101 d[v] = t 

2102 pred[v] = u 

2103 if v not in neg_count: 

2104 neg_count[v] = neg_count[u] + 1 

2105 stack.append((v, iter(G_succ[v].items()))) 

2106 in_stack.add(v) 

2107 elif v in in_stack and neg_count[u] + 1 > neg_count[v]: 

2108 # (u, v) is a back edge, and the cycle formed by the 

2109 # path v to u and (u, v) contains at least one edge of 

2110 # negative reduced cost. The cycle must be of negative 

2111 # cost. 

2112 raise nx.NetworkXUnbounded("Negative cycle detected.") 

2113 to_scan.reverse() 

2114 return to_scan 

2115 

2116 def relax(to_scan): 

2117 """Relax out-edges of relabeled nodes.""" 

2118 relabeled = set() 

2119 # Scan nodes in to_scan in topological order and relax incident 

2120 # out-edges. Add the relabeled nodes to labeled. 

2121 for u in to_scan: 

2122 d_u = d[u] 

2123 for v, e in G_succ[u].items(): 

2124 w_e = weight(u, v, e) 

2125 if d_u + w_e < d[v]: 

2126 d[v] = d_u + w_e 

2127 pred[v] = u 

2128 relabeled.add(v) 

2129 return relabeled 

2130 

2131 # Set of nodes relabeled in the last round of scan operations. Denoted by B 

2132 # in Goldberg and Radzik's paper. 

2133 relabeled = {source} 

2134 

2135 while relabeled: 

2136 to_scan = topo_sort(relabeled) 

2137 relabeled = relax(to_scan) 

2138 

2139 d = {u: d[u] for u in pred} 

2140 return pred, d 

2141 

2142 

2143@nx._dispatchable(edge_attrs="weight") 

2144def negative_edge_cycle(G, weight="weight", heuristic=True): 

2145 """Returns True if there exists a negative edge cycle anywhere in G. 

2146 

2147 Parameters 

2148 ---------- 

2149 G : NetworkX graph 

2150 

2151 weight : string or function 

2152 If this is a string, then edge weights will be accessed via the 

2153 edge attribute with this key (that is, the weight of the edge 

2154 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

2155 such edge attribute exists, the weight of the edge is assumed to 

2156 be one. 

2157 

2158 If this is a function, the weight of an edge is the value 

2159 returned by the function. The function must accept exactly three 

2160 positional arguments: the two endpoints of an edge and the 

2161 dictionary of edge attributes for that edge. The function must 

2162 return a number. 

2163 

2164 heuristic : bool 

2165 Determines whether to use a heuristic to early detect negative 

2166 cycles at a negligible cost. In case of graphs with a negative cycle, 

2167 the performance of detection increases by at least an order of magnitude. 

2168 

2169 Returns 

2170 ------- 

2171 negative_cycle : bool 

2172 True if a negative edge cycle exists, otherwise False. 

2173 

2174 Examples 

2175 -------- 

2176 >>> G = nx.cycle_graph(5, create_using=nx.DiGraph()) 

2177 >>> print(nx.negative_edge_cycle(G)) 

2178 False 

2179 >>> G[1][2]["weight"] = -7 

2180 >>> print(nx.negative_edge_cycle(G)) 

2181 True 

2182 

2183 Notes 

2184 ----- 

2185 Edge weight attributes must be numerical. 

2186 Distances are calculated as sums of weighted edges traversed. 

2187 

2188 This algorithm uses bellman_ford_predecessor_and_distance() but finds 

2189 negative cycles on any component by first adding a new node connected to 

2190 every node, and starting bellman_ford_predecessor_and_distance on that 

2191 node. It then removes that extra node. 

2192 """ 

2193 if G.size() == 0: 

2194 return False 

2195 

2196 # find unused node to use temporarily 

2197 newnode = -1 

2198 while newnode in G: 

2199 newnode -= 1 

2200 # connect it to all nodes 

2201 G.add_edges_from([(newnode, n) for n in G]) 

2202 

2203 try: 

2204 bellman_ford_predecessor_and_distance( 

2205 G, newnode, weight=weight, heuristic=heuristic 

2206 ) 

2207 except nx.NetworkXUnbounded: 

2208 return True 

2209 finally: 

2210 G.remove_node(newnode) 

2211 return False 

2212 

2213 

2214@nx._dispatchable(edge_attrs="weight") 

2215def find_negative_cycle(G, source, weight="weight"): 

2216 """Returns a cycle with negative total weight if it exists. 

2217 

2218 Bellman-Ford is used to find shortest_paths. That algorithm 

2219 stops if there exists a negative cycle. This algorithm 

2220 picks up from there and returns the found negative cycle. 

2221 

2222 The cycle consists of a list of nodes in the cycle order. The last 

2223 node equals the first to make it a cycle. 

2224 You can look up the edge weights in the original graph. In the case 

2225 of multigraphs the relevant edge is the minimal weight edge between 

2226 the nodes in the 2-tuple. 

2227 

2228 If the graph has no negative cycle, a NetworkXError is raised. 

2229 

2230 Parameters 

2231 ---------- 

2232 G : NetworkX graph 

2233 

2234 source: node label 

2235 The search for the negative cycle will start from this node. 

2236 

2237 weight : string or function 

2238 If this is a string, then edge weights will be accessed via the 

2239 edge attribute with this key (that is, the weight of the edge 

2240 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

2241 such edge attribute exists, the weight of the edge is assumed to 

2242 be one. 

2243 

2244 If this is a function, the weight of an edge is the value 

2245 returned by the function. The function must accept exactly three 

2246 positional arguments: the two endpoints of an edge and the 

2247 dictionary of edge attributes for that edge. The function must 

2248 return a number. 

2249 

2250 Examples 

2251 -------- 

2252 >>> G = nx.DiGraph() 

2253 >>> G.add_weighted_edges_from( 

2254 ... [(0, 1, 2), (1, 2, 2), (2, 0, 1), (1, 4, 2), (4, 0, -5)] 

2255 ... ) 

2256 >>> nx.find_negative_cycle(G, 0) 

2257 [4, 0, 1, 4] 

2258 

2259 Returns 

2260 ------- 

2261 cycle : list 

2262 A list of nodes in the order of the cycle found. The last node 

2263 equals the first to indicate a cycle. 

2264 

2265 Raises 

2266 ------ 

2267 NetworkXError 

2268 If no negative cycle is found. 

2269 """ 

2270 weight = _weight_function(G, weight) 

2271 pred = {source: []} 

2272 

2273 v = _inner_bellman_ford(G, [source], weight, pred=pred) 

2274 if v is None: 

2275 raise nx.NetworkXError("No negative cycles detected.") 

2276 

2277 # negative cycle detected... find it 

2278 neg_cycle = [] 

2279 stack = [(v, list(pred[v]))] 

2280 seen = {v} 

2281 while stack: 

2282 node, preds = stack[-1] 

2283 if v in preds: 

2284 # found the cycle 

2285 neg_cycle.extend([node, v]) 

2286 neg_cycle = list(reversed(neg_cycle)) 

2287 return neg_cycle 

2288 

2289 if preds: 

2290 nbr = preds.pop() 

2291 if nbr not in seen: 

2292 stack.append((nbr, list(pred[nbr]))) 

2293 neg_cycle.append(node) 

2294 seen.add(nbr) 

2295 else: 

2296 stack.pop() 

2297 if neg_cycle: 

2298 neg_cycle.pop() 

2299 else: 

2300 if v in G[v] and weight(G, v, v) < 0: 

2301 return [v, v] 

2302 # should not reach here 

2303 raise nx.NetworkXError("Negative cycle is detected but not found") 

2304 # should not get here... 

2305 msg = "negative cycle detected but not identified" 

2306 raise nx.NetworkXUnbounded(msg) 

2307 

2308 

2309@nx._dispatchable(edge_attrs="weight") 

2310def bidirectional_dijkstra(G, source, target, weight="weight"): 

2311 r"""Dijkstra's algorithm for shortest paths using bidirectional search. 

2312 

2313 Parameters 

2314 ---------- 

2315 G : NetworkX graph 

2316 

2317 source : node 

2318 Starting node. 

2319 

2320 target : node 

2321 Ending node. 

2322 

2323 weight : string or function 

2324 If this is a string, then edge weights will be accessed via the 

2325 edge attribute with this key (that is, the weight of the edge 

2326 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

2327 such edge attribute exists, the weight of the edge is assumed to 

2328 be one. 

2329 

2330 If this is a function, the weight of an edge is the value 

2331 returned by the function. The function must accept exactly three 

2332 positional arguments: the two endpoints of an edge and the 

2333 dictionary of edge attributes for that edge. The function must 

2334 return a number or None to indicate a hidden edge. 

2335 

2336 Returns 

2337 ------- 

2338 length, path : number and list 

2339 length is the distance from source to target. 

2340 path is a list of nodes on a path from source to target. 

2341 

2342 Raises 

2343 ------ 

2344 NodeNotFound 

2345 If `source` or `target` is not in `G`. 

2346 

2347 NetworkXNoPath 

2348 If no path exists between source and target. 

2349 

2350 Examples 

2351 -------- 

2352 >>> G = nx.path_graph(5) 

2353 >>> length, path = nx.bidirectional_dijkstra(G, 0, 4) 

2354 >>> print(length) 

2355 4 

2356 >>> print(path) 

2357 [0, 1, 2, 3, 4] 

2358 

2359 Notes 

2360 ----- 

2361 Edge weight attributes must be numerical. 

2362 Distances are calculated as sums of weighted edges traversed. 

2363 

2364 The weight function can be used to hide edges by returning None. 

2365 So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` 

2366 will find the shortest red path. 

2367 

2368 In practice bidirectional Dijkstra is much more than twice as fast as 

2369 ordinary Dijkstra. 

2370 

2371 Ordinary Dijkstra expands nodes in a sphere-like manner from the 

2372 source. The radius of this sphere will eventually be the length 

2373 of the shortest path. Bidirectional Dijkstra will expand nodes 

2374 from both the source and the target, making two spheres of half 

2375 this radius. Volume of the first sphere is `\pi*r*r` while the 

2376 others are `2*\pi*r/2*r/2`, making up half the volume. 

2377 

2378 This algorithm is not guaranteed to work if edge weights 

2379 are negative or are floating point numbers 

2380 (overflows and roundoff errors can cause problems). 

2381 

2382 See Also 

2383 -------- 

2384 shortest_path 

2385 shortest_path_length 

2386 """ 

2387 if source not in G: 

2388 raise nx.NodeNotFound(f"Source {source} is not in G") 

2389 

2390 if target not in G: 

2391 raise nx.NodeNotFound(f"Target {target} is not in G") 

2392 

2393 if source == target: 

2394 return (0, [source]) 

2395 

2396 weight = _weight_function(G, weight) 

2397 # Init: [Forward, Backward] 

2398 dists = [{}, {}] # dictionary of final distances 

2399 preds = [{source: None}, {target: None}] # dictionary of preds 

2400 

2401 def path(curr, direction): 

2402 ret = [] 

2403 while curr is not None: 

2404 ret.append(curr) 

2405 curr = preds[direction][curr] 

2406 return list(reversed(ret)) if direction == 0 else ret 

2407 

2408 fringe = [[], []] # heap of (distance, node) for choosing node to expand 

2409 seen = [{source: 0}, {target: 0}] # dict of distances to seen nodes 

2410 c = count() 

2411 # initialize fringe heap 

2412 heappush(fringe[0], (0, next(c), source)) 

2413 heappush(fringe[1], (0, next(c), target)) 

2414 # neighbors for extracting correct neighbor information 

2415 if G.is_directed(): 

2416 neighbors = [G._succ, G._pred] 

2417 else: 

2418 neighbors = [G._adj, G._adj] 

2419 # variables to hold shortest discovered path 

2420 finaldist = None 

2421 meetnode = None 

2422 direction = 1 

2423 while fringe[0] and fringe[1]: 

2424 # choose direction 

2425 # direction == 0 is forward direction and direction == 1 is back 

2426 direction = 1 - direction 

2427 # extract closest to expand 

2428 (dist, _, v) = heappop(fringe[direction]) 

2429 if v in dists[direction]: 

2430 # Shortest path to v has already been found 

2431 continue 

2432 # update distance 

2433 dists[direction][v] = dist # equal to seen[direction][v] 

2434 if v in dists[1 - direction]: 

2435 # if we have scanned v in both directions we are done 

2436 # we have now discovered the shortest path 

2437 return (finaldist, path(meetnode, 0) + path(preds[1][meetnode], 1)) 

2438 

2439 for w, d in neighbors[direction][v].items(): 

2440 # weight(v, w, d) for forward and weight(w, v, d) for back direction 

2441 cost = weight(v, w, d) if direction == 0 else weight(w, v, d) 

2442 if cost is None: 

2443 continue 

2444 vwLength = dist + cost 

2445 if w in dists[direction]: 

2446 if vwLength < dists[direction][w]: 

2447 raise ValueError("Contradictory paths found: negative weights?") 

2448 elif w not in seen[direction] or vwLength < seen[direction][w]: 

2449 # relaxing 

2450 seen[direction][w] = vwLength 

2451 heappush(fringe[direction], (vwLength, next(c), w)) 

2452 preds[direction][w] = v 

2453 if w in seen[1 - direction]: 

2454 # see if this path is better than the already 

2455 # discovered shortest path 

2456 finaldist_w = vwLength + seen[1 - direction][w] 

2457 if finaldist is None or finaldist > finaldist_w: 

2458 finaldist, meetnode = finaldist_w, w 

2459 raise nx.NetworkXNoPath(f"No path between {source} and {target}.") 

2460 

2461 

2462@nx._dispatchable(edge_attrs="weight") 

2463def johnson(G, weight="weight"): 

2464 r"""Uses Johnson's Algorithm to compute shortest paths. 

2465 

2466 Johnson's Algorithm finds a shortest path between each pair of 

2467 nodes in a weighted graph even if negative weights are present. 

2468 

2469 Parameters 

2470 ---------- 

2471 G : NetworkX graph 

2472 

2473 weight : string or function 

2474 If this is a string, then edge weights will be accessed via the 

2475 edge attribute with this key (that is, the weight of the edge 

2476 joining `u` to `v` will be ``G.edges[u, v][weight]``). If no 

2477 such edge attribute exists, the weight of the edge is assumed to 

2478 be one. 

2479 

2480 If this is a function, the weight of an edge is the value 

2481 returned by the function. The function must accept exactly three 

2482 positional arguments: the two endpoints of an edge and the 

2483 dictionary of edge attributes for that edge. The function must 

2484 return a number. 

2485 

2486 Returns 

2487 ------- 

2488 distance : dictionary 

2489 Dictionary, keyed by source and target, of shortest paths. 

2490 

2491 Examples 

2492 -------- 

2493 >>> graph = nx.DiGraph() 

2494 >>> graph.add_weighted_edges_from( 

2495 ... [("0", "3", 3), ("0", "1", -5), ("0", "2", 2), ("1", "2", 4), ("2", "3", 1)] 

2496 ... ) 

2497 >>> paths = nx.johnson(graph, weight="weight") 

2498 >>> paths["0"]["2"] 

2499 ['0', '1', '2'] 

2500 

2501 Notes 

2502 ----- 

2503 Johnson's algorithm is suitable even for graphs with negative weights. It 

2504 works by using the Bellman–Ford algorithm to compute a transformation of 

2505 the input graph that removes all negative weights, allowing Dijkstra's 

2506 algorithm to be used on the transformed graph. 

2507 

2508 The time complexity of this algorithm is $O(n^2 \log n + n m)$, 

2509 where $n$ is the number of nodes and $m$ the number of edges in the 

2510 graph. For dense graphs, this may be faster than the Floyd–Warshall 

2511 algorithm. 

2512 

2513 See Also 

2514 -------- 

2515 floyd_warshall_predecessor_and_distance 

2516 floyd_warshall_numpy 

2517 all_pairs_shortest_path 

2518 all_pairs_shortest_path_length 

2519 all_pairs_dijkstra_path 

2520 bellman_ford_predecessor_and_distance 

2521 all_pairs_bellman_ford_path 

2522 all_pairs_bellman_ford_path_length 

2523 

2524 """ 

2525 dist = {v: 0 for v in G} 

2526 pred = {v: [] for v in G} 

2527 weight = _weight_function(G, weight) 

2528 

2529 # Calculate distance of shortest paths 

2530 dist_bellman = _bellman_ford(G, list(G), weight, pred=pred, dist=dist) 

2531 

2532 # Update the weight function to take into account the Bellman--Ford 

2533 # relaxation distances. 

2534 def new_weight(u, v, d): 

2535 return weight(u, v, d) + dist_bellman[u] - dist_bellman[v] 

2536 

2537 def dist_path(v): 

2538 paths = {v: [v]} 

2539 _dijkstra(G, v, new_weight, paths=paths) 

2540 return paths 

2541 

2542 return {v: dist_path(v) for v in G}