This appears to have two questions in it. I can answer the part involving networkx
.
Graph
:
To be a little pedantic (and because I'm imagining future people Googling this), this does depend on the type of graph you're working in. We'll start with a generic graph:
import networkx as nx
G = nx.path_graph(5)
G.add_edge(2, 8, weight=0.3) # A
G.add_edge(2, 8, weight=0.6) # B
G.add_edge(1, 8, weight=1.0)
for u, v, w in G.edges(data=True):
print(u, v, k)
... and consider what happens if we switch the order of the lines marked A
and B
:
import networkx as nx
G = nx.path_graph(5)
G.add_edge(2, 8, weight=0.6) # B
G.add_edge(2, 8, weight=0.3) # A
G.add_edge(1, 8, weight=1.0)
for u, v, w in G.edges(data=True):
print(u, v, k)
In both cases: the network will look the same:

But the parameters of our network are different in the two cases:
# A first
0 1 {}
1 2 {}
1 8 {'weight': 1.0}
2 3 {}
2 8 {'weight': 0.6}
3 4 {}
and
# B first
0 1 {}
1 2 {}
1 8 {'weight': 1.0}
2 3 {}
2 8 {'weight': 0.3}
3 4 {}
So here: the answer is that u
, v
, and k
are unique and the list returned by shortest_path
will be unique.
MultiDiGraph
:
I'm 90% sure this is the case the question wants to ask about. In a MultiDiGraph
the nodes are still indexed by u
, v
, but there can be multiple weights k
:
import networkx as nx
GM = nx.MultiDiGraph()
GM.add_edge(0, 2, weight=0.3)
GM.add_edge(0, 2, weight=0.15)
GM.add_edge(1, 2, weight=0.1)
GM.add_edge(0, 1, weight=0.1)
GM.add_edge(2, 3, weight=0.4)
GM.add_edge(2, 3, weight=0.5)
for u, v, w in GM.edges(data=True):
print(u, v, w)
path = nx.shortest_path(GM, source=0, target=3, weight='weight')
print(path)
# [0, 2, 3]
The list returned by nx.shortest_path
is ambiguous, but it's pretty straightforward to reconstruct the path of least weight:
for u, v in zip(path[0:], path[1:]):
edge_data = GM.get_edge_data(u, v)
min_weight = min([edge_data[edge]['weight'] for edge in edge_data])
print(f"{u}---({min_weight})---{v}")
Result:
0---(0.15)---2
2---(0.4)---3