Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add doctests for graphs_floyd_warshall.py #12436

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
155 changes: 82 additions & 73 deletions graphs/graphs_floyd_warshall.py
Original file line number Diff line number Diff line change
@@ -1,102 +1,111 @@
# floyd_warshall.py
"""
The problem is to find the shortest distance between all pairs of vertices in a
weighted directed graph that can have negative edge weights.
The problem is to find and return the shortest distance between all pairs of vertices
in a weighted directed graph that can have negative edge weights.

https://docs.python.org/3/library/doctest.html

asmitannu marked this conversation as resolved.
Show resolved Hide resolved
"""


def _print_dist(dist, v):
print("\nThe shortest path matrix using Floyd Warshall algorithm\n")
for i in range(v):
for j in range(v):
if dist[i][j] != float("inf"):
print(int(dist[i][j]), end="\t")
else:
print("INF", end="\t")
print()
def floyd_warshall(graph: list[list[float]], vertex: int) -> tuple:
# 1. For all edges from v to n, distance[i][j] = weight(edge(i, j)).

# 2. distance[i][j] = min(distance[i][j], distance[i][k] + distance[k][j]).

# 3. Step 2 is true for each pair of vertices.Repeat for k vertex in the graph.

# 4. Whenever distance[i][j] is given a new minimum value,
# next vertex[i][j] = next vertex[i][k].

def floyd_warshall(graph, v):
"""
:param graph: 2D array calculated from weight[edge[i, j]]
:type graph: List[List[float]]

:param v: number of vertices
:type v: int

:return: shortest distance between all vertex pairs

distance[u][v] will contain the shortest distance from vertex u to v.

1. For all edges from v to n, distance[i][j] = weight(edge(i, j)).
3. The algorithm then performs distance[i][j] = min(distance[i][j], distance[i][k] +
distance[k][j]) for each possible pair i, j of vertices.
4. The above is repeated for each vertex k in the graph.
5. Whenever distance[i][j] is given a new minimum value, next vertex[i][j] is
updated to the next vertex[i][k].
# doctests:

>>> graph = [[0, 3, float('inf')], [2, 0, float('inf')],[float('inf'), 7, 0]]
>>> floyd_warshall(graph, 3)[0]
[[0, 3, inf], [2, 0, inf], [9, 7, 0]]

>>> graph = [[0, 1, 4],[float('inf'), 0, 2],[float('inf'), float('inf'), 0]]
>>> floyd_warshall(graph, 3)[0]
[[0, 1, 3], [inf, 0, 2], [inf, inf, 0]]

>>> graph = [[0, 0, 0],[0, 0, 0],[0, 0, 0]]
>>> floyd_warshall(graph, 3)[0]
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

#Graph with all edge weights = infinity

>>> graph = [[float('inf'), float('inf'), float('inf')],
... [float('inf'), float('inf'), float('inf')],
... [float('inf'), float('inf'), float('inf')]]
>>> floyd_warshall(graph, 3)[0]
[[inf, inf, inf], [inf, inf, inf], [inf, inf, inf]]


#Handling negetive weighted graph:

>>> graph = [[0, -2, float('inf')],[float('inf'), 0, 3],[4, float('inf'), 0]]
>>> floyd_warshall(graph, 3)[0]
[[0, -2, 1], [7, 0, 3], [4, 2, 0]]


#Handling negetive weighted cycle:

>>> graph = [[0, -1, float('inf')],[float('inf'), 0, -2],[-3, float('inf'), 0]]
>>> floyd_warshall(graph, 3)[0]
[[-6, -7, -9], [-5, -6, -8], [-9, -10, -12]]


#Number of vertex in function argument should match number of vertex in graph:

>>> graph = [[0, -1, float('inf')],[float('inf'), 0, -2]]
>>> floyd_warshall(graph, 3)[0]
Traceback (most recent call last):
...
IndexError: list index out of range


#Graph data type should be a 2D list:

>>> graph = "strings not allowed"
>>> floyd_warshall(graph, 3)[0]
Traceback (most recent call last):
...
IndexError: string index out of range
"""

dist = [[float("inf") for _ in range(v)] for _ in range(v)]
dist = [[float("inf") for _ in range(vertex)] for _ in range(vertex)]

for i in range(v):
for j in range(v):
for i in range(vertex):
for j in range(vertex):
dist[i][j] = graph[i][j]

# check vertex k against all other vertices (i, j)
for k in range(v):

for k in range(vertex):
# looping through rows of graph array
for i in range(v):

for i in range(vertex):
# looping through columns of graph array
for j in range(v):

for j in range(vertex):
if (
dist[i][k] != float("inf")
and dist[k][j] != float("inf")
and dist[i][k] + dist[k][j] < dist[i][j]
):
dist[i][j] = dist[i][k] + dist[k][j]

_print_dist(dist, v)
return dist, v
return dist, vertex


if __name__ == "__main__":
v = int(input("Enter number of vertices: "))
asmitannu marked this conversation as resolved.
Show resolved Hide resolved
e = int(input("Enter number of edges: "))

graph = [[float("inf") for i in range(v)] for j in range(v)]

for i in range(v):
graph[i][i] = 0.0

# src and dst are indices that must be within the array size graph[e][v]
# failure to follow this will result in an error
for i in range(e):
print("\nEdge ", i + 1)
src = int(input("Enter source:"))
dst = int(input("Enter destination:"))
weight = float(input("Enter weight:"))
graph[src][dst] = weight

floyd_warshall(graph, v)

# Example Input
# Enter number of vertices: 3
# Enter number of edges: 2

# # generated graph from vertex and edge inputs
# [[inf, inf, inf], [inf, inf, inf], [inf, inf, inf]]
# [[0.0, inf, inf], [inf, 0.0, inf], [inf, inf, 0.0]]

# specify source, destination and weight for edge #1
# Edge 1
# Enter source:1
# Enter destination:2
# Enter weight:2

# specify source, destination and weight for edge #2
# Edge 2
# Enter source:2
# Enter destination:1
# Enter weight:1

# # Expected Output from the vertice, edge and src, dst, weight inputs!!
# 0 INF INF
# INF 0 2
# INF 1 0
import doctest

doctest.testmod()
Loading