1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488 |
- """
- 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)
- 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
- 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
- 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)
- 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)
- 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
- )
- 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
- 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)
- 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
- 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))
- 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))
- 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))
- 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._dispatch
- 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 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._dispatch
- 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._dispatch
- 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._dispatch
- 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._dispatch
- 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._dispatch
- 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._dispatch
- 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._dispatch
- 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
- # TODO This can be trivially parallelized.
- for n in G:
- yield (n, path(G, n, weight=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.
- 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 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._dispatch
- 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
- 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)
- 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 either `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 or target not in G:
- msg = f"Either source {source} or target {target} is not in G"
- raise nx.NodeNotFound(msg)
- 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}.")
- 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.
- Raises
- ------
- NetworkXError
- If given graph is not weighted.
- 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
- """
- if not nx.is_weighted(G, weight=weight):
- raise nx.NetworkXError("Graph is not weighted.")
- 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}
|