Skip to content

Uniform Cost Search algorithm #12286

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

Closed
wants to merge 2 commits into from
Closed
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
102 changes: 102 additions & 0 deletions graphs/uniform_cost_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/python

"""Author: MRINAL"""

from __future__ import annotations
from queue import PriorityQueue


class Graph:

Check failure on line 9 in graphs/uniform_cost_search.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

graphs/uniform_cost_search.py:5:1: I001 Import block is un-sorted or un-formatted
def __init__(self) -> None:
# Graph represented as an adjacency list with edge weights
self.vertices: dict[int, list[tuple[int, int]]] = {}

def print_graph(self) -> None:
"""
Prints adjacency list representation of the graph.
>>> g = Graph()
>>> g.add_edge(0, 1, 2)
>>> g.add_edge(0, 2, 4)
>>> g.print_graph()
0 : [(1, 2), (2, 4)]
"""
for i in self.vertices:
print(i, " : ", self.vertices[i])

def add_edge(self, from_vertex: int, to_vertex: int, cost: int) -> None:
"""
Adds an edge with a specified cost between two vertices.
>>> g = Graph()
>>> g.add_edge(0, 1, 2)
>>> g.print_graph()
0 : [(1, 2)]
"""
if from_vertex in self.vertices:
self.vertices[from_vertex].append((to_vertex, cost))
else:
self.vertices[from_vertex] = [(to_vertex, cost)]

def ucs(self, start_vertex: int, goal_vertex: int) -> tuple[int, list[int]]:
"""
Uniform Cost Search to find the minimum cost path from start to goal.
>>> g = Graph()
>>> g.add_edge(0, 1, 2)
>>> g.add_edge(0, 2, 4)
>>> g.add_edge(1, 2, 1)
>>> g.add_edge(1, 3, 7)
>>> g.add_edge(2, 3, 3)
>>> g.ucs(0, 3)
(6, [0, 1, 2, 3])
"""
# Priority queue to hold nodes to explore; initializes with (cost, start_vertex)
pq = PriorityQueue()
pq.put((0, start_vertex, [start_vertex]))

# Dictionary to track the minimum cost to reach each vertex
visited = {}

while not pq.empty():
cost, vertex, path = pq.get()

# If the goal is reached, return the cost and path
if vertex == goal_vertex:
return cost, path

# If the vertex is already visited with a lower cost, skip it
if vertex in visited and visited[vertex] <= cost:
continue

# Mark the vertex with the cost for the first time or with a lower cost
visited[vertex] = cost

# Explore neighbors
for neighbor, edge_cost in self.vertices.get(vertex, []):
if neighbor not in visited or visited[neighbor] > cost + edge_cost:
pq.put((cost + edge_cost, neighbor, path + [neighbor]))

Check failure on line 75 in graphs/uniform_cost_search.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (RUF005)

graphs/uniform_cost_search.py:75:57: RUF005 Consider `[*path, neighbor]` instead of concatenation

return float("inf"), [] # If no path found


if __name__ == "__main__":
from doctest import testmod

testmod(verbose=True)

g = Graph()
g.add_edge(0, 1, 2)
g.add_edge(0, 2, 4)
g.add_edge(1, 2, 1)
g.add_edge(1, 3, 7)
g.add_edge(2, 3, 3)

g.print_graph()
# 0 : [(1, 2), (2, 4)]
# 1 : [(2, 1), (3, 7)]
# 2 : [(3, 3)]

result = g.ucs(0, 3)
print("Minimum cost:", result[0])
print("Path:", result[1])
# Expected output:
# Minimum cost: 6
# Path: [0, 1, 2, 3]
Loading