|
3 | 3 | data structure.
|
4 | 4 | """
|
5 | 5 | from collections import deque
|
| 6 | +from typing import Tuple, Dict |
6 | 7 | from concurrent.futures import ThreadPoolExecutor
|
7 | 8 | from pydatastructs.utils.misc_util import (
|
8 | 9 | _comp, raise_if_backend_is_not_python, Backend)
|
@@ -826,6 +827,7 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str,
|
826 | 827 | are implemented,
|
827 | 828 |
|
828 | 829 | 'floyd_warshall' -> Floyd Warshall algorithm as given in [1].
|
| 830 | + 'floyd_warshall_parallel' -> Parallel Floyd Warshall algorithm as given in [2]. |
829 | 831 | backend: pydatastructs.Backend
|
830 | 832 | The backend to be used.
|
831 | 833 | Optional, by default, the best available
|
@@ -853,11 +855,17 @@ def all_pair_shortest_paths(graph: Graph, algorithm: str,
|
853 | 855 | 21
|
854 | 856 | >>> dist['V3']['V1']
|
855 | 857 | 5
|
| 858 | + >>> dist, _ = all_pair_shortest_paths(G, 'floyd_warshall_parallel') |
| 859 | + >>> dist['V1']['V3'] |
| 860 | + 21 |
| 861 | + >>> dist['V3']['V1'] |
| 862 | + 5 |
856 | 863 |
|
857 | 864 | References
|
858 | 865 | ==========
|
859 | 866 |
|
860 | 867 | .. [1] https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
|
| 868 | + .. [2] https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm#Parallel_execution |
861 | 869 | """
|
862 | 870 | raise_if_backend_is_not_python(
|
863 | 871 | all_pair_shortest_paths, kwargs.get('backend', Backend.PYTHON))
|
@@ -900,6 +908,44 @@ def _floyd_warshall_adjacency_list(graph: Graph):
|
900 | 908 |
|
901 | 909 | _floyd_warshall_adjacency_matrix = _floyd_warshall_adjacency_list
|
902 | 910 |
|
| 911 | +def _floyd_warshall_parallel_adjacency_list(graph: Graph) -> Tuple[Dict, Dict]: |
| 912 | + """ |
| 913 | + Parallel Floyd-Warshall using ThreadPoolExecutor. |
| 914 | + Ensures correct updates of both distance and next_vertex matrices. |
| 915 | +
|
| 916 | + :param graph: Graph object with vertices and edge_weights. |
| 917 | + :return: Tuple (dist, next_vertex) matrices. |
| 918 | + """ |
| 919 | + dist, next_vertex = {}, {} |
| 920 | + V, E = graph.vertices, graph.edge_weights |
| 921 | + |
| 922 | + # Initialize distance and next vertex matrices |
| 923 | + for v in V: |
| 924 | + dist[v] = {u: float('inf') for u in V} |
| 925 | + next_vertex[v] = {u: None for u in V} |
| 926 | + dist[v][v] = 0 # Distance to itself is 0 |
| 927 | + |
| 928 | + # Populate initial distances from edges |
| 929 | + for name, edge in E.items(): |
| 930 | + dist[edge.source.name][edge.target.name] = edge.value |
| 931 | + next_vertex[edge.source.name][edge.target.name] = edge.target.name |
| 932 | + |
| 933 | + def _update_row(i, k): |
| 934 | + """Update a single row in parallel.""" |
| 935 | + for j in V: |
| 936 | + if dist[i][j] > dist[i][k] + dist[k][j]: |
| 937 | + dist[i][j] = dist[i][k] + dist[k][j] |
| 938 | + next_vertex[i][j] = next_vertex[i][k] if next_vertex[i][k] else k |
| 939 | + |
| 940 | + # Parallel Floyd-Warshall execution |
| 941 | + for k in V: |
| 942 | + with ThreadPoolExecutor() as executor: |
| 943 | + executor.map(lambda i: _update_row(i, k), V) |
| 944 | + |
| 945 | + return dist, next_vertex |
| 946 | + |
| 947 | +_floyd_warshall_parallel_adjacency_matrix = _floyd_warshall_parallel_adjacency_list |
| 948 | + |
903 | 949 | def topological_sort(graph: Graph, algorithm: str,
|
904 | 950 | **kwargs) -> list:
|
905 | 951 | """
|
|
0 commit comments