Skip to content

Commit b2937ee

Browse files
feat: replace Bellman Ford Algorithm with queue version
1 parent 2a83fec commit b2937ee

File tree

2 files changed

+22
-53
lines changed

2 files changed

+22
-53
lines changed

pydatastructs/graphs/algorithms.py

Lines changed: 22 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -697,11 +697,9 @@ def shortest_paths(graph: Graph, algorithm: str,
697697
The algorithm to be used. Currently, the following algorithms
698698
are implemented,
699699
700-
'bellman_ford' -> Bellman-Ford algorithm as given in [1].
700+
'bellman_ford' -> Bellman-Ford algorithm as given in [1], with a queue to improve performance on sparse graphs.
701701
702702
'dijkstra' -> Dijkstra algorithm as given in [2].
703-
704-
'queue_improved_bellman_ford' -> Queue Improved Bellman-Ford algorithm as given in [3].
705703
source: str
706704
The name of the source the node.
707705
target: str
@@ -744,7 +742,6 @@ def shortest_paths(graph: Graph, algorithm: str,
744742
745743
.. [1] https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
746744
.. [2] https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
747-
.. [3] https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm#Improvements
748745
"""
749746
raise_if_backend_is_not_python(
750747
shortest_paths, kwargs.get('backend', Backend.PYTHON))
@@ -757,27 +754,34 @@ def shortest_paths(graph: Graph, algorithm: str,
757754
return getattr(algorithms, func)(graph, source, target)
758755

759756
def _bellman_ford_adjacency_list(graph: Graph, source: str, target: str) -> tuple:
760-
distances, predecessor = {}, {}
757+
distances, predecessor, visited, cnts = {}, {}, {}, {}
761758

762759
for v in graph.vertices:
763760
distances[v] = float('inf')
764761
predecessor[v] = None
762+
visited[v] = False
763+
cnts[v] = 0
765764
distances[source] = 0
765+
verticy_num = len(graph.vertices)
766766

767-
edges = graph.edge_weights.values()
768-
for _ in range(len(graph.vertices) - 1):
769-
for edge in edges:
770-
u, v = edge.source.name, edge.target.name
771-
w = edge.value
772-
if distances[u] + edge.value < distances[v]:
773-
distances[v] = distances[u] + w
774-
predecessor[v] = u
767+
que = Queue([source])
775768

776-
for edge in edges:
777-
u, v = edge.source.name, edge.target.name
778-
w = edge.value
779-
if distances[u] + w < distances[v]:
780-
raise ValueError("Graph contains a negative weight cycle.")
769+
while que:
770+
u = que.popleft()
771+
visited[u] = False
772+
neighbors = graph.neighbors(u)
773+
for neighbor in neighbors:
774+
v = neighbor.name
775+
edge_str = u + '_' + v
776+
if distances[u] != float('inf') and distances[u] + graph.edge_weights[edge_str].value < distances[v]:
777+
distances[v] = distances[u] + graph.edge_weights[edge_str].value
778+
predecessor[v] = u
779+
cnts[v] = cnts[u] + 1
780+
if cnts[v] >= verticy_num:
781+
raise ValueError("Graph contains a negative weight cycle.")
782+
if not visited[v]:
783+
que.append(v)
784+
visited[v] = True
781785

782786
if target != "":
783787
return (distances[target], predecessor)
@@ -814,37 +818,6 @@ def _dijkstra_adjacency_list(graph: Graph, start: str, target: str):
814818

815819
_dijkstra_adjacency_matrix = _dijkstra_adjacency_list
816820

817-
def _queue_improved_bellman_ford_adjacency_list(graph: Graph, source: str, target: str) -> tuple:
818-
distances, predecessor, visited = {}, {}, {}
819-
820-
for v in graph.vertices:
821-
distances[v] = float('inf')
822-
predecessor[v] = None
823-
visited[v] = False
824-
distances[source] = 0
825-
826-
que = Queue([source])
827-
828-
while que:
829-
u = que.popleft()
830-
visited[u] = False
831-
neighbors = graph.neighbors(u)
832-
for neighbor in neighbors:
833-
v = neighbor.name
834-
edge_str = u + '_' + v
835-
if distances[u] != float('inf') and distances[u] + graph.edge_weights[edge_str].value < distances[v]:
836-
distances[v] = distances[u] + graph.edge_weights[edge_str].value
837-
predecessor[v] = u
838-
if not visited[v]:
839-
que.append(v)
840-
visited[v] = True
841-
842-
if target != "":
843-
return (distances[target], predecessor)
844-
return (distances, predecessor)
845-
846-
_queue_improved_bellman_ford_adjacency_matrix = _queue_improved_bellman_ford_adjacency_list
847-
848821
def all_pair_shortest_paths(graph: Graph, algorithm: str,
849822
**kwargs) -> tuple:
850823
"""

pydatastructs/graphs/tests/test_algorithms.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,6 @@ def _test_shortest_paths_negative_edges(ds, algorithm):
321321
_test_shortest_paths_negative_edges("Matrix", 'bellman_ford')
322322
_test_shortest_paths_positive_edges("List", 'dijkstra')
323323
_test_shortest_paths_positive_edges("Matrix", 'dijkstra')
324-
_test_shortest_paths_positive_edges("List", 'queue_improved_bellman_ford')
325-
_test_shortest_paths_positive_edges("Matrix", 'queue_improved_bellman_ford')
326-
_test_shortest_paths_negative_edges("List", 'queue_improved_bellman_ford')
327-
_test_shortest_paths_negative_edges("Matrix", 'queue_improved_bellman_ford')
328324

329325
def test_all_pair_shortest_paths():
330326

0 commit comments

Comments
 (0)