CSE-41XX
CS-4101 AI

Lecture 04.2: A* Search and Extensions

Understanding A* search, admissible heuristics, and advanced variations like Weighted A* and IDA*.

Greedy Best-First Search is fast but not optimal, because it only looks at the estimated distance to the goal (h(n)h(n)) and ignores the cost of the path accumulated so far (g(n)g(n)).

To achieve optimal search, we want to minimize the overall length of the path. We introduce g(n)g(n) as the exact cost of the best path found so far from the initial node to node nn.


A Search* combines uniform-cost search (which minimizes path cost g(n)g(n)) with greedy best-first search (which minimizes estimated goal distance h(n)h(n)). The core intuition is to avoid expanding paths that are already expensive.

The evaluation function for A* is: f(n)=g(n)+h(n)f(n) = g(n) + h(n)

  • g(n)g(n): Exact cost so far to reach node nn from the initial state.
  • h(n)h(n): Estimated cost from node nn to the nearest goal state.
  • f(n)f(n): Estimated total cost of the cheapest solution path through node nn to a goal.

Admissible Heuristics

For A* search to guarantee an optimal solution, the heuristic function h(n)h(n) must be admissible.

Let h(n)h^*(n) be the true cost of the optimal path from node nn to a goal node. A heuristic h(n)h(n) is admissible if it never overestimates the cost to reach the goal: 0h(n)h(n)0 \le h(n) \le h^*(n)

An admissible heuristic is always optimistic. Because an admissible heuristic never overestimates the remaining distance, A* will never mistakenly rule out or skip over a path that could lead to an optimal goal state.


Visualizing Step-by-Step A* Expansion

Let's return to finding a route from Arad to Bucharest using f(n)=g(n)+h(n)f(n) = g(n) + h(n) with hSLD(n)h_{SLD}(n):

Romania Road Network and Straight-Line Distances (h_SLD) to Bucharest

Step-by-Step Search Trace

  1. Start at Arad: g(Arad)=0g(\text{Arad}) = 0, h(Arad)=366    f(Arad)=366h(\text{Arad}) = 366 \implies f(\text{Arad}) = 366.
  2. Expand Arad:
    • Sibiu: g=140,h=253    f=393g = 140, h = 253 \implies f = 393
    • Timisoara: g=118,h=329    f=447g = 118, h = 329 \implies f = 447
    • Zerind: g=75,h=374    f=449g = 75, h = 374 \implies f = 449
    • Frontier: [Sibiu (393), Timisoara (447), Zerind (449)] \rightarrow Expand Sibiu (f=393f=393).
  3. Expand Sibiu:
    • Rimnicu Vilcea: g=220,h=193    f=413g = 220, h = 193 \implies f = 413
    • Fagaras: g=239,h=176    f=415g = 239, h = 176 \implies f = 415
    • Arad: g=280,h=366    f=646g = 280, h = 366 \implies f = 646
    • Oradea: g=291,h=380    f=671g = 291, h = 380 \implies f = 671
    • Frontier: [Rimnicu Vilcea (413), Fagaras (415), Timisoara (447), Zerind (449), Arad (646), Oradea (671)] \rightarrow Expand Rimnicu Vilcea (f=413f=413).
  4. Expand Rimnicu Vilcea:
    • Pitesti: g=317,h=100    f=417g = 317, h = 100 \implies f = 417
    • Craiova: g=366,h=160    f=526g = 366, h = 160 \implies f = 526
    • Sibiu: g=300,h=253    f=553g = 300, h = 253 \implies f = 553
    • Frontier: [Fagaras (415), Pitesti (417), Timisoara (447), Zerind (449), Craiova (526), Sibiu (553)] \rightarrow Expand Fagaras (f=415f=415).
  5. Expand Fagaras:
    • Bucharest: g=450,h=0    f=450g = 450, h = 0 \implies f = 450
    • Frontier: [Pitesti (417), Timisoara (447), Zerind (449), Bucharest via Fagaras (450), Craiova (526)] \rightarrow A* does not stop yet! Pitesti (f=417f=417) has a lower ff-value than Bucharest via Fagaras (f=450f=450). Expand Pitesti (f=417f=417).
  6. Expand Pitesti:
    • Bucharest: g=418,h=0    f=418g = 418, h = 0 \implies f = 418
    • Frontier: [Bucharest via Pitesti (418), Timisoara (447), Zerind (449), Bucharest via Fagaras (450)] \rightarrow Pop Bucharest via Pitesti (f=418f=418). Goal selected from queue!

By evaluating total path cost f(n)=g(n)+h(n)f(n) = g(n) + h(n), A correctly pivots away from the non-optimal route via Fagaras and finds the optimal path:* AradSibiuRimnicu VilceaPitestiBucharest(Cost=418)\text{Arad} \rightarrow \text{Sibiu} \rightarrow \text{Rimnicu Vilcea} \rightarrow \text{Pitesti} \rightarrow \text{Bucharest} \quad (\text{Cost} = 418)


FeatureGreedy Best-First SearchA* Search
Evaluation Functionf(n)=h(n)f(n) = h(n)f(n)=g(n)+h(n)f(n) = g(n) + h(n)
Cost ConsiderationIgnores accumulated path cost g(n)g(n)Balances accumulated path cost g(n)g(n) and estimated remaining cost h(n)h(n)
Optimal Path (Romania)AradSibiuFagarasBucharest\text{Arad} \rightarrow \text{Sibiu} \rightarrow \text{Fagaras} \rightarrow \text{Bucharest} (Cost: 450450)AradSibiuRimnicu VilceaPitestiBucharest\text{Arad} \rightarrow \text{Sibiu} \rightarrow \text{Rimnicu Vilcea} \rightarrow \text{Pitesti} \rightarrow \text{Bucharest} (Cost: 418418)
Optimality GuaranteeNon-optimalGuaranteed optimal (if h(n)h(n) is admissible)
CompletenessComplete only with repeated state eliminationComplete

The Effect of the Heuristic Function

The choice of evaluation function drastically alters search behavior:

  • Dijkstra’s Algorithm (Uniform-Cost Search): Expands states in order of f(n)=g(n)f(n) = g(n) (equivalent to A* with h(n)=0h(n) = 0). It explores outward in all directions equally like ripples in water.
  • A Search:* Expands states in order of f(n)=g(n)+h(n)f(n) = g(n) + h(n). It directs exploration toward the goal, eliminating unnecessary state expansions.
  • Weighted A Search:* Expands states in order of f(n)=g(n)+Wh(n)f(n) = g(n) + W \cdot h(n), where W>1W > 1. This heavily weights estimated remaining distance, speeding up computation while bounding suboptimality to at most W×optimal costW \times \text{optimal cost}.

Even with a good heuristic, A* must keep all generated nodes in memory (O(bd)O(b^d) space complexity) to reconstruct the optimal path and prevent revisit loops, which can lead to memory exhaustion on very large search spaces.


Advanced Extensions of A*

To overcome memory limitations and speed up search, several variations of A* exist:

1. Bidirectional A*

  • Idea: Runs two simultaneous A* searches—one forward from the start state and one backward from the goal state—meeting in the middle.
  • Use Case: Drastically reduces the search tree depth, provided an effective heuristic exists in both directions.

2. Iterative Deepening A* (IDA*)

  • Idea: Combines A* evaluation with iterative deepening depth-first search. Instead of limiting depth, each iteration uses an increasing ff-cost limit (threshold).
  • Use Case: Reduces space complexity from exponential O(bd)O(b^d) to linear O(bd)O(bd) (like DFS) while retaining A*'s optimality.

3. Beam A*

  • Idea: Combines A* with beam search by truncating the frontier to a fixed maximum "beam width" kk. Only the kk best nodes are retained at each level.
  • Use Case: Essential when memory is strictly constrained or when an approximate fast solution is acceptable.

On this page