Uninformed search algorithms like breadth-first search (BFS) and uniform-cost search (UCS) explore the state space blindly, treating all nodes equally until a goal is found. For many problems, this is prohibitively slow: a warehouse robot navigating a 100×100 grid might expand thousands of nodes before reaching the goal. Informed search uses domain-specific knowledge in the form of a heuristic function to guide exploration toward promising states. The most celebrated informed algorithm is A*, which combines the path cost of UCS with a heuristic estimate to the goal. This section covers heuristics, their properties, and A*, then explores variants for practical applications where perfect solutions are less important than fast answers.
A heuristic function \(h(n)\) estimates the cost of the cheapest path from node \(n\) (with state \(s = \text{state}(n)\)) to a goal state. The estimate is used to prioritize which nodes to expand during search.
In the warehouse example, if the robot needs to reach a goal location \((g_x, g_y)\) from its current position \((x, y)\), a natural heuristic is the Manhattan distance:
\[h(n) = |x - g_x| + |y - g_y|\]
This estimate is cheaper than the true path cost because it ignores obstacles and robot dynamics—Manhattan distance assumes a straight-line-like path on a grid. Yet it provides useful guidance: there is often a cheaper path to the goal from states that are closer by Manhattan distance.
Not all heuristics are equally useful. Two key properties determine whether a heuristic provides correctness guarantees.
A heuristic \(h(n)\) is admissible if it never overestimates the true cost to the goal. Formally: \(h(n) \leq c^*(n)\), where \(c^*(n)\) is the actual minimum cost from node \(n\) to a goal.
Intuition: An admissible heuristic is optimistic. It says "the goal is at least this far away," and the true minimum distance is never less.
Example: Manhattan distance on a grid with obstacles is admissible because obstacles only increase the path cost. Without obstacles, Manhattan distance is the minimum; with obstacles, it may underestimate.
A heuristic \(h(n)\) is consistent if for every node \(n\) and its successor \(n'\) reached by action \(a\) with step cost \(c(n, a, n')\):
\[h(n) \leq c(n, a, n') + h(n')\]
Intuition: This is admissibility applied to each step: the cost to get to \(n'\) must be more than or equal to the decrease in heuristic value. We see then why consistency is also called monotonicity.
Relationship: Every consistent heuristic is admissible. The converse is not always true: an admissible heuristic may not be consistent. However, consistency is the stronger property and is what enables efficient graph search in A*. In practice, most useful heuristics are consistent.
Example: Manhattan distance is consistent on a grid because for any step the heuristic can decrease by at most the step cost.
Three common heuristics for pathfinding in warehouse domains:
The Manhattan distance (or "taxicab distance") between two points \((x_1, y_1)\) and \((x_2, y_2)\) is:
\[d_M = |x_1 - x_2| + |y_1 - y_2|\]
It represents the minimum number of moves on an axis-aligned grid without obstacles.
Consider a grid world where the robot can move only in the four cardinal directions. Is the heuristic:
Admissible? Yes because obstacles only increase cost
Consistent? Yes because any step can reduce distance by at most the step cost
The Manhattan distance is fast, simple, and effective when obstacles are sparse. However, since it ignores obstacles, it may lead a search astray in cluttered environments.
The Euclidean distance is the straight-line distance:
\[d_E = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}\]
In grid worlds where diagonal movement is allowed, Euclidean distance can provide a tighter estimate than Manhattan distance. Is the heuristic: Admissible? Yes (straight line is always shortest)
Consistent? On grids with diagonal moves (cost ~1.414), Euclidean may violate consistency with uniform costs. Generally consistent in continuous spaces where diagonal costs match \(\sqrt{2}\).
The Euclidean distance is more accurate than Manhattan in environments with diagonal movement; it dominates Manhattan distance (\(d_E < d_M\)), leading to fewer nodes expanded.
In multi-robot or dynamic warehouse environments, congestion—areas where many robots compete—can inflate path costs beyond simple distance metrics. A congestion-aware heuristic augments distance with occupancy data:
\[h(n) = d_M(\text{state}(n), \text{goal}) + \lambda \cdot \text{occupancy}(\text{state}(n))\]
where \(\text{occupancy}(s)\) reflects the density of robots or obstacles in the region near \(s\), and \(\lambda > 0\) is a weighting parameter.
Is the heuristic admissible? Requires careful tuning; naive congestion penalties can overestimate
For multi-robot coordination in dynamic environments, congestion-aware heuristics can significantly improve pathfinding efficiency by steering robots away from crowded areas.
Now we formalize A*, which combines path cost and heuristic estimates.
A* search expands nodes in order of the evaluation function:
\[f(n) = g(n) + h(n)\]
where \(g(n)\) is the cost from the start to node \(n\), and \(h(n)\) is the heuristic estimate from node \(n\) to a goal. A* uses a priority queue ordered by \(f(n)\).
Relationship to other algorithms:
Here is a standard A* implementation using graph search (which maintains an explored set):
def a_star(problem, h):
node = Node(problem.initial_state, g=0, h=h(problem.initial_state))
frontier = priority queue (ordered by f = g + h)
frontier.add(node, priority=node.h)
explored = set()
while frontier not empty:
node = frontier.pop() # expand node with lowest f(n) first
if problem.goal_test(node.state):
return node
explored.add(node.state)
for action, child_state, step_cost in problem.successors(node.state):
if child_state not in explored:
g_child = node.g + step_cost
h_child = h(child_state)
child = Node(child_state, parent=node, action=action,
g=g_child, h=h_child)
# If child already in frontier with higher cost, update it
frontier.add_or_update(child, priority=g_child + h_child)
return NoneA key variant is tree search (without the explored set), which allows revisiting states but guarantees optimality with admissible heuristics, though sometimes less efficiently.
For finite state spaces and positive action costs, A* is complete: if a solution exists, it will find one.
The optimality of A* depends on the heuristic used.
Since \(h(n)\) never overestimates, A* will not overlook a potentially optimal path. It expands nodes in order of increasing \(f(n)\), ensuring that once a goal is reached, no cheaper path exists.
If the heuristic is also consistent, A* avoids re-expanding nodes, making it more efficient.
In practice, A* can be slow if the problem is large or the heuristic is weak. Several variants trade off solution quality for speed.
Weighted A* modifies the evaluation function:
\[f(n) = g(n) + w \cdot h(n)\]
where \(w > 1\) is a weight. Larger \(w\) emphasizes the heuristic, expanding fewer nodes but risking suboptimal solutions.
Behavior:
Warehouse example: A robot with a 10-hour battery might use \(w = 2\) to find a "good enough" path quickly, ensuring energy efficiency without insisting on the absolute optimal route.
Anytime search starts with a high weight (greedy, fast, suboptimal) and gradually decreases it over time, improving solution quality as computation allows. If interrupted, it returns the best solution found so far.
def anytime_a_star(problem, h, time_limit):
best_solution = None
w = w_initial # start with high weight (e.g., 5)
start_time = current_time()
while current_time() - start_time < time_limit:
solution = weighted_a_star(problem, h, w)
if solution and (best_solution is None or
cost(solution) < cost(best_solution)):
best_solution = solution
w = w - 0.1 # gradually decrease weight
return best_solutionThe advantages of the anytime approach are that it greedily provides a usable solution quickly and refines it as time permits. Use cases include real-time applications like robots navigating dynamic environments and live path replanning.
When comparing search algorithms, measure:
For new domains, heuristics must be engineered carefully. This section gives practical guidance.
A relaxed problem removes constraints from the original, making the goal easier to reach. The optimal solution cost of the relaxed problem is an admissible heuristic for the original.
Example: Warehouse routing
Relaxation 2's heuristic is always \(\leq\) Relaxation 1's, so in a world without diagonal movement, the Manhattan distance is always better (i.e., closer to true cost). Globally, we call this the dominance of the larger heuristic. Larger is always better for admissible heuristics (which never overestimate) because it provides tighter estimates, leading to fewer node expansions in A*.
If multiple relaxations exist, combine them using dominance:
\[h(n) = \max(h_1(n), h_2(n), \ldots, h_k(n))\]
Dominance means \(h_i\) will expand fewer nodes in A* search. Taking the max of multiple admissible heuristics creates a new admissible heuristic that dominates each individual heuristic.
Example: For warehouse routing with multiple objectives (reach goal, avoid obstacles, minimize energy), compute heuristics for each and take the max to get a stronger estimate. The downside is increased computation per node, but the reduced search space often compensates.
For repeated problem instances (e.g., many warehouse routing queries), you can learn better heuristics:
This approach bridges uninformed and learned search, useful when domain-specific knowledge is expensive to encode but many similar problems arise.
Informed search uses heuristics—domain-specific estimates of progress toward the goal—to guide exploration. A* combines actual cost \(g\) and estimated cost \(h\) to balance exploration and exploitation. With admissible heuristics, A* guarantees optimality; with weighted variants, it trades off solution quality for speed. Designing good heuristics requires understanding the problem structure: relaxations, composition, and learning can all help.
All the search algorithms we've studied so far—BFS, UCS, A*—maintain a search tree or frontier and explore paths systematically. But for many optimization problems, we don't need the path, just the solution itself. The next section introduces local search, which operates on a single current state and iteratively improves it, trading completeness for memory efficiency and scalability.
Theorem: A* with admissible heuristic
If the heuristic \(h(n)\) is admissible, A* will find an optimal path (lowest cost solution).