Skip to content
Open
Changes from all commits
Commits
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
88 changes: 88 additions & 0 deletions searches/dijkstra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""Dijkstra's shortest path algorithm.

This module provides a simple Dijkstra implementation that works on a
graph represented as an adjacency mapping: {node: [(neighbor, weight), ...], ...}.

Functions:
- dijkstra(graph, source) -> (dist, prev)
- shortest_path(prev, target) -> list

Doctests include a small example graph.
"""

from __future__ import annotations

import heapq
from typing import Dict, Iterable, List, Tuple, Any

Check failure on line 16 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP035)

searches/dijkstra.py:16:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead

Check failure on line 16 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP035)

searches/dijkstra.py:16:1: UP035 `typing.List` is deprecated, use `list` instead

Check failure on line 16 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP035)

searches/dijkstra.py:16:1: UP035 `typing.Dict` is deprecated, use `dict` instead

Check failure on line 16 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP035)

searches/dijkstra.py:16:1: UP035 Import from `collections.abc` instead: `Iterable`

Check failure on line 16 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

searches/dijkstra.py:13:1: I001 Import block is un-sorted or un-formatted


def dijkstra(
graph: Dict[Any, Iterable[Tuple[Any, float]]], source: Any

Check failure on line 20 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

searches/dijkstra.py:20:31: UP006 Use `tuple` instead of `Tuple` for type annotation

Check failure on line 20 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

searches/dijkstra.py:20:12: UP006 Use `dict` instead of `Dict` for type annotation
) -> Tuple[Dict[Any, float], Dict[Any, Any]]:

Check failure on line 21 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

searches/dijkstra.py:21:30: UP006 Use `dict` instead of `Dict` for type annotation

Check failure on line 21 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

searches/dijkstra.py:21:12: UP006 Use `dict` instead of `Dict` for type annotation

Check failure on line 21 in searches/dijkstra.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

searches/dijkstra.py:21:6: UP006 Use `tuple` instead of `Tuple` for type annotation
"""Compute shortest path distances from source to all reachable nodes.

Args:
graph: adjacency mapping where graph[u] yields (v, weight) pairs.
source: start node.

Returns:
(dist, prev)
- dist: mapping node -> distance (float). Unreachable nodes are absent.
- prev: mapping node -> predecessor on shortest path (or None for source).

Example:
>>> graph = {
... 'A': [('B', 1), ('C', 4)],
... 'B': [('C', 2), ('D', 5)],
... 'C': [('D', 1)],
... 'D': []
... }
>>> dist, prev = dijkstra(graph, 'A')
>>> dist['D']
4
>>> shortest_path(prev, 'D')
['A', 'B', 'C', 'D']
"""
dist: Dict[Any, float] = {}
prev: Dict[Any, Any] = {}
pq: List[Tuple[float, Any]] = [] # (distance, node)

heapq.heappush(pq, (0.0, source))
dist[source] = 0.0
prev[source] = None

while pq:
d, u = heapq.heappop(pq)
# Skip stale entries
if d != dist.get(u, float("inf")):
continue
for v, w in graph.get(u, []):
nd = d + float(w)
if nd < dist.get(v, float("inf")):
dist[v] = nd
prev[v] = u
heapq.heappush(pq, (nd, v))

return dist, prev


def shortest_path(prev: Dict[Any, Any], target: Any) -> List[Any]:

Choose a reason for hiding this comment

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

As there is no test file in this pull request nor any test function or class in the file searches/dijkstra.py, please provide doctest for the function shortest_path

"""Reconstruct path from source to target using predecessor map.

If target is not in `prev`, returns an empty list.
"""
if target not in prev:
return []
path: List[Any] = []
cur = target
while cur is not None:
path.append(cur)
cur = prev.get(cur)
path.reverse()
return path


if __name__ == "__main__":
import doctest

doctest.testmod()
Loading