Skip to content

Bi directional dijkstra #7982

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

Merged
merged 27 commits into from
Nov 20, 2022
Merged
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1bca1de
Added Bi-Directional Dijkstra
SwayamInSync Nov 13, 2022
c74289b
Added Bi-Directional Dijkstra
SwayamInSync Nov 13, 2022
c369745
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 13, 2022
4de4d62
Added doctest and type hints
SwayamInSync Nov 13, 2022
c689393
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 13, 2022
0ddf115
Rename Bi_directional_Dijkstra.py to bi_directional_dijkstra.py
SwayamInSync Nov 13, 2022
62fc026
Update bi_directional_dijkstra.py
SwayamInSync Nov 13, 2022
12902d7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 13, 2022
a006750
Update bi_directional_dijkstra.py
SwayamInSync Nov 13, 2022
6620798
Update bi_directional_dijkstra.py
SwayamInSync Nov 13, 2022
80396fe
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 13, 2022
baabd64
Update bi_directional_dijkstra.py
SwayamInSync Nov 13, 2022
4ff3b59
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 13, 2022
a22e0d9
Update bi_directional_dijkstra.py
SwayamInSync Nov 14, 2022
91670cc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2022
35c9e4b
Update bi_directional_dijkstra.py
SwayamInSync Nov 14, 2022
23ac248
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2022
f3cede3
Update bi_directional_dijkstra.py
SwayamInSync Nov 14, 2022
3adab98
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2022
9552936
Update bi_directional_dijkstra.py
SwayamInSync Nov 14, 2022
36e68d3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2022
8a00b3e
Update bi_directional_dijkstra.py
SwayamInSync Nov 15, 2022
d64667e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 15, 2022
10b529a
Update bi_directional_dijkstra.py
SwayamInSync Nov 15, 2022
9425f6f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 15, 2022
c5c4ebe
Update bi_directional_dijkstra.py
SwayamInSync Nov 18, 2022
dc57aae
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions graphs/bi_directional_dijkstra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
"""
Bi-directional Dijkstra's algorithm.

A bi-directional approach is an efficient and
less time consuming optimization for Dijkstra's
searching algorithm

Reference: shorturl.at/exHM7
"""

# Author: Swayam Singh (https://github.com/practice404)


from queue import PriorityQueue
from typing import Any

import numpy as np


def bidirectional_dij(
source: str, destination: str, graph_forward: dict, graph_backward: dict
) -> int:
"""
Bi-directional Dijkstra's algorithm.
Returns:
shortest_path_distance (int): length of the shortest path.

Warnings:
If the destination is not reachable, function returns -1

>>> bidirectional_dij("E", "F", graph_fwd, graph_bwd)
3
"""
shortest_path_distance = -1

visited_forward = set()
visited_backward = set()
cst_fwd = {source: 0}
cst_bwd = {destination: 0}
parent_forward = {source: None}
parent_backward = {destination: None}
queue_forward: PriorityQueue[Any] = PriorityQueue()
queue_backward: PriorityQueue[Any] = PriorityQueue()

shortest_distance = np.inf

queue_forward.put((0, source))
queue_backward.put((0, destination))

if source == destination:
return 0

while queue_forward and queue_backward:
while not queue_forward.empty():
_, v_fwd = queue_forward.get()

if v_fwd not in visited_forward:
break
else:
break
visited_forward.add(v_fwd)

while not queue_backward.empty():
_, v_bwd = queue_backward.get()

if v_bwd not in visited_backward:
break
else:
break
visited_backward.add(v_bwd)

# forward pass and relaxation
for nxt_fwd, d_forward in graph_forward[v_fwd]:
if nxt_fwd in visited_forward:
continue
old_cost_f = cst_fwd.get(nxt_fwd, np.inf)
new_cost_f = cst_fwd[v_fwd] + d_forward
if new_cost_f < old_cost_f:
queue_forward.put((new_cost_f, nxt_fwd))
cst_fwd[nxt_fwd] = new_cost_f
parent_forward[nxt_fwd] = v_fwd
if nxt_fwd in visited_backward:
if cst_fwd[v_fwd] + d_forward + cst_bwd[nxt_fwd] < shortest_distance:
shortest_distance = cst_fwd[v_fwd] + d_forward + cst_bwd[nxt_fwd]

# backward pass and relaxation
for nxt_bwd, d_backward in graph_backward[v_bwd]:
if nxt_bwd in visited_backward:
continue
old_cost_b = cst_bwd.get(nxt_bwd, np.inf)
new_cost_b = cst_bwd[v_bwd] + d_backward
if new_cost_b < old_cost_b:
queue_backward.put((new_cost_b, nxt_bwd))
cst_bwd[nxt_bwd] = new_cost_b
parent_backward[nxt_bwd] = v_bwd

if nxt_bwd in visited_forward:
if cst_bwd[v_bwd] + d_backward + cst_fwd[nxt_bwd] < shortest_distance:
shortest_distance = cst_bwd[v_bwd] + d_backward + cst_fwd[nxt_bwd]

if cst_fwd[v_fwd] + cst_bwd[v_bwd] >= shortest_distance:
break

if shortest_distance != np.inf:
shortest_path_distance = shortest_distance
return shortest_path_distance


graph_fwd = {
"B": [["C", 1]],
"C": [["D", 1]],
"D": [["F", 1]],
"E": [["B", 1], ["G", 2]],
"F": [],
"G": [["F", 1]],
}
graph_bwd = {
"B": [["E", 1]],
"C": [["B", 1]],
"D": [["C", 1]],
"F": [["D", 1], ["G", 1]],
"E": [[None, np.inf]],
"G": [["E", 2]],
}
Comment on lines +110 to +125
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this within the doctest - its why it failed earlier


if __name__ == "__main__":
import doctest

doctest.testmod()