From 2cffe89a5ff9a8e021eabf9e0d84f7e3d0ff0524 Mon Sep 17 00:00:00 2001 From: Prerak Singh Date: Sat, 8 Mar 2025 21:40:22 +0530 Subject: [PATCH 1/4] johnson's algorithm and fixed tests for all pair shortes t paths --- pydatastructs/graphs/algorithms.py | 51 ++++++++++++++++++- pydatastructs/graphs/tests/test_algorithms.py | 8 ++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/pydatastructs/graphs/algorithms.py b/pydatastructs/graphs/algorithms.py index ea3322c02..3b190c6d2 100644 --- a/pydatastructs/graphs/algorithms.py +++ b/pydatastructs/graphs/algorithms.py @@ -5,7 +5,7 @@ from collections import deque from concurrent.futures import ThreadPoolExecutor from pydatastructs.utils.misc_util import ( - _comp, raise_if_backend_is_not_python, Backend) + _comp, raise_if_backend_is_not_python, Backend, AdjacencyListGraphNode) from pydatastructs.miscellaneous_data_structures import ( DisjointSetForest, PriorityQueue) from pydatastructs.graphs.graph import Graph @@ -799,7 +799,7 @@ def _dijkstra_adjacency_list(graph: Graph, start: str, target: str): visited[u] = True for v in graph.vertices: edge_str = u + '_' + v - if (edge_str in graph.edge_weights and graph.edge_weights[edge_str].value > 0 and + if (edge_str in graph.edge_weights and graph.edge_weights[edge_str].value >= 0 and visited[v] is False and dist[v] > dist[u] + graph.edge_weights[edge_str].value): dist[v] = dist[u] + graph.edge_weights[edge_str].value pred[v] = u @@ -900,6 +900,53 @@ def _floyd_warshall_adjacency_list(graph: Graph): _floyd_warshall_adjacency_matrix = _floyd_warshall_adjacency_list +def _johnson_adjacency_list(graph: Graph): + new_vertex=AdjacencyListGraphNode('q') + graph.add_vertex(new_vertex) + + for vertex in graph.vertices: + if vertex != 'q': + graph.add_edge('q',vertex,0) + + distances, predecessors=shortest_paths(graph,'bellman_ford','q') + + edges_to_remove=[] + for edge in graph.edge_weights: + edge_node=graph.edge_weights[edge] + if edge_node.source.name=='q': + edges_to_remove.append((edge_node.source.name,edge_node.target.name)) + + for u,v in edges_to_remove: + graph.remove_edge(u,v) + graph.remove_vertex('q') + + for edge in graph.edge_weights: + edge_node=graph.edge_weights[edge] + u,v=edge_node.source.name,edge_node.target.name + graph.edge_weights[edge].value+=distances[u]-distances[v] + + print(graph.edge_weights) + all_distances={} + all_next_vertex={} + + for vertex in graph.vertices: + u = vertex + dijkstra_dist,dijkstra_pred=shortest_paths(graph, 'dijkstra', u) + print(dijkstra_pred) + all_distances[u]={} + all_next_vertex[u] = {} + for v in graph.vertices: + if dijkstra_pred[v]==None or dijkstra_pred[v]==u : + all_next_vertex[u][v]=u + else: + all_next_vertex[u][v]=None + if v in dijkstra_dist: + all_distances[u][v]=dijkstra_dist[v]-distances[u]+distances[v] + else: + all_distances[u][v]=float('inf') + + return (all_distances,all_next_vertex) + def topological_sort(graph: Graph, algorithm: str, **kwargs) -> list: """ diff --git a/pydatastructs/graphs/tests/test_algorithms.py b/pydatastructs/graphs/tests/test_algorithms.py index fde3571da..c842bccf4 100644 --- a/pydatastructs/graphs/tests/test_algorithms.py +++ b/pydatastructs/graphs/tests/test_algorithms.py @@ -1,7 +1,7 @@ from pydatastructs import (breadth_first_search, Graph, breadth_first_search_parallel, minimum_spanning_tree, minimum_spanning_tree_parallel, strongly_connected_components, -depth_first_search, shortest_paths, topological_sort, +depth_first_search, shortest_paths,all_pair_shortest_paths, topological_sort, topological_sort_parallel, max_flow) from pydatastructs.utils.raises_util import raises @@ -336,7 +336,7 @@ def _test_shortest_paths_negative_edges(ds, algorithm): graph.add_edge('2', '3', 3) graph.add_edge('3', '4', 2) graph.add_edge('4', '2', -1) - dist, next_v = shortest_paths(graph, algorithm, 's') + dist, next_v = all_pair_shortest_paths(graph, algorithm) assert dist == {'1': {'3': -2, '1': 0, '4': 0, '2': -1}, '2': {'1': 4, '3': 2, '2': 0, '4': 4}, '3': {'4': 2, '3': 0, '1': 5, '2': 1}, @@ -346,6 +346,10 @@ def _test_shortest_paths_negative_edges(ds, algorithm): '3': {'4': '3', '3': '3', '1': None, '2': None}, '4': {'2': '4', '4': '4', '1': None, '3': None}} + _test_shortest_paths_negative_edges("List",'floyd_warshall') + _test_shortest_paths_negative_edges("Matrix",'floyd_warshall') + _test_shortest_paths_negative_edges("List",'johnson') + def test_topological_sort(): def _test_topological_sort(func, ds, algorithm, threads=None): From 2629bbdb829519c7212ee589fb5e1e49f01e7eda Mon Sep 17 00:00:00 2001 From: Prerak Singh Date: Sat, 8 Mar 2025 23:40:03 +0530 Subject: [PATCH 2/4] Documentation Update --- pydatastructs/graphs/algorithms.py | 44 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/pydatastructs/graphs/algorithms.py b/pydatastructs/graphs/algorithms.py index 3b190c6d2..5d417fc02 100644 --- a/pydatastructs/graphs/algorithms.py +++ b/pydatastructs/graphs/algorithms.py @@ -826,6 +826,7 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str, are implemented, 'floyd_warshall' -> Floyd Warshall algorithm as given in [1]. + 'johnson' -> Johnson's Algorithm as given in [2] backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available @@ -858,6 +859,7 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str, ========== .. [1] https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm + .. [2] https://en.wikipedia.org/wiki/Johnson's_algorithm """ raise_if_backend_is_not_python( all_pair_shortest_paths, kwargs.get('backend', Backend.PYTHON)) @@ -901,49 +903,47 @@ def _floyd_warshall_adjacency_list(graph: Graph): _floyd_warshall_adjacency_matrix = _floyd_warshall_adjacency_list def _johnson_adjacency_list(graph: Graph): - new_vertex=AdjacencyListGraphNode('q') + new_vertex=AdjacencyListGraphNode('__q__') graph.add_vertex(new_vertex) for vertex in graph.vertices: - if vertex != 'q': - graph.add_edge('q',vertex,0) + if vertex != '__q__': + graph.add_edge('__q__',vertex,0) - distances, predecessors=shortest_paths(graph,'bellman_ford','q') + distances, predecessors = shortest_paths(graph,'bellman_ford','__q__') - edges_to_remove=[] + edges_to_remove = [] for edge in graph.edge_weights: - edge_node=graph.edge_weights[edge] - if edge_node.source.name=='q': + edge_node = graph.edge_weights[edge] + if edge_node.source.name == '__q__': edges_to_remove.append((edge_node.source.name,edge_node.target.name)) for u,v in edges_to_remove: graph.remove_edge(u,v) - graph.remove_vertex('q') + graph.remove_vertex('__q__') for edge in graph.edge_weights: - edge_node=graph.edge_weights[edge] - u,v=edge_node.source.name,edge_node.target.name - graph.edge_weights[edge].value+=distances[u]-distances[v] + edge_node = graph.edge_weights[edge] + u,v = edge_node.source.name,edge_node.target.name + graph.edge_weights[edge].value += distances[u]-distances[v] - print(graph.edge_weights) - all_distances={} - all_next_vertex={} + all_distances = {} + all_next_vertex = {} for vertex in graph.vertices: u = vertex - dijkstra_dist,dijkstra_pred=shortest_paths(graph, 'dijkstra', u) - print(dijkstra_pred) - all_distances[u]={} + dijkstra_dist,dijkstra_pred = shortest_paths(graph, 'dijkstra', u) + all_distances[u] = {} all_next_vertex[u] = {} for v in graph.vertices: - if dijkstra_pred[v]==None or dijkstra_pred[v]==u : - all_next_vertex[u][v]=u + if dijkstra_pred[v] is None or dijkstra_pred[v] == u : + all_next_vertex[u][v] = u else: - all_next_vertex[u][v]=None + all_next_vertex[u][v] = None if v in dijkstra_dist: - all_distances[u][v]=dijkstra_dist[v]-distances[u]+distances[v] + all_distances[u][v] = dijkstra_dist[v]-distances[u]+distances[v] else: - all_distances[u][v]=float('inf') + all_distances[u][v] = float('inf') return (all_distances,all_next_vertex) From 74663b26a3d12bfd13a5eede39ca6b45a724c7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A8=97=E0=A8=97=E0=A8=A8=E0=A8=A6=E0=A9=80=E0=A8=AA=20?= =?UTF-8?q?=E0=A8=B8=E0=A8=BF=E0=A9=B0=E0=A8=98=20=28Gagandeep=20Singh=29?= Date: Mon, 10 Mar 2025 10:34:14 +0530 Subject: [PATCH 3/4] Apply suggestions from code review --- pydatastructs/graphs/algorithms.py | 20 +++++++++---------- pydatastructs/graphs/tests/test_algorithms.py | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pydatastructs/graphs/algorithms.py b/pydatastructs/graphs/algorithms.py index 5d417fc02..78a1cfc75 100644 --- a/pydatastructs/graphs/algorithms.py +++ b/pydatastructs/graphs/algorithms.py @@ -903,36 +903,36 @@ def _floyd_warshall_adjacency_list(graph: Graph): _floyd_warshall_adjacency_matrix = _floyd_warshall_adjacency_list def _johnson_adjacency_list(graph: Graph): - new_vertex=AdjacencyListGraphNode('__q__') + new_vertex = AdjacencyListGraphNode('__q__') graph.add_vertex(new_vertex) for vertex in graph.vertices: if vertex != '__q__': - graph.add_edge('__q__',vertex,0) + graph.add_edge('__q__', vertex, 0) - distances, predecessors = shortest_paths(graph,'bellman_ford','__q__') + distances, predecessors = shortest_paths(graph, 'bellman_ford', '__q__') edges_to_remove = [] for edge in graph.edge_weights: edge_node = graph.edge_weights[edge] if edge_node.source.name == '__q__': - edges_to_remove.append((edge_node.source.name,edge_node.target.name)) + edges_to_remove.append((edge_node.source.name, edge_node.target.name)) - for u,v in edges_to_remove: - graph.remove_edge(u,v) + for u, v in edges_to_remove: + graph.remove_edge(u, v) graph.remove_vertex('__q__') for edge in graph.edge_weights: edge_node = graph.edge_weights[edge] - u,v = edge_node.source.name,edge_node.target.name - graph.edge_weights[edge].value += distances[u]-distances[v] + u, v = edge_node.source.name, edge_node.target.name + graph.edge_weights[edge].value += (distances[u] - distances[v]) all_distances = {} all_next_vertex = {} for vertex in graph.vertices: u = vertex - dijkstra_dist,dijkstra_pred = shortest_paths(graph, 'dijkstra', u) + dijkstra_dist, dijkstra_pred = shortest_paths(graph, 'dijkstra', u) all_distances[u] = {} all_next_vertex[u] = {} for v in graph.vertices: @@ -941,7 +941,7 @@ def _johnson_adjacency_list(graph: Graph): else: all_next_vertex[u][v] = None if v in dijkstra_dist: - all_distances[u][v] = dijkstra_dist[v]-distances[u]+distances[v] + all_distances[u][v] = dijkstra_dist[v] - distances[u] + distances[v] else: all_distances[u][v] = float('inf') diff --git a/pydatastructs/graphs/tests/test_algorithms.py b/pydatastructs/graphs/tests/test_algorithms.py index c842bccf4..f1586f512 100644 --- a/pydatastructs/graphs/tests/test_algorithms.py +++ b/pydatastructs/graphs/tests/test_algorithms.py @@ -346,9 +346,9 @@ def _test_shortest_paths_negative_edges(ds, algorithm): '3': {'4': '3', '3': '3', '1': None, '2': None}, '4': {'2': '4', '4': '4', '1': None, '3': None}} - _test_shortest_paths_negative_edges("List",'floyd_warshall') - _test_shortest_paths_negative_edges("Matrix",'floyd_warshall') - _test_shortest_paths_negative_edges("List",'johnson') + _test_shortest_paths_negative_edges("List", 'floyd_warshall') + _test_shortest_paths_negative_edges("Matrix", 'floyd_warshall') + _test_shortest_paths_negative_edges("List", 'johnson') def test_topological_sort(): From 97630aded247ea223b2c54072023cc99fcc6d92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A8=97=E0=A8=97=E0=A8=A8=E0=A8=A6=E0=A9=80=E0=A8=AA=20?= =?UTF-8?q?=E0=A8=B8=E0=A8=BF=E0=A9=B0=E0=A8=98=20=28Gagandeep=20Singh=29?= Date: Mon, 10 Mar 2025 10:36:12 +0530 Subject: [PATCH 4/4] Apply suggestions from code review --- pydatastructs/graphs/algorithms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydatastructs/graphs/algorithms.py b/pydatastructs/graphs/algorithms.py index 78a1cfc75..204c2fbd8 100644 --- a/pydatastructs/graphs/algorithms.py +++ b/pydatastructs/graphs/algorithms.py @@ -945,7 +945,7 @@ def _johnson_adjacency_list(graph: Graph): else: all_distances[u][v] = float('inf') - return (all_distances,all_next_vertex) + return (all_distances, all_next_vertex) def topological_sort(graph: Graph, algorithm: str, **kwargs) -> list: