Compute all-pairs shortest paths using Johnson's algorithm. Reference: https://en.wikipedia.org/wiki/Johnson%27s_algorithm Args: graph: adjacency list {u: [(v, weight), ...], ...} Returns: dict of dicts: dist[u][v] = shortest distance from u to v Rais
(graph: adjacency)
| 73 | |
| 74 | |
| 75 | def johnson(graph: adjacency) -> dict[Node, dict[Node, float]]: |
| 76 | """ |
| 77 | Compute all-pairs shortest paths using Johnson's algorithm. |
| 78 | |
| 79 | Reference: |
| 80 | https://en.wikipedia.org/wiki/Johnson%27s_algorithm |
| 81 | |
| 82 | Args: |
| 83 | graph: adjacency list {u: [(v, weight), ...], ...} |
| 84 | |
| 85 | Returns: |
| 86 | dict of dicts: dist[u][v] = shortest distance from u to v |
| 87 | |
| 88 | Raises: |
| 89 | ValueError: if a negative weight cycle is detected |
| 90 | |
| 91 | Example: |
| 92 | >>> g = { |
| 93 | ... 0: [(1, 3), (2, 8), (4, -4)], |
| 94 | ... 1: [(3, 1), (4, 7)], |
| 95 | ... 2: [(1, 4)], |
| 96 | ... 3: [(0, 2), (2, -5)], |
| 97 | ... 4: [(3, 6)], |
| 98 | ... } |
| 99 | >>> round(johnson(g)[0][3], 2) |
| 100 | 2.0 |
| 101 | """ |
| 102 | nodes, edges = _collect_nodes_and_edges(graph) |
| 103 | potentials = _bellman_ford(nodes, edges) |
| 104 | |
| 105 | all_pairs: dict[Node, dict[Node, float]] = {} |
| 106 | inf = float("inf") |
| 107 | for s in nodes: |
| 108 | dist_reweighted = _dijkstra(s, nodes, graph, potentials) |
| 109 | dists_orig: dict[Node, float] = {} |
| 110 | for v in nodes: |
| 111 | d_prime = dist_reweighted[v] |
| 112 | if d_prime < inf: |
| 113 | dists_orig[v] = d_prime - potentials[s] + potentials[v] |
| 114 | else: |
| 115 | dists_orig[v] = inf |
| 116 | all_pairs[s] = dists_orig |
| 117 | |
| 118 | return all_pairs |