aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/networkx/algorithms/shortest_paths/weighted.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/networkx/algorithms/shortest_paths/weighted.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/algorithms/shortest_paths/weighted.py')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/shortest_paths/weighted.py2520
1 files changed, 2520 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/shortest_paths/weighted.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/shortest_paths/weighted.py
new file mode 100644
index 00000000..f8421d42
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/shortest_paths/weighted.py
@@ -0,0 +1,2520 @@
+"""
+Shortest path algorithms for weighted graphs.
+"""
+
+from collections import deque
+from heapq import heappop, heappush
+from itertools import count
+
+import networkx as nx
+from networkx.algorithms.shortest_paths.generic import _build_paths_from_predecessors
+
+__all__ = [
+ "dijkstra_path",
+ "dijkstra_path_length",
+ "bidirectional_dijkstra",
+ "single_source_dijkstra",
+ "single_source_dijkstra_path",
+ "single_source_dijkstra_path_length",
+ "multi_source_dijkstra",
+ "multi_source_dijkstra_path",
+ "multi_source_dijkstra_path_length",
+ "all_pairs_dijkstra",
+ "all_pairs_dijkstra_path",
+ "all_pairs_dijkstra_path_length",
+ "dijkstra_predecessor_and_distance",
+ "bellman_ford_path",
+ "bellman_ford_path_length",
+ "single_source_bellman_ford",
+ "single_source_bellman_ford_path",
+ "single_source_bellman_ford_path_length",
+ "all_pairs_bellman_ford_path",
+ "all_pairs_bellman_ford_path_length",
+ "bellman_ford_predecessor_and_distance",
+ "negative_edge_cycle",
+ "find_negative_cycle",
+ "goldberg_radzik",
+ "johnson",
+]
+
+
+def _weight_function(G, weight):
+ """Returns a function that returns the weight of an edge.
+
+ The returned function is specifically suitable for input to
+ functions :func:`_dijkstra` and :func:`_bellman_ford_relaxation`.
+
+ Parameters
+ ----------
+ G : NetworkX graph.
+
+ weight : string or function
+ If it is callable, `weight` itself is returned. If it is a string,
+ it is assumed to be the name of the edge attribute that represents
+ the weight of an edge. In that case, a function is returned that
+ gets the edge weight according to the specified edge attribute.
+
+ Returns
+ -------
+ function
+ This function returns a callable that accepts exactly three inputs:
+ a node, an node adjacent to the first one, and the edge attribute
+ dictionary for the eedge joining those nodes. That function returns
+ a number representing the weight of an edge.
+
+ If `G` is a multigraph, and `weight` is not callable, the
+ minimum edge weight over all parallel edges is returned. If any edge
+ does not have an attribute with key `weight`, it is assumed to
+ have weight one.
+
+ """
+ if callable(weight):
+ return weight
+ # If the weight keyword argument is not callable, we assume it is a
+ # string representing the edge attribute containing the weight of
+ # the edge.
+ if G.is_multigraph():
+ return lambda u, v, d: min(attr.get(weight, 1) for attr in d.values())
+ return lambda u, v, data: data.get(weight, 1)
+
+
+@nx._dispatchable(edge_attrs="weight")
+def dijkstra_path(G, source, target, weight="weight"):
+ """Returns the shortest weighted path from source to target in G.
+
+ Uses Dijkstra's Method to compute the shortest weighted path
+ between two nodes in a graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node
+ Starting node
+
+ target : node
+ Ending node
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ path : list
+ List of nodes in a shortest path.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ NetworkXNoPath
+ If no path exists between source and target.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> print(nx.dijkstra_path(G, 0, 4))
+ [0, 1, 2, 3, 4]
+
+ Find edges of shortest path in Multigraph
+
+ >>> G = nx.MultiDiGraph()
+ >>> G.add_weighted_edges_from([(1, 2, 0.75), (1, 2, 0.5), (2, 3, 0.5), (1, 3, 1.5)])
+ >>> nodes = nx.dijkstra_path(G, 1, 3)
+ >>> edges = nx.utils.pairwise(nodes)
+ >>> list(
+ ... (u, v, min(G[u][v], key=lambda k: G[u][v][k].get("weight", 1)))
+ ... for u, v in edges
+ ... )
+ [(1, 2, 1), (2, 3, 0)]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ The weight function can be used to include node weights.
+
+ >>> def func(u, v, d):
+ ... node_u_wt = G.nodes[u].get("node_weight", 1)
+ ... node_v_wt = G.nodes[v].get("node_weight", 1)
+ ... edge_wt = d.get("weight", 1)
+ ... return node_u_wt / 2 + node_v_wt / 2 + edge_wt
+
+ In this example we take the average of start and end node
+ weights of an edge and add it to the weight of the edge.
+
+ The function :func:`single_source_dijkstra` computes both
+ path and length-of-path if you need both, use that.
+
+ See Also
+ --------
+ bidirectional_dijkstra
+ bellman_ford_path
+ single_source_dijkstra
+ """
+ (length, path) = single_source_dijkstra(G, source, target=target, weight=weight)
+ return path
+
+
+@nx._dispatchable(edge_attrs="weight")
+def dijkstra_path_length(G, source, target, weight="weight"):
+ """Returns the shortest weighted path length in G from source to target.
+
+ Uses Dijkstra's Method to compute the shortest weighted path length
+ between two nodes in a graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node label
+ starting node for path
+
+ target : node label
+ ending node for path
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ length : number
+ Shortest path length.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ NetworkXNoPath
+ If no path exists between source and target.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> nx.dijkstra_path_length(G, 0, 4)
+ 4
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ The function :func:`single_source_dijkstra` computes both
+ path and length-of-path if you need both, use that.
+
+ See Also
+ --------
+ bidirectional_dijkstra
+ bellman_ford_path_length
+ single_source_dijkstra
+
+ """
+ if source not in G:
+ raise nx.NodeNotFound(f"Node {source} not found in graph")
+ if source == target:
+ return 0
+ weight = _weight_function(G, weight)
+ length = _dijkstra(G, source, weight, target=target)
+ try:
+ return length[target]
+ except KeyError as err:
+ raise nx.NetworkXNoPath(f"Node {target} not reachable from {source}") from err
+
+
+@nx._dispatchable(edge_attrs="weight")
+def single_source_dijkstra_path(G, source, cutoff=None, weight="weight"):
+ """Find shortest weighted paths in G from a source node.
+
+ Compute shortest path between source and all other reachable
+ nodes for a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node
+ Starting node for path.
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ paths : dictionary
+ Dictionary of shortest path lengths keyed by target.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> path = nx.single_source_dijkstra_path(G, 0)
+ >>> path[4]
+ [0, 1, 2, 3, 4]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ See Also
+ --------
+ single_source_dijkstra, single_source_bellman_ford
+
+ """
+ return multi_source_dijkstra_path(G, {source}, cutoff=cutoff, weight=weight)
+
+
+@nx._dispatchable(edge_attrs="weight")
+def single_source_dijkstra_path_length(G, source, cutoff=None, weight="weight"):
+ """Find shortest weighted path lengths in G from a source node.
+
+ Compute the shortest path length between source and all other
+ reachable nodes for a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node label
+ Starting node for path
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ length : dict
+ Dict keyed by node to shortest path length from source.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length = nx.single_source_dijkstra_path_length(G, 0)
+ >>> length[4]
+ 4
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"{node}: {length[node]}")
+ 0: 0
+ 1: 1
+ 2: 2
+ 3: 3
+ 4: 4
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ See Also
+ --------
+ single_source_dijkstra, single_source_bellman_ford_path_length
+
+ """
+ return multi_source_dijkstra_path_length(G, {source}, cutoff=cutoff, weight=weight)
+
+
+@nx._dispatchable(edge_attrs="weight")
+def single_source_dijkstra(G, source, target=None, cutoff=None, weight="weight"):
+ """Find shortest weighted paths and lengths from a source node.
+
+ Compute the shortest path length between source and all other
+ reachable nodes for a weighted graph.
+
+ Uses Dijkstra's algorithm to compute shortest paths and lengths
+ between a source and all other reachable nodes in a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node label
+ Starting node for path
+
+ target : node label, optional
+ Ending node for path
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ distance, path : pair of dictionaries, or numeric and list.
+ If target is None, paths and lengths to all nodes are computed.
+ The return value is a tuple of two dictionaries keyed by target nodes.
+ The first dictionary stores distance to each target node.
+ The second stores the path to each target node.
+ If target is not None, returns a tuple (distance, path), where
+ distance is the distance from source to target and path is a list
+ representing the path from source to target.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length, path = nx.single_source_dijkstra(G, 0)
+ >>> length[4]
+ 4
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"{node}: {length[node]}")
+ 0: 0
+ 1: 1
+ 2: 2
+ 3: 3
+ 4: 4
+ >>> path[4]
+ [0, 1, 2, 3, 4]
+ >>> length, path = nx.single_source_dijkstra(G, 0, 1)
+ >>> length
+ 1
+ >>> path
+ [0, 1]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ Based on the Python cookbook recipe (119466) at
+ https://code.activestate.com/recipes/119466/
+
+ This algorithm is not guaranteed to work if edge weights
+ are negative or are floating point numbers
+ (overflows and roundoff errors can cause problems).
+
+ See Also
+ --------
+ single_source_dijkstra_path
+ single_source_dijkstra_path_length
+ single_source_bellman_ford
+ """
+ return multi_source_dijkstra(
+ G, {source}, cutoff=cutoff, target=target, weight=weight
+ )
+
+
+@nx._dispatchable(edge_attrs="weight")
+def multi_source_dijkstra_path(G, sources, cutoff=None, weight="weight"):
+ """Find shortest weighted paths in G from a given set of source
+ nodes.
+
+ Compute shortest path between any of the source nodes and all other
+ reachable nodes for a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ sources : non-empty set of nodes
+ Starting nodes for paths. If this is just a set containing a
+ single node, then all paths computed by this function will start
+ from that node. If there are two or more nodes in the set, the
+ computed paths may begin from any one of the start nodes.
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ paths : dictionary
+ Dictionary of shortest paths keyed by target.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> path = nx.multi_source_dijkstra_path(G, {0, 4})
+ >>> path[1]
+ [0, 1]
+ >>> path[3]
+ [4, 3]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ Raises
+ ------
+ ValueError
+ If `sources` is empty.
+ NodeNotFound
+ If any of `sources` is not in `G`.
+
+ See Also
+ --------
+ multi_source_dijkstra, multi_source_bellman_ford
+
+ """
+ length, path = multi_source_dijkstra(G, sources, cutoff=cutoff, weight=weight)
+ return path
+
+
+@nx._dispatchable(edge_attrs="weight")
+def multi_source_dijkstra_path_length(G, sources, cutoff=None, weight="weight"):
+ """Find shortest weighted path lengths in G from a given set of
+ source nodes.
+
+ Compute the shortest path length between any of the source nodes and
+ all other reachable nodes for a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ sources : non-empty set of nodes
+ Starting nodes for paths. If this is just a set containing a
+ single node, then all paths computed by this function will start
+ from that node. If there are two or more nodes in the set, the
+ computed paths may begin from any one of the start nodes.
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ length : dict
+ Dict keyed by node to shortest path length to nearest source.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length = nx.multi_source_dijkstra_path_length(G, {0, 4})
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"{node}: {length[node]}")
+ 0: 0
+ 1: 1
+ 2: 2
+ 3: 1
+ 4: 0
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ Raises
+ ------
+ ValueError
+ If `sources` is empty.
+ NodeNotFound
+ If any of `sources` is not in `G`.
+
+ See Also
+ --------
+ multi_source_dijkstra
+
+ """
+ if not sources:
+ raise ValueError("sources must not be empty")
+ for s in sources:
+ if s not in G:
+ raise nx.NodeNotFound(f"Node {s} not found in graph")
+ weight = _weight_function(G, weight)
+ return _dijkstra_multisource(G, sources, weight, cutoff=cutoff)
+
+
+@nx._dispatchable(edge_attrs="weight")
+def multi_source_dijkstra(G, sources, target=None, cutoff=None, weight="weight"):
+ """Find shortest weighted paths and lengths from a given set of
+ source nodes.
+
+ Uses Dijkstra's algorithm to compute the shortest paths and lengths
+ between one of the source nodes and the given `target`, or all other
+ reachable nodes if not specified, for a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ sources : non-empty set of nodes
+ Starting nodes for paths. If this is just a set containing a
+ single node, then all paths computed by this function will start
+ from that node. If there are two or more nodes in the set, the
+ computed paths may begin from any one of the start nodes.
+
+ target : node label, optional
+ Ending node for path
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ distance, path : pair of dictionaries, or numeric and list
+ If target is None, returns a tuple of two dictionaries keyed by node.
+ The first dictionary stores distance from one of the source nodes.
+ The second stores the path from one of the sources to that node.
+ If target is not None, returns a tuple of (distance, path) where
+ distance is the distance from source to target and path is a list
+ representing the path from source to target.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length, path = nx.multi_source_dijkstra(G, {0, 4})
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"{node}: {length[node]}")
+ 0: 0
+ 1: 1
+ 2: 2
+ 3: 1
+ 4: 0
+ >>> path[1]
+ [0, 1]
+ >>> path[3]
+ [4, 3]
+
+ >>> length, path = nx.multi_source_dijkstra(G, {0, 4}, 1)
+ >>> length
+ 1
+ >>> path
+ [0, 1]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ Based on the Python cookbook recipe (119466) at
+ https://code.activestate.com/recipes/119466/
+
+ This algorithm is not guaranteed to work if edge weights
+ are negative or are floating point numbers
+ (overflows and roundoff errors can cause problems).
+
+ Raises
+ ------
+ ValueError
+ If `sources` is empty.
+ NodeNotFound
+ If any of `sources` is not in `G`.
+
+ See Also
+ --------
+ multi_source_dijkstra_path
+ multi_source_dijkstra_path_length
+
+ """
+ if not sources:
+ raise ValueError("sources must not be empty")
+ for s in sources:
+ if s not in G:
+ raise nx.NodeNotFound(f"Node {s} not found in graph")
+ if target in sources:
+ return (0, [target])
+ weight = _weight_function(G, weight)
+ paths = {source: [source] for source in sources} # dictionary of paths
+ dist = _dijkstra_multisource(
+ G, sources, weight, paths=paths, cutoff=cutoff, target=target
+ )
+ if target is None:
+ return (dist, paths)
+ try:
+ return (dist[target], paths[target])
+ except KeyError as err:
+ raise nx.NetworkXNoPath(f"No path to {target}.") from err
+
+
+def _dijkstra(G, source, weight, pred=None, paths=None, cutoff=None, target=None):
+ """Uses Dijkstra's algorithm to find shortest weighted paths from a
+ single source.
+
+ This is a convenience function for :func:`_dijkstra_multisource`
+ with all the arguments the same, except the keyword argument
+ `sources` set to ``[source]``.
+
+ """
+ return _dijkstra_multisource(
+ G, [source], weight, pred=pred, paths=paths, cutoff=cutoff, target=target
+ )
+
+
+def _dijkstra_multisource(
+ G, sources, weight, pred=None, paths=None, cutoff=None, target=None
+):
+ """Uses Dijkstra's algorithm to find shortest weighted paths
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ sources : non-empty iterable of nodes
+ Starting nodes for paths. If this is just an iterable containing
+ a single node, then all paths computed by this function will
+ start from that node. If there are two or more nodes in this
+ iterable, the computed paths may begin from any one of the start
+ nodes.
+
+ weight: function
+ Function with (u, v, data) input that returns that edge's weight
+ or None to indicate a hidden edge
+
+ pred: dict of lists, optional(default=None)
+ dict to store a list of predecessors keyed by that node
+ If None, predecessors are not stored.
+
+ paths: dict, optional (default=None)
+ dict to store the path list from source to each node, keyed by node.
+ If None, paths are not stored.
+
+ target : node label, optional
+ Ending node for path. Search is halted when target is found.
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ Returns
+ -------
+ distance : dictionary
+ A mapping from node to shortest distance to that node from one
+ of the source nodes.
+
+ Raises
+ ------
+ NodeNotFound
+ If any of `sources` is not in `G`.
+
+ Notes
+ -----
+ The optional predecessor and path dictionaries can be accessed by
+ the caller through the original pred and paths objects passed
+ as arguments. No need to explicitly return pred or paths.
+
+ """
+ G_succ = G._adj # For speed-up (and works for both directed and undirected graphs)
+
+ push = heappush
+ pop = heappop
+ dist = {} # dictionary of final distances
+ seen = {}
+ # fringe is heapq with 3-tuples (distance,c,node)
+ # use the count c to avoid comparing nodes (may not be able to)
+ c = count()
+ fringe = []
+ for source in sources:
+ seen[source] = 0
+ push(fringe, (0, next(c), source))
+ while fringe:
+ (d, _, v) = pop(fringe)
+ if v in dist:
+ continue # already searched this node.
+ dist[v] = d
+ if v == target:
+ break
+ for u, e in G_succ[v].items():
+ cost = weight(v, u, e)
+ if cost is None:
+ continue
+ vu_dist = dist[v] + cost
+ if cutoff is not None:
+ if vu_dist > cutoff:
+ continue
+ if u in dist:
+ u_dist = dist[u]
+ if vu_dist < u_dist:
+ raise ValueError("Contradictory paths found:", "negative weights?")
+ elif pred is not None and vu_dist == u_dist:
+ pred[u].append(v)
+ elif u not in seen or vu_dist < seen[u]:
+ seen[u] = vu_dist
+ push(fringe, (vu_dist, next(c), u))
+ if paths is not None:
+ paths[u] = paths[v] + [u]
+ if pred is not None:
+ pred[u] = [v]
+ elif vu_dist == seen[u]:
+ if pred is not None:
+ pred[u].append(v)
+
+ # The optional predecessor and path dictionaries can be accessed
+ # by the caller via the pred and paths objects passed as arguments.
+ return dist
+
+
+@nx._dispatchable(edge_attrs="weight")
+def dijkstra_predecessor_and_distance(G, source, cutoff=None, weight="weight"):
+ """Compute weighted shortest path length and predecessors.
+
+ Uses Dijkstra's Method to obtain the shortest weighted paths
+ and return dictionaries of predecessors for each node and
+ distance for each node from the `source`.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node label
+ Starting node for path
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ pred, distance : dictionaries
+ Returns two dictionaries representing a list of predecessors
+ of a node and the distance to each node.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The list of predecessors contains more than one element only when
+ there are more than one shortest paths to the key node.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5, create_using=nx.DiGraph())
+ >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0)
+ >>> sorted(pred.items())
+ [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])]
+ >>> sorted(dist.items())
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
+
+ >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0, 1)
+ >>> sorted(pred.items())
+ [(0, []), (1, [0])]
+ >>> sorted(dist.items())
+ [(0, 0), (1, 1)]
+ """
+ if source not in G:
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
+ weight = _weight_function(G, weight)
+ pred = {source: []} # dictionary of predecessors
+ return (pred, _dijkstra(G, source, weight, pred=pred, cutoff=cutoff))
+
+
+@nx._dispatchable(edge_attrs="weight")
+def all_pairs_dijkstra(G, cutoff=None, weight="weight"):
+ """Find shortest weighted paths and lengths between all nodes.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edge[u][v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Yields
+ ------
+ (node, (distance, path)) : (node obj, (dict, dict))
+ Each source node has two associated dicts. The first holds distance
+ keyed by target and the second holds paths keyed by target.
+ (See single_source_dijkstra for the source/target node terminology.)
+ If desired you can apply `dict()` to this function to create a dict
+ keyed by source node to the two dicts.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> len_path = dict(nx.all_pairs_dijkstra(G))
+ >>> len_path[3][0][1]
+ 2
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"3 - {node}: {len_path[3][0][node]}")
+ 3 - 0: 3
+ 3 - 1: 2
+ 3 - 2: 1
+ 3 - 3: 0
+ 3 - 4: 1
+ >>> len_path[3][1][1]
+ [3, 2, 1]
+ >>> for n, (dist, path) in nx.all_pairs_dijkstra(G):
+ ... print(path[1])
+ [0, 1]
+ [1]
+ [2, 1]
+ [3, 2, 1]
+ [4, 3, 2, 1]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The yielded dicts only have keys for reachable nodes.
+ """
+ for n in G:
+ dist, path = single_source_dijkstra(G, n, cutoff=cutoff, weight=weight)
+ yield (n, (dist, path))
+
+
+@nx._dispatchable(edge_attrs="weight")
+def all_pairs_dijkstra_path_length(G, cutoff=None, weight="weight"):
+ """Compute shortest path lengths between all nodes in a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ distance : iterator
+ (source, dictionary) iterator with dictionary keyed by target and
+ shortest path length as the key value.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length = dict(nx.all_pairs_dijkstra_path_length(G))
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"1 - {node}: {length[1][node]}")
+ 1 - 0: 1
+ 1 - 1: 0
+ 1 - 2: 1
+ 1 - 3: 2
+ 1 - 4: 3
+ >>> length[3][2]
+ 1
+ >>> length[2][2]
+ 0
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The dictionary returned only has keys for reachable node pairs.
+ """
+ length = single_source_dijkstra_path_length
+ for n in G:
+ yield (n, length(G, n, cutoff=cutoff, weight=weight))
+
+
+@nx._dispatchable(edge_attrs="weight")
+def all_pairs_dijkstra_path(G, cutoff=None, weight="weight"):
+ """Compute shortest paths between all nodes in a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ cutoff : integer or float, optional
+ Length (sum of edge weights) at which the search is stopped.
+ If cutoff is provided, only return paths with summed weight <= cutoff.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ paths : iterator
+ (source, dictionary) iterator with dictionary keyed by target and
+ shortest path as the key value.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> path = dict(nx.all_pairs_dijkstra_path(G))
+ >>> path[0][4]
+ [0, 1, 2, 3, 4]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ See Also
+ --------
+ floyd_warshall, all_pairs_bellman_ford_path
+
+ """
+ path = single_source_dijkstra_path
+ # TODO This can be trivially parallelized.
+ for n in G:
+ yield (n, path(G, n, cutoff=cutoff, weight=weight))
+
+
+@nx._dispatchable(edge_attrs="weight")
+def bellman_ford_predecessor_and_distance(
+ G, source, target=None, weight="weight", heuristic=False
+):
+ """Compute shortest path lengths and predecessors on shortest paths
+ in weighted graphs.
+
+ The algorithm has a running time of $O(mn)$ where $n$ is the number of
+ nodes and $m$ is the number of edges. It is slower than Dijkstra but
+ can handle negative edge weights.
+
+ If a negative cycle is detected, you can use :func:`find_negative_cycle`
+ to return the cycle and examine it. Shortest paths are not defined when
+ a negative cycle exists because once reached, the path can cycle forever
+ to build up arbitrarily low weights.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+ The algorithm works for all types of graphs, including directed
+ graphs and multigraphs.
+
+ source: node label
+ Starting node for path
+
+ target : node label, optional
+ Ending node for path
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ heuristic : bool
+ Determines whether to use a heuristic to early detect negative
+ cycles at a hopefully negligible cost.
+
+ Returns
+ -------
+ pred, dist : dictionaries
+ Returns two dictionaries keyed by node to predecessor in the
+ path and to the distance from the source respectively.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ NetworkXUnbounded
+ If the (di)graph contains a negative (di)cycle, the
+ algorithm raises an exception to indicate the presence of the
+ negative (di)cycle. Note: any negative weight edge in an
+ undirected graph is a negative cycle.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5, create_using=nx.DiGraph())
+ >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0)
+ >>> sorted(pred.items())
+ [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])]
+ >>> sorted(dist.items())
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
+
+ >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0, 1)
+ >>> sorted(pred.items())
+ [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])]
+ >>> sorted(dist.items())
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
+
+ >>> G = nx.cycle_graph(5, create_using=nx.DiGraph())
+ >>> G[1][2]["weight"] = -7
+ >>> nx.bellman_ford_predecessor_and_distance(G, 0)
+ Traceback (most recent call last):
+ ...
+ networkx.exception.NetworkXUnbounded: Negative cycle detected.
+
+ See Also
+ --------
+ find_negative_cycle
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The dictionaries returned only have keys for nodes reachable from
+ the source.
+
+ In the case where the (di)graph is not connected, if a component
+ not containing the source contains a negative (di)cycle, it
+ will not be detected.
+
+ In NetworkX v2.1 and prior, the source node had predecessor `[None]`.
+ In NetworkX v2.2 this changed to the source node having predecessor `[]`
+ """
+ if source not in G:
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
+ weight = _weight_function(G, weight)
+ if G.is_multigraph():
+ if any(
+ weight(u, v, {k: d}) < 0
+ for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True)
+ ):
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
+ else:
+ if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)):
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
+
+ dist = {source: 0}
+ pred = {source: []}
+
+ if len(G) == 1:
+ return pred, dist
+
+ weight = _weight_function(G, weight)
+
+ dist = _bellman_ford(
+ G, [source], weight, pred=pred, dist=dist, target=target, heuristic=heuristic
+ )
+ return (pred, dist)
+
+
+def _bellman_ford(
+ G,
+ source,
+ weight,
+ pred=None,
+ paths=None,
+ dist=None,
+ target=None,
+ heuristic=True,
+):
+ """Calls relaxation loop for Bellman–Ford algorithm and builds paths
+
+ This is an implementation of the SPFA variant.
+ See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source: list
+ List of source nodes. The shortest path from any of the source
+ nodes will be found if multiple sources are provided.
+
+ weight : function
+ The weight of an edge is the value returned by the function. The
+ function must accept exactly three positional arguments: the two
+ endpoints of an edge and the dictionary of edge attributes for
+ that edge. The function must return a number.
+
+ pred: dict of lists, optional (default=None)
+ dict to store a list of predecessors keyed by that node
+ If None, predecessors are not stored
+
+ paths: dict, optional (default=None)
+ dict to store the path list from source to each node, keyed by node
+ If None, paths are not stored
+
+ dist: dict, optional (default=None)
+ dict to store distance from source to the keyed node
+ If None, returned dist dict contents default to 0 for every node in the
+ source list
+
+ target: node label, optional
+ Ending node for path. Path lengths to other destinations may (and
+ probably will) be incorrect.
+
+ heuristic : bool
+ Determines whether to use a heuristic to early detect negative
+ cycles at a hopefully negligible cost.
+
+ Returns
+ -------
+ dist : dict
+ Returns a dict keyed by node to the distance from the source.
+ Dicts for paths and pred are in the mutated input dicts by those names.
+
+ Raises
+ ------
+ NodeNotFound
+ If any of `source` is not in `G`.
+
+ NetworkXUnbounded
+ If the (di)graph contains a negative (di)cycle, the
+ algorithm raises an exception to indicate the presence of the
+ negative (di)cycle. Note: any negative weight edge in an
+ undirected graph is a negative cycle
+ """
+ if pred is None:
+ pred = {v: [] for v in source}
+
+ if dist is None:
+ dist = {v: 0 for v in source}
+
+ negative_cycle_found = _inner_bellman_ford(
+ G,
+ source,
+ weight,
+ pred,
+ dist,
+ heuristic,
+ )
+ if negative_cycle_found is not None:
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
+
+ if paths is not None:
+ sources = set(source)
+ dsts = [target] if target is not None else pred
+ for dst in dsts:
+ gen = _build_paths_from_predecessors(sources, dst, pred)
+ paths[dst] = next(gen)
+
+ return dist
+
+
+def _inner_bellman_ford(
+ G,
+ sources,
+ weight,
+ pred,
+ dist=None,
+ heuristic=True,
+):
+ """Inner Relaxation loop for Bellman–Ford algorithm.
+
+ This is an implementation of the SPFA variant.
+ See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source: list
+ List of source nodes. The shortest path from any of the source
+ nodes will be found if multiple sources are provided.
+
+ weight : function
+ The weight of an edge is the value returned by the function. The
+ function must accept exactly three positional arguments: the two
+ endpoints of an edge and the dictionary of edge attributes for
+ that edge. The function must return a number.
+
+ pred: dict of lists
+ dict to store a list of predecessors keyed by that node
+
+ dist: dict, optional (default=None)
+ dict to store distance from source to the keyed node
+ If None, returned dist dict contents default to 0 for every node in the
+ source list
+
+ heuristic : bool
+ Determines whether to use a heuristic to early detect negative
+ cycles at a hopefully negligible cost.
+
+ Returns
+ -------
+ node or None
+ Return a node `v` where processing discovered a negative cycle.
+ If no negative cycle found, return None.
+
+ Raises
+ ------
+ NodeNotFound
+ If any of `source` is not in `G`.
+ """
+ for s in sources:
+ if s not in G:
+ raise nx.NodeNotFound(f"Source {s} not in G")
+
+ if pred is None:
+ pred = {v: [] for v in sources}
+
+ if dist is None:
+ dist = {v: 0 for v in sources}
+
+ # Heuristic Storage setup. Note: use None because nodes cannot be None
+ nonexistent_edge = (None, None)
+ pred_edge = {v: None for v in sources}
+ recent_update = {v: nonexistent_edge for v in sources}
+
+ G_succ = G._adj # For speed-up (and works for both directed and undirected graphs)
+ inf = float("inf")
+ n = len(G)
+
+ count = {}
+ q = deque(sources)
+ in_q = set(sources)
+ while q:
+ u = q.popleft()
+ in_q.remove(u)
+
+ # Skip relaxations if any of the predecessors of u is in the queue.
+ if all(pred_u not in in_q for pred_u in pred[u]):
+ dist_u = dist[u]
+ for v, e in G_succ[u].items():
+ dist_v = dist_u + weight(u, v, e)
+
+ if dist_v < dist.get(v, inf):
+ # In this conditional branch we are updating the path with v.
+ # If it happens that some earlier update also added node v
+ # that implies the existence of a negative cycle since
+ # after the update node v would lie on the update path twice.
+ # The update path is stored up to one of the source nodes,
+ # therefore u is always in the dict recent_update
+ if heuristic:
+ if v in recent_update[u]:
+ # Negative cycle found!
+ pred[v].append(u)
+ return v
+
+ # Transfer the recent update info from u to v if the
+ # same source node is the head of the update path.
+ # If the source node is responsible for the cost update,
+ # then clear the history and use it instead.
+ if v in pred_edge and pred_edge[v] == u:
+ recent_update[v] = recent_update[u]
+ else:
+ recent_update[v] = (u, v)
+
+ if v not in in_q:
+ q.append(v)
+ in_q.add(v)
+ count_v = count.get(v, 0) + 1
+ if count_v == n:
+ # Negative cycle found!
+ return v
+
+ count[v] = count_v
+ dist[v] = dist_v
+ pred[v] = [u]
+ pred_edge[v] = u
+
+ elif dist.get(v) is not None and dist_v == dist.get(v):
+ pred[v].append(u)
+
+ # successfully found shortest_path. No negative cycles found.
+ return None
+
+
+@nx._dispatchable(edge_attrs="weight")
+def bellman_ford_path(G, source, target, weight="weight"):
+ """Returns the shortest path from source to target in a weighted graph G.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node
+ Starting node
+
+ target : node
+ Ending node
+
+ weight : string or function (default="weight")
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ path : list
+ List of nodes in a shortest path.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ NetworkXNoPath
+ If no path exists between source and target.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> nx.bellman_ford_path(G, 0, 4)
+ [0, 1, 2, 3, 4]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ See Also
+ --------
+ dijkstra_path, bellman_ford_path_length
+ """
+ length, path = single_source_bellman_ford(G, source, target=target, weight=weight)
+ return path
+
+
+@nx._dispatchable(edge_attrs="weight")
+def bellman_ford_path_length(G, source, target, weight="weight"):
+ """Returns the shortest path length from source to target
+ in a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node label
+ starting node for path
+
+ target : node label
+ ending node for path
+
+ weight : string or function (default="weight")
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ length : number
+ Shortest path length.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ NetworkXNoPath
+ If no path exists between source and target.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> nx.bellman_ford_path_length(G, 0, 4)
+ 4
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ See Also
+ --------
+ dijkstra_path_length, bellman_ford_path
+ """
+ if source == target:
+ if source not in G:
+ raise nx.NodeNotFound(f"Node {source} not found in graph")
+ return 0
+
+ weight = _weight_function(G, weight)
+
+ length = _bellman_ford(G, [source], weight, target=target)
+
+ try:
+ return length[target]
+ except KeyError as err:
+ raise nx.NetworkXNoPath(f"node {target} not reachable from {source}") from err
+
+
+@nx._dispatchable(edge_attrs="weight")
+def single_source_bellman_ford_path(G, source, weight="weight"):
+ """Compute shortest path between source and all other reachable
+ nodes for a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node
+ Starting node for path.
+
+ weight : string or function (default="weight")
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ paths : dictionary
+ Dictionary of shortest path lengths keyed by target.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> path = nx.single_source_bellman_ford_path(G, 0)
+ >>> path[4]
+ [0, 1, 2, 3, 4]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ See Also
+ --------
+ single_source_dijkstra, single_source_bellman_ford
+
+ """
+ (length, path) = single_source_bellman_ford(G, source, weight=weight)
+ return path
+
+
+@nx._dispatchable(edge_attrs="weight")
+def single_source_bellman_ford_path_length(G, source, weight="weight"):
+ """Compute the shortest path length between source and all other
+ reachable nodes for a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node label
+ Starting node for path
+
+ weight : string or function (default="weight")
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ length : dictionary
+ Dictionary of shortest path length keyed by target
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length = nx.single_source_bellman_ford_path_length(G, 0)
+ >>> length[4]
+ 4
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"{node}: {length[node]}")
+ 0: 0
+ 1: 1
+ 2: 2
+ 3: 3
+ 4: 4
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ See Also
+ --------
+ single_source_dijkstra, single_source_bellman_ford
+
+ """
+ weight = _weight_function(G, weight)
+ return _bellman_ford(G, [source], weight)
+
+
+@nx._dispatchable(edge_attrs="weight")
+def single_source_bellman_ford(G, source, target=None, weight="weight"):
+ """Compute shortest paths and lengths in a weighted graph G.
+
+ Uses Bellman-Ford algorithm for shortest paths.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node label
+ Starting node for path
+
+ target : node label, optional
+ Ending node for path
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ distance, path : pair of dictionaries, or numeric and list
+ If target is None, returns a tuple of two dictionaries keyed by node.
+ The first dictionary stores distance from one of the source nodes.
+ The second stores the path from one of the sources to that node.
+ If target is not None, returns a tuple of (distance, path) where
+ distance is the distance from source to target and path is a list
+ representing the path from source to target.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length, path = nx.single_source_bellman_ford(G, 0)
+ >>> length[4]
+ 4
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"{node}: {length[node]}")
+ 0: 0
+ 1: 1
+ 2: 2
+ 3: 3
+ 4: 4
+ >>> path[4]
+ [0, 1, 2, 3, 4]
+ >>> length, path = nx.single_source_bellman_ford(G, 0, 1)
+ >>> length
+ 1
+ >>> path
+ [0, 1]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ See Also
+ --------
+ single_source_dijkstra
+ single_source_bellman_ford_path
+ single_source_bellman_ford_path_length
+ """
+ if source == target:
+ if source not in G:
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
+ return (0, [source])
+
+ weight = _weight_function(G, weight)
+
+ paths = {source: [source]} # dictionary of paths
+ dist = _bellman_ford(G, [source], weight, paths=paths, target=target)
+ if target is None:
+ return (dist, paths)
+ try:
+ return (dist[target], paths[target])
+ except KeyError as err:
+ msg = f"Node {target} not reachable from {source}"
+ raise nx.NetworkXNoPath(msg) from err
+
+
+@nx._dispatchable(edge_attrs="weight")
+def all_pairs_bellman_ford_path_length(G, weight="weight"):
+ """Compute shortest path lengths between all nodes in a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ weight : string or function (default="weight")
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ distance : iterator
+ (source, dictionary) iterator with dictionary keyed by target and
+ shortest path length as the key value.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length = dict(nx.all_pairs_bellman_ford_path_length(G))
+ >>> for node in [0, 1, 2, 3, 4]:
+ ... print(f"1 - {node}: {length[1][node]}")
+ 1 - 0: 1
+ 1 - 1: 0
+ 1 - 2: 1
+ 1 - 3: 2
+ 1 - 4: 3
+ >>> length[3][2]
+ 1
+ >>> length[2][2]
+ 0
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The dictionary returned only has keys for reachable node pairs.
+ """
+ length = single_source_bellman_ford_path_length
+ for n in G:
+ yield (n, dict(length(G, n, weight=weight)))
+
+
+@nx._dispatchable(edge_attrs="weight")
+def all_pairs_bellman_ford_path(G, weight="weight"):
+ """Compute shortest paths between all nodes in a weighted graph.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ weight : string or function (default="weight")
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ paths : iterator
+ (source, dictionary) iterator with dictionary keyed by target and
+ shortest path as the key value.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> path = dict(nx.all_pairs_bellman_ford_path(G))
+ >>> path[0][4]
+ [0, 1, 2, 3, 4]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ See Also
+ --------
+ floyd_warshall, all_pairs_dijkstra_path
+
+ """
+ path = single_source_bellman_ford_path
+ for n in G:
+ yield (n, path(G, n, weight=weight))
+
+
+@nx._dispatchable(edge_attrs="weight")
+def goldberg_radzik(G, source, weight="weight"):
+ """Compute shortest path lengths and predecessors on shortest paths
+ in weighted graphs.
+
+ The algorithm has a running time of $O(mn)$ where $n$ is the number of
+ nodes and $m$ is the number of edges. It is slower than Dijkstra but
+ can handle negative edge weights.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+ The algorithm works for all types of graphs, including directed
+ graphs and multigraphs.
+
+ source: node label
+ Starting node for path
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ pred, dist : dictionaries
+ Returns two dictionaries keyed by node to predecessor in the
+ path and to the distance from the source respectively.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` is not in `G`.
+
+ NetworkXUnbounded
+ If the (di)graph contains a negative (di)cycle, the
+ algorithm raises an exception to indicate the presence of the
+ negative (di)cycle. Note: any negative weight edge in an
+ undirected graph is a negative cycle.
+
+ As of NetworkX v3.2, a zero weight cycle is no longer
+ incorrectly reported as a negative weight cycle.
+
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5, create_using=nx.DiGraph())
+ >>> pred, dist = nx.goldberg_radzik(G, 0)
+ >>> sorted(pred.items())
+ [(0, None), (1, 0), (2, 1), (3, 2), (4, 3)]
+ >>> sorted(dist.items())
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
+
+ >>> G = nx.cycle_graph(5, create_using=nx.DiGraph())
+ >>> G[1][2]["weight"] = -7
+ >>> nx.goldberg_radzik(G, 0)
+ Traceback (most recent call last):
+ ...
+ networkx.exception.NetworkXUnbounded: Negative cycle detected.
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The dictionaries returned only have keys for nodes reachable from
+ the source.
+
+ In the case where the (di)graph is not connected, if a component
+ not containing the source contains a negative (di)cycle, it
+ will not be detected.
+
+ """
+ if source not in G:
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
+ weight = _weight_function(G, weight)
+ if G.is_multigraph():
+ if any(
+ weight(u, v, {k: d}) < 0
+ for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True)
+ ):
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
+ else:
+ if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)):
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
+
+ if len(G) == 1:
+ return {source: None}, {source: 0}
+
+ G_succ = G._adj # For speed-up (and works for both directed and undirected graphs)
+
+ inf = float("inf")
+ d = {u: inf for u in G}
+ d[source] = 0
+ pred = {source: None}
+
+ def topo_sort(relabeled):
+ """Topologically sort nodes relabeled in the previous round and detect
+ negative cycles.
+ """
+ # List of nodes to scan in this round. Denoted by A in Goldberg and
+ # Radzik's paper.
+ to_scan = []
+ # In the DFS in the loop below, neg_count records for each node the
+ # number of edges of negative reduced costs on the path from a DFS root
+ # to the node in the DFS forest. The reduced cost of an edge (u, v) is
+ # defined as d[u] + weight[u][v] - d[v].
+ #
+ # neg_count also doubles as the DFS visit marker array.
+ neg_count = {}
+ for u in relabeled:
+ # Skip visited nodes.
+ if u in neg_count:
+ continue
+ d_u = d[u]
+ # Skip nodes without out-edges of negative reduced costs.
+ if all(d_u + weight(u, v, e) >= d[v] for v, e in G_succ[u].items()):
+ continue
+ # Nonrecursive DFS that inserts nodes reachable from u via edges of
+ # nonpositive reduced costs into to_scan in (reverse) topological
+ # order.
+ stack = [(u, iter(G_succ[u].items()))]
+ in_stack = {u}
+ neg_count[u] = 0
+ while stack:
+ u, it = stack[-1]
+ try:
+ v, e = next(it)
+ except StopIteration:
+ to_scan.append(u)
+ stack.pop()
+ in_stack.remove(u)
+ continue
+ t = d[u] + weight(u, v, e)
+ d_v = d[v]
+ if t < d_v:
+ is_neg = t < d_v
+ d[v] = t
+ pred[v] = u
+ if v not in neg_count:
+ neg_count[v] = neg_count[u] + int(is_neg)
+ stack.append((v, iter(G_succ[v].items())))
+ in_stack.add(v)
+ elif v in in_stack and neg_count[u] + int(is_neg) > neg_count[v]:
+ # (u, v) is a back edge, and the cycle formed by the
+ # path v to u and (u, v) contains at least one edge of
+ # negative reduced cost. The cycle must be of negative
+ # cost.
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
+ to_scan.reverse()
+ return to_scan
+
+ def relax(to_scan):
+ """Relax out-edges of relabeled nodes."""
+ relabeled = set()
+ # Scan nodes in to_scan in topological order and relax incident
+ # out-edges. Add the relabled nodes to labeled.
+ for u in to_scan:
+ d_u = d[u]
+ for v, e in G_succ[u].items():
+ w_e = weight(u, v, e)
+ if d_u + w_e < d[v]:
+ d[v] = d_u + w_e
+ pred[v] = u
+ relabeled.add(v)
+ return relabeled
+
+ # Set of nodes relabled in the last round of scan operations. Denoted by B
+ # in Goldberg and Radzik's paper.
+ relabeled = {source}
+
+ while relabeled:
+ to_scan = topo_sort(relabeled)
+ relabeled = relax(to_scan)
+
+ d = {u: d[u] for u in pred}
+ return pred, d
+
+
+@nx._dispatchable(edge_attrs="weight")
+def negative_edge_cycle(G, weight="weight", heuristic=True):
+ """Returns True if there exists a negative edge cycle anywhere in G.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ heuristic : bool
+ Determines whether to use a heuristic to early detect negative
+ cycles at a negligible cost. In case of graphs with a negative cycle,
+ the performance of detection increases by at least an order of magnitude.
+
+ Returns
+ -------
+ negative_cycle : bool
+ True if a negative edge cycle exists, otherwise False.
+
+ Examples
+ --------
+ >>> G = nx.cycle_graph(5, create_using=nx.DiGraph())
+ >>> print(nx.negative_edge_cycle(G))
+ False
+ >>> G[1][2]["weight"] = -7
+ >>> print(nx.negative_edge_cycle(G))
+ True
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ This algorithm uses bellman_ford_predecessor_and_distance() but finds
+ negative cycles on any component by first adding a new node connected to
+ every node, and starting bellman_ford_predecessor_and_distance on that
+ node. It then removes that extra node.
+ """
+ if G.size() == 0:
+ return False
+
+ # find unused node to use temporarily
+ newnode = -1
+ while newnode in G:
+ newnode -= 1
+ # connect it to all nodes
+ G.add_edges_from([(newnode, n) for n in G])
+
+ try:
+ bellman_ford_predecessor_and_distance(
+ G, newnode, weight=weight, heuristic=heuristic
+ )
+ except nx.NetworkXUnbounded:
+ return True
+ finally:
+ G.remove_node(newnode)
+ return False
+
+
+@nx._dispatchable(edge_attrs="weight")
+def find_negative_cycle(G, source, weight="weight"):
+ """Returns a cycle with negative total weight if it exists.
+
+ Bellman-Ford is used to find shortest_paths. That algorithm
+ stops if there exists a negative cycle. This algorithm
+ picks up from there and returns the found negative cycle.
+
+ The cycle consists of a list of nodes in the cycle order. The last
+ node equals the first to make it a cycle.
+ You can look up the edge weights in the original graph. In the case
+ of multigraphs the relevant edge is the minimal weight edge between
+ the nodes in the 2-tuple.
+
+ If the graph has no negative cycle, a NetworkXError is raised.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source: node label
+ The search for the negative cycle will start from this node.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Examples
+ --------
+ >>> G = nx.DiGraph()
+ >>> G.add_weighted_edges_from(
+ ... [(0, 1, 2), (1, 2, 2), (2, 0, 1), (1, 4, 2), (4, 0, -5)]
+ ... )
+ >>> nx.find_negative_cycle(G, 0)
+ [4, 0, 1, 4]
+
+ Returns
+ -------
+ cycle : list
+ A list of nodes in the order of the cycle found. The last node
+ equals the first to indicate a cycle.
+
+ Raises
+ ------
+ NetworkXError
+ If no negative cycle is found.
+ """
+ weight = _weight_function(G, weight)
+ pred = {source: []}
+
+ v = _inner_bellman_ford(G, [source], weight, pred=pred)
+ if v is None:
+ raise nx.NetworkXError("No negative cycles detected.")
+
+ # negative cycle detected... find it
+ neg_cycle = []
+ stack = [(v, list(pred[v]))]
+ seen = {v}
+ while stack:
+ node, preds = stack[-1]
+ if v in preds:
+ # found the cycle
+ neg_cycle.extend([node, v])
+ neg_cycle = list(reversed(neg_cycle))
+ return neg_cycle
+
+ if preds:
+ nbr = preds.pop()
+ if nbr not in seen:
+ stack.append((nbr, list(pred[nbr])))
+ neg_cycle.append(node)
+ seen.add(nbr)
+ else:
+ stack.pop()
+ if neg_cycle:
+ neg_cycle.pop()
+ else:
+ if v in G[v] and weight(G, v, v) < 0:
+ return [v, v]
+ # should not reach here
+ raise nx.NetworkXError("Negative cycle is detected but not found")
+ # should not get here...
+ msg = "negative cycle detected but not identified"
+ raise nx.NetworkXUnbounded(msg)
+
+
+@nx._dispatchable(edge_attrs="weight")
+def bidirectional_dijkstra(G, source, target, weight="weight"):
+ r"""Dijkstra's algorithm for shortest paths using bidirectional search.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ source : node
+ Starting node.
+
+ target : node
+ Ending node.
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number or None to indicate a hidden edge.
+
+ Returns
+ -------
+ length, path : number and list
+ length is the distance from source to target.
+ path is a list of nodes on a path from source to target.
+
+ Raises
+ ------
+ NodeNotFound
+ If `source` or `target` is not in `G`.
+
+ NetworkXNoPath
+ If no path exists between source and target.
+
+ Examples
+ --------
+ >>> G = nx.path_graph(5)
+ >>> length, path = nx.bidirectional_dijkstra(G, 0, 4)
+ >>> print(length)
+ 4
+ >>> print(path)
+ [0, 1, 2, 3, 4]
+
+ Notes
+ -----
+ Edge weight attributes must be numerical.
+ Distances are calculated as sums of weighted edges traversed.
+
+ The weight function can be used to hide edges by returning None.
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
+ will find the shortest red path.
+
+ In practice bidirectional Dijkstra is much more than twice as fast as
+ ordinary Dijkstra.
+
+ Ordinary Dijkstra expands nodes in a sphere-like manner from the
+ source. The radius of this sphere will eventually be the length
+ of the shortest path. Bidirectional Dijkstra will expand nodes
+ from both the source and the target, making two spheres of half
+ this radius. Volume of the first sphere is `\pi*r*r` while the
+ others are `2*\pi*r/2*r/2`, making up half the volume.
+
+ This algorithm is not guaranteed to work if edge weights
+ are negative or are floating point numbers
+ (overflows and roundoff errors can cause problems).
+
+ See Also
+ --------
+ shortest_path
+ shortest_path_length
+ """
+ if source not in G:
+ raise nx.NodeNotFound(f"Source {source} is not in G")
+
+ if target not in G:
+ raise nx.NodeNotFound(f"Target {target} is not in G")
+
+ if source == target:
+ return (0, [source])
+
+ weight = _weight_function(G, weight)
+ push = heappush
+ pop = heappop
+ # Init: [Forward, Backward]
+ dists = [{}, {}] # dictionary of final distances
+ paths = [{source: [source]}, {target: [target]}] # dictionary of paths
+ fringe = [[], []] # heap of (distance, node) for choosing node to expand
+ seen = [{source: 0}, {target: 0}] # dict of distances to seen nodes
+ c = count()
+ # initialize fringe heap
+ push(fringe[0], (0, next(c), source))
+ push(fringe[1], (0, next(c), target))
+ # neighs for extracting correct neighbor information
+ if G.is_directed():
+ neighs = [G._succ, G._pred]
+ else:
+ neighs = [G._adj, G._adj]
+ # variables to hold shortest discovered path
+ # finaldist = 1e30000
+ finalpath = []
+ dir = 1
+ while fringe[0] and fringe[1]:
+ # choose direction
+ # dir == 0 is forward direction and dir == 1 is back
+ dir = 1 - dir
+ # extract closest to expand
+ (dist, _, v) = pop(fringe[dir])
+ if v in dists[dir]:
+ # Shortest path to v has already been found
+ continue
+ # update distance
+ dists[dir][v] = dist # equal to seen[dir][v]
+ if v in dists[1 - dir]:
+ # if we have scanned v in both directions we are done
+ # we have now discovered the shortest path
+ return (finaldist, finalpath)
+
+ for w, d in neighs[dir][v].items():
+ # weight(v, w, d) for forward and weight(w, v, d) for back direction
+ cost = weight(v, w, d) if dir == 0 else weight(w, v, d)
+ if cost is None:
+ continue
+ vwLength = dists[dir][v] + cost
+ if w in dists[dir]:
+ if vwLength < dists[dir][w]:
+ raise ValueError("Contradictory paths found: negative weights?")
+ elif w not in seen[dir] or vwLength < seen[dir][w]:
+ # relaxing
+ seen[dir][w] = vwLength
+ push(fringe[dir], (vwLength, next(c), w))
+ paths[dir][w] = paths[dir][v] + [w]
+ if w in seen[0] and w in seen[1]:
+ # see if this path is better than the already
+ # discovered shortest path
+ totaldist = seen[0][w] + seen[1][w]
+ if finalpath == [] or finaldist > totaldist:
+ finaldist = totaldist
+ revpath = paths[1][w][:]
+ revpath.reverse()
+ finalpath = paths[0][w] + revpath[1:]
+ raise nx.NetworkXNoPath(f"No path between {source} and {target}.")
+
+
+@nx._dispatchable(edge_attrs="weight")
+def johnson(G, weight="weight"):
+ r"""Uses Johnson's Algorithm to compute shortest paths.
+
+ Johnson's Algorithm finds a shortest path between each pair of
+ nodes in a weighted graph even if negative weights are present.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ weight : string or function
+ If this is a string, then edge weights will be accessed via the
+ edge attribute with this key (that is, the weight of the edge
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
+ such edge attribute exists, the weight of the edge is assumed to
+ be one.
+
+ If this is a function, the weight of an edge is the value
+ returned by the function. The function must accept exactly three
+ positional arguments: the two endpoints of an edge and the
+ dictionary of edge attributes for that edge. The function must
+ return a number.
+
+ Returns
+ -------
+ distance : dictionary
+ Dictionary, keyed by source and target, of shortest paths.
+
+ Examples
+ --------
+ >>> graph = nx.DiGraph()
+ >>> graph.add_weighted_edges_from(
+ ... [("0", "3", 3), ("0", "1", -5), ("0", "2", 2), ("1", "2", 4), ("2", "3", 1)]
+ ... )
+ >>> paths = nx.johnson(graph, weight="weight")
+ >>> paths["0"]["2"]
+ ['0', '1', '2']
+
+ Notes
+ -----
+ Johnson's algorithm is suitable even for graphs with negative weights. It
+ works by using the Bellman–Ford algorithm to compute a transformation of
+ the input graph that removes all negative weights, allowing Dijkstra's
+ algorithm to be used on the transformed graph.
+
+ The time complexity of this algorithm is $O(n^2 \log n + n m)$,
+ where $n$ is the number of nodes and $m$ the number of edges in the
+ graph. For dense graphs, this may be faster than the Floyd–Warshall
+ algorithm.
+
+ See Also
+ --------
+ floyd_warshall_predecessor_and_distance
+ floyd_warshall_numpy
+ all_pairs_shortest_path
+ all_pairs_shortest_path_length
+ all_pairs_dijkstra_path
+ bellman_ford_predecessor_and_distance
+ all_pairs_bellman_ford_path
+ all_pairs_bellman_ford_path_length
+
+ """
+ dist = {v: 0 for v in G}
+ pred = {v: [] for v in G}
+ weight = _weight_function(G, weight)
+
+ # Calculate distance of shortest paths
+ dist_bellman = _bellman_ford(G, list(G), weight, pred=pred, dist=dist)
+
+ # Update the weight function to take into account the Bellman--Ford
+ # relaxation distances.
+ def new_weight(u, v, d):
+ return weight(u, v, d) + dist_bellman[u] - dist_bellman[v]
+
+ def dist_path(v):
+ paths = {v: [v]}
+ _dijkstra(G, v, new_weight, paths=paths)
+ return paths
+
+ return {v: dist_path(v) for v in G}