Skip to content

Commit f4c1677

Browse files
authored
Implementing Johnson's Algorithm (#608)
1 parent a98308d commit f4c1677

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

pydatastructs/graphs/algorithms.py

+49-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from collections import deque
66
from concurrent.futures import ThreadPoolExecutor
77
from pydatastructs.utils.misc_util import (
8-
_comp, raise_if_backend_is_not_python, Backend)
8+
_comp, raise_if_backend_is_not_python, Backend, AdjacencyListGraphNode)
99
from pydatastructs.miscellaneous_data_structures import (
1010
DisjointSetForest, PriorityQueue)
1111
from pydatastructs.graphs.graph import Graph
@@ -799,7 +799,7 @@ def _dijkstra_adjacency_list(graph: Graph, start: str, target: str):
799799
visited[u] = True
800800
for v in graph.vertices:
801801
edge_str = u + '_' + v
802-
if (edge_str in graph.edge_weights and graph.edge_weights[edge_str].value > 0 and
802+
if (edge_str in graph.edge_weights and graph.edge_weights[edge_str].value >= 0 and
803803
visited[v] is False and dist[v] > dist[u] + graph.edge_weights[edge_str].value):
804804
dist[v] = dist[u] + graph.edge_weights[edge_str].value
805805
pred[v] = u
@@ -826,6 +826,7 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str,
826826
are implemented,
827827
828828
'floyd_warshall' -> Floyd Warshall algorithm as given in [1].
829+
'johnson' -> Johnson's Algorithm as given in [2]
829830
backend: pydatastructs.Backend
830831
The backend to be used.
831832
Optional, by default, the best available
@@ -858,6 +859,7 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str,
858859
==========
859860
860861
.. [1] https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
862+
.. [2] https://en.wikipedia.org/wiki/Johnson's_algorithm
861863
"""
862864
raise_if_backend_is_not_python(
863865
all_pair_shortest_paths, kwargs.get('backend', Backend.PYTHON))
@@ -900,6 +902,51 @@ def _floyd_warshall_adjacency_list(graph: Graph):
900902

901903
_floyd_warshall_adjacency_matrix = _floyd_warshall_adjacency_list
902904

905+
def _johnson_adjacency_list(graph: Graph):
906+
new_vertex = AdjacencyListGraphNode('__q__')
907+
graph.add_vertex(new_vertex)
908+
909+
for vertex in graph.vertices:
910+
if vertex != '__q__':
911+
graph.add_edge('__q__', vertex, 0)
912+
913+
distances, predecessors = shortest_paths(graph, 'bellman_ford', '__q__')
914+
915+
edges_to_remove = []
916+
for edge in graph.edge_weights:
917+
edge_node = graph.edge_weights[edge]
918+
if edge_node.source.name == '__q__':
919+
edges_to_remove.append((edge_node.source.name, edge_node.target.name))
920+
921+
for u, v in edges_to_remove:
922+
graph.remove_edge(u, v)
923+
graph.remove_vertex('__q__')
924+
925+
for edge in graph.edge_weights:
926+
edge_node = graph.edge_weights[edge]
927+
u, v = edge_node.source.name, edge_node.target.name
928+
graph.edge_weights[edge].value += (distances[u] - distances[v])
929+
930+
all_distances = {}
931+
all_next_vertex = {}
932+
933+
for vertex in graph.vertices:
934+
u = vertex
935+
dijkstra_dist, dijkstra_pred = shortest_paths(graph, 'dijkstra', u)
936+
all_distances[u] = {}
937+
all_next_vertex[u] = {}
938+
for v in graph.vertices:
939+
if dijkstra_pred[v] is None or dijkstra_pred[v] == u :
940+
all_next_vertex[u][v] = u
941+
else:
942+
all_next_vertex[u][v] = None
943+
if v in dijkstra_dist:
944+
all_distances[u][v] = dijkstra_dist[v] - distances[u] + distances[v]
945+
else:
946+
all_distances[u][v] = float('inf')
947+
948+
return (all_distances, all_next_vertex)
949+
903950
def topological_sort(graph: Graph, algorithm: str,
904951
**kwargs) -> list:
905952
"""

pydatastructs/graphs/tests/test_algorithms.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pydatastructs import (breadth_first_search, Graph,
22
breadth_first_search_parallel, minimum_spanning_tree,
33
minimum_spanning_tree_parallel, strongly_connected_components,
4-
depth_first_search, shortest_paths, topological_sort,
4+
depth_first_search, shortest_paths,all_pair_shortest_paths, topological_sort,
55
topological_sort_parallel, max_flow)
66
from pydatastructs.utils.raises_util import raises
77

@@ -336,7 +336,7 @@ def _test_shortest_paths_negative_edges(ds, algorithm):
336336
graph.add_edge('2', '3', 3)
337337
graph.add_edge('3', '4', 2)
338338
graph.add_edge('4', '2', -1)
339-
dist, next_v = shortest_paths(graph, algorithm, 's')
339+
dist, next_v = all_pair_shortest_paths(graph, algorithm)
340340
assert dist == {'1': {'3': -2, '1': 0, '4': 0, '2': -1},
341341
'2': {'1': 4, '3': 2, '2': 0, '4': 4},
342342
'3': {'4': 2, '3': 0, '1': 5, '2': 1},
@@ -346,6 +346,10 @@ def _test_shortest_paths_negative_edges(ds, algorithm):
346346
'3': {'4': '3', '3': '3', '1': None, '2': None},
347347
'4': {'2': '4', '4': '4', '1': None, '3': None}}
348348

349+
_test_shortest_paths_negative_edges("List", 'floyd_warshall')
350+
_test_shortest_paths_negative_edges("Matrix", 'floyd_warshall')
351+
_test_shortest_paths_negative_edges("List", 'johnson')
352+
349353
def test_topological_sort():
350354

351355
def _test_topological_sort(func, ds, algorithm, threads=None):

0 commit comments

Comments
 (0)