Part of World Models Handbook
Covers MCTS, UCT, PUCT, belief-space planning, and POMCP for decision-making under uncertainty with a hidden-state maze and tiger problem.
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Search and Belief-Space Planning
Imagine walking into a building you have never seen, with a hand-drawn floor plan someone gave you. The plan is roughly right. You have a model of the building (the floor plan), an observation (the weak flashlight), and an objective (the room). Your flashlight is weak, and the corridor ahead looks identical to the one behind you. You need to find a specific room, and you need to decide, right now, whether to walk forward, turn back, or stop and look around to figure out where you are.
That scenario contains the entire problem of this chapter. You have a model (the floor plan), an observation (the weak flashlight), and an objective (the room). Turning the model into an action requires something that neither the model nor the objective provides by itself. It requires a decision procedure for evaluating candidate actions or contingent policies and selecting what to do. In this chapter, that decision procedure is search.
Why does that procedure deserve an entire chapter of its own, when the previous chapters already gave us planners? Search allocates compute differently from the preceding planners, which can make it especially useful in some large, discrete, or partially observed problems. To see why, it helps to recall what the alternatives do with their compute.
Search-based planning sits alongside the two planning families you have already seen in this part. In Sampling-Based Planning and Model Predictive Control you saw planners that score sampled action sequences. In Differentiable Planning you saw planners that optimize one smooth action sequence by differentiating through latent state dynamics and a cost over horizon . Both can focus computation: adaptive shooting methods such as CEM refit their proposal distributions, and gradient methods follow local derivatives. Tree search focuses it differently. Each simulation updates branch statistics, and those statistics determine which branch receives the next simulation. This explicit, adaptive allocation is especially useful when the horizon is long, the choices are discrete, or the model is available only as a simulator. It does not imply that all search problems are nondifferentiable; it means tree search does not require derivatives from the simulator interface.
The simulator interface is worth stating precisely. Gradient planning needs derivatives through the model. Shooting methods and Monte Carlo tree search can instead use a generative model: given a state and action, sample a successor, reward, and, for a partially observed problem, an observation. Tree search is therefore a natural option when derivatives are unavailable and discrete branching matters, but its interface is not weaker than every shooting method's interface. Both families can work with forward samples; they differ in how they reuse those samples and allocate the next query.
The second half of the chapter addresses the harder half of the problem. The planner comparison immediately above assumed you know what state you are in. In the corridor, you do not. You know a distribution over states, which we have been calling a belief, and for which you built machinery back in Bayesian Filtering and Belief States. Planning with a belief as your starting point changes the problem in a way that is not merely quantitative. Actions that change what you can observe may become valuable even when they make little immediate physical progress. In this chapter you will see how to search over beliefs, how to recognize information-gathering behavior when it emerges, and how to make the search cheap enough to run inside a control loop.
That phrase "not merely quantitative" needs unpacking before we start. If uncertainty only made our estimates noisier, we could handle it with the same planning machinery and a little more caution. But uncertainty adds structure to the problem. It gives information a decision value that is absent when the relevant state is already known. An uncertain agent may have to trade task progress against observations that improve later choices, and a planner that cannot represent that tradeoff can miss good policies rather than merely attach noisier values to them. This is the sense in which the second half of the chapter differs from the first, even though the two share an algorithm.
The chapter proceeds as follows. We start with tree search and Monte Carlo Tree Search (MCTS), the workhorse algorithm that turns a simulator into a decision rule. We then confront partial observability and see why the MDP machinery breaks, which leads to the belief MDP and its difficult continuous state space. Next we build belief trees, the structures that let a planner reason about observations, and we work through the classic tiger problem to see information gathering emerge from expected value alone. We then put all of it together in a hidden-state maze where an agent has to infer its location while choosing movements. Finally, we replace hand-crafted heuristics with learned guidance and measure how a small neural network changes finite-budget MCTS in this maze. Throughout, we will keep model error, sampling error, and search confidence separate, because conflating them makes finite-budget results easy to overstate.
Tree Search and Monte Carlo Tree Search
Before we can talk about searching over beliefs, we need the mechanics of searching over states. This section builds MCTS from the ground up: what problem it solves, why sampling is a reasonable answer, the four phases of the algorithm, the bandit theory underneath it, and the practical details that separate a working implementation from a minimal one. Even if you never implement MCTS yourself, the concepts here recur throughout the rest of the book: the difference between tree and default policies, the role of exploration bonuses, and the meaning of a backpropagated return. The belief-space algorithm later reuses MCTS selection, simulation, and backup, and adds history-indexed observation branching plus latent-state sampling from the current belief.
The Search Problem
Recall from Markov and Partially Observable Decision Processes that a Markov decision process is a tuple , where is the state space, the action space, the transition kernel, the reward, and the discount factor. For the finite discrete case used below, the optimal value function satisfies the Bellman optimality equation:
where:
- : the maximum expected discounted return obtainable from state
- : the expected immediate reward for taking action in state
- : the probability of successor state under the transition model
- : the discount factor
If you can evaluate the right-hand side exactly, you can solve for by dynamic programming, as we did for the grid world in Classical Planning and Optimal Control. An exact tabular solution requires enumerating and iterating until convergence, and both scale badly. For factored state variables, the number of joint assignments grows exponentially; a few dozen binary features already yield billions of states, while a continuous space cannot be tabulated at all. But there is a second way to use the Bellman equation: not to solve for the whole function , but to answer a single question about a single state. Given a state , which action maximizes the right-hand side?
That reframing is the key move. You do not need to know everywhere. You need to know it at the states that arise from your current situation, and ideally only at those. Everything MCTS does follows from taking that observation seriously. The value function is a book with pages for every state in the world, most of which you will never read; MCTS is a procedure for reading only the pages you need. It is guided by the assumption that you do not need many of them.
The naive way to exploit it is a depth-limited expectimax tree. From the root state , expand every action, then every successor with nonzero probability, then every action from there, and so on to depth . If each state has available actions and each state-action pair has at most possible successors, the tree can have leaves. In a deterministic 6-by-6 grid, and four actions already produce length-20 action sequences before transpositions or pruning. Even this tiny domain therefore yields roughly a trillion candidates, each of which requires model transitions and value bookkeeping rather than a single machine instruction. The point is not merely that we need a faster computer; uniform enumeration spends its effort in the wrong shape for this problem.
MCTS addresses this by refusing to build the tree uniformly. Instead of expanding every branch to depth , it runs a fixed number of simulations, each of which walks from the root down to a leaf along a policy that balances exploitation of branches with strong sampled returns against exploration of under-sampled ones, evaluates the leaf cheaply, and then updates statistics along the visited path. The represented tree is therefore usually asymmetric. Its exact shape reflects the selection rule, the rollout or leaf evaluator, the model, and the finite budget; an initially misleading estimate can direct substantial work toward a poor branch before later evidence corrects it.
MCTS is an anytime algorithm once every legal root action has an initialized decision statistic: you can stop it at a budget boundary and return the current recommendation. Under its consistency conditions, increasing the simulation budget improves the estimate asymptotically, but a single finite-budget recommendation need not improve monotonically. This interface makes MCTS usable inside a receding-horizon control loop, where the real constraint is often the wall-clock budget between two control commands. In practice you rarely run MCTS to convergence; you run it until the clock runs out and then act on the current tree. The tree should therefore contain useful decisions at the operating budget, not only after far more simulations.
The Four Phases
Each MCTS simulation executes four phases in sequence.
-
Selection. Starting at the root, repeatedly choose the child that maximizes the tree policy. The tree policy is what makes MCTS work, and we will spend most of this section on it. Selection stops when you reach a node that has not been fully expanded, or a terminal node. Because each step of selection moves one level down the tree, a single simulation visits nodes, and the tree policy is consulted at each one.
-
Expansion. If the selected node is not terminal and has unexpanded actions, add one or more children. A common choice is to add all children at once and mark the node fully expanded. You can also add children lazily, one per visit; this matters when is large, and we will return to it. When child creation evaluates the model, eager expansion can require up to model queries, many for children that may never be revisited. Laziness delays that work until a child is needed.
-
Simulation (rollout). From the newly created node, simulate a trajectory using some default policy, such as uniform random actions or a cheap heuristic, until you hit a terminal state or a depth limit. Sum the discounted rewards to get a return estimate . In rollout-based MCTS, this phase evaluates what lies beyond the explicit tree; other variants use a learned or heuristic leaf evaluator instead. A random default policy often produces noisy leaf values, while an accurate goal-directed heuristic can reduce that variance.
-
Backpropagation. Walk back up the path you came down, incrementing visit counts and updating the running mean return at each visited node or edge. Every visited ancestor receives an update on that simulation; the update does not guarantee that its finite-sample estimate becomes more accurate.
The distinction between the tree policy (used during selection, inside the tree) and the default policy (used during simulation, outside the tree) is central. The tree policy can afford more computation per decision because it is applied only along the explicit-tree prefix and its job is to allocate future simulations well. The default policy is applied throughout the remaining rollout for every simulation, so its cost is multiplied across many simulated steps. The useful balance depends on depth, branching, simulator cost, and how much a better tree or default policy changes return variance and action ranking.
From UCB to UCT to PUCT
The tree policy treats action selection at each node like a multi-armed bandit problem. Each selected edge produces a sampled downstream return, and the selection rule balances exploiting actions with high observed returns against exploring actions with little evidence. A canonical rule is UCB1 (Auer, Cesa-Bianchi, and Fischer, 2002):
where:
- : the running mean return observed when action was tried from
- : the number of times node has been visited
- : the number of times action has been tried from
- : the exploration constant controlling the size of the uncertainty bonus
The expression is evaluated only after every available action has been visited at least once; implementations usually force unvisited actions to be selected before applying it. Read the score as a conversation between two terms. The first term, , is exploitation: it prefers actions that have paid off so far. The second term is exploration: it grows when is small relative to , so an action that has rarely been tried gets a large bonus. The logarithm in the numerator means the bonus grows slowly. Kocsis and Szepesvári (2006) applied upper-confidence selection recursively in a search tree and called the result UCT. They proved consistency for the finite-horizon and discounted MDP settings analyzed in their paper; the result depends on bounded rewards, a correct generative model, and sufficient exploration.
The bonus has the shape of a concentration bound. In the stationary bandit setting used to derive UCB1, uncertainty shrinks roughly as , while the term makes an under-sampled action eligible again as the parent is revisited. The coefficient absorbs the reward range and the desired confidence level. Recursive tree search is more delicate than an independent stationary bandit at every node because the return distribution changes as policies deeper in the tree change. UCT's consistency analysis handles that coupling under its stated assumptions; the single-node UCB1 regret guarantee should not be copied to every node without those conditions.
UCT has one important weakness for our purposes. The exploration bonus has no place to insert side information about which actions are likely to be good. If a learned policy assigns most of its probability to one action, plain UCT does not use that ranking: it normally gives every legal action an initial visit and then allocates later visits from sampled returns and counts alone. With hundreds of legal moves, those mandatory first visits can consume much of a small simulation budget even when a useful prior is available.
PUCT fixes this by multiplying the exploration term by a prior :
where:
- : the action prior, normally produced by a policy network, indicating how promising action looks before any search statistics are collected
- : PUCT's exploration coefficient, playing the same qualitative role as the UCB coefficient (though the two formulas have different scales, so their numerical values are not interchangeable)
The denominator makes the prior-weighted bonus decay relative to repeated visits to the same action. AlphaGo and AlphaZero use closely related prior-guided tree policies, with implementation-specific coefficients and root exploration. We will return to that design in the final section and in MuZero and Value-Equivalent Models.
The PUCT score combines three signals. The prior says how promising the action looks before search at this node. The running mean summarizes sampled returns, and records how often the edge has been visited. High-prior actions receive a larger early exploration bonus; repeated visits reduce that bonus relative to alternatives. A positive prior and continued exploration can let later return evidence override an imperfect ranking. A zero prior is different: in the displayed formula it gives no exploration bonus, so implementations commonly add root noise, probability floors, or forced initial visits. PUCT is a knowledge-guided selection rule, not a general guarantee of using fewer simulations than UCT.
The constant controls how strongly search favors under-explored branches. The textbook UCB1 coefficient is when rewards are normalized to the range assumed by its bound, but practical UCT and PUCT implementations tune the coefficient to their reward and value scales. AlphaZero describes a fixed ; later systems such as MuZero use a visit-dependent coefficient. These choices should not be transferred between problems without checking the scale of . A useful sanity check: if you rescale your rewards by a factor of 10 and do not rescale , you have effectively shrunk the exploration bonus by the same factor, and the search will behave differently.
Backpropagation and the Value Estimate
When a simulation returns a discounted return from the leaf, that value is the return from the leaf. But the node statistics you need to update are indexed by the path from the root. If the path is and is the reward received when entering node , then the return from node is defined recursively:
where:
- : the return backed up to node , obtained by working backward from the leaf
- : the reward on the transition from to
- : the discount factor
- : the leaf evaluation or remaining rollout return at node
Working backward along the path and adding each corresponding to node gives the correctly indexed discounted sample return. Backing up the root return unchanged to every node instead shifts the reward timing and biases deeper-node estimates. This matters because selection compares deeper-node values against each other, and a systematic shift in those values biases the search. A buggy implementation can still populate a tree and sometimes reach the goal, so the defect may surface as inefficient allocation or different action choices rather than a crash.
Once you have them, the node statistics are simple running averages:
where:
- : the number of simulations in which action was taken from node
- : the discounted return from node recorded on simulation
- the sum runs over simulations whose selected path passed through the edge
This estimator is a sample mean of returns generated by the search procedure; it is not automatically an unbiased estimate of . The tree policy and leaf evaluation change as the tree grows, so the samples are neither identically distributed nor drawn from the final policy. Uneven action sampling alone does not bias the conditional mean for an edge, but adaptive downstream policies, finite horizons, and approximate leaf values can. Treat a finite-budget MCTS as a search statistic tied to a particular algorithm and budget, not as a calibrated critic unless calibration is checked separately.
Choosing a Final Action
When the budget runs out, you need to pick an action. Two options:
- Most-visited child. Return . This convention reports which action received the largest allocation under the configured tree policy and budget.
- Highest-value child. Return . This convention reports the largest sampled mean and can be sensitive to actions supported by very few visits.
Many implementations choose the root action by visit count while using value estimates inside the tree. Both statistics reflect returns propagated through a subtree, but they answer different questions. is the observed mean for one edge; records how often the selection rule returned to that edge after comparing it with alternatives. A high value supported by two visits is fragile, while a large visit count can still be wrong when the prior, exploration rule, or model is biased. Visit count is an allocation statistic, not a calibrated confidence probability.
The visit distribution at the root can itself serve as a policy or a policy-training target. AlphaZero uses as a search-policy target, where is a temperature. If a search allocates 80% of its simulations to one action, that is a strong preference under that search configuration and budget. We will exploit this in the Policies Learned in Imagination chapter. The temperature controls how sharp the distribution is: at you take the raw visit proportions, at you get a one-hot distribution when the most-visited action is unique (ties require an explicit rule), and larger flattens the distribution. A training scheme may use a higher temperature while collecting exploratory data than at deployment, but the schedule is a design choice rather than a property of MCTS itself.
Progressive Widening
The scheme above assumes that expanding a node means adding all children. That can be manageable when is four and each child is cheap to instantiate. It is impossible to enumerate when is a continuous set, such as a bounded subset of , and costly when the discrete action set contains hundreds of moves. Progressive widening (Coulom, 2007; later refined by Auger, Couëtoux, and Teytaud, 2013) limits the number of instantiated children after visits to
where:
- : the number of children the node is allowed to have at visit count
- : the widening constant that sets the overall rate of growth
- : the widening exponent controlling how quickly the child budget broadens
The constants are problem-dependent; is a common starting point, not a universal default. Early visits instantiate few children and go deep; later visits broaden as the budget grows. POMCPOW (Sunberg and Kochenderfer, 2018) applies progressive widening to sampled actions and observations so a finite search tree can be used in continuous spaces. Widening does not by itself ensure that an optimal continuous action is ever sampled. That conclusion additionally requires an action proposal with suitable support and regularity assumptions. The practical tradeoff is depth against coverage: a slow schedule gives each instantiated child more visits, while a fast schedule covers more candidates with fewer samples per child.
Let us now build the MCTS algorithm. The first cell binds shared plot-style helpers alongside computation imports. Figure construction remains in the later visualization cells, while arrays and statistics are prepared beforehand.
# Shared simulation setup and plot-style bindings.
# Figure construction stays in the plot cells below.
import math
from collections import deque
import numpy as np
# Plot helpers are defined once here so later plot cells can use them locally.
try:
from book_plot_style import label_bars, polish_axes, use_book_style
except ImportError: # fallback for environments without book_plot_style
def use_book_style():
pass
def polish_axes(ax):
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
def label_bars(ax, bars):
for b in bars:
ax.annotate(
f"{int(b.get_height())}",
(b.get_x() + b.get_width() / 2, b.get_height()),
ha="center",
va="bottom",
fontsize=7,
)
# Rows top to bottom, columns left to right. True marks a wall.
GRID = np.array(
[
[0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 1, 0],
[1, 1, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 1, 0],
],
dtype=bool,
)
H, W = GRID.shape
START = (0, 0)
GOAL = (5, 5)
MOVES = ((-1, 0), (1, 0), (0, -1), (0, 1)) # up, down, left, right
N_ACTIONS = len(MOVES)
ACTION_NAMES = ("up", "down", "left", "right")
STEP_COST = -0.02
GOAL_REWARD = 1.0
GAMMA = 0.97
def step(state, action):
"""Deterministic grid transition. Returns (next_state, reward, done)."""
if state == GOAL:
return state, 0.0, True
r, c = state
dr, dc = MOVES[action]
nr, nc = r + dr, c + dc
if not (0 <= nr < H and 0 <= nc < W) or GRID[nr, nc]:
nr, nc = r, c # bumping a wall leaves you where you were
nxt = (nr, nc)
if nxt == GOAL:
return nxt, GOAL_REWARD, True
return nxt, STEP_COST, FalseThe maze is deliberately shaped so that the goal is not reachable by greedy Manhattan descent: the bottom-left arm looks closer to the goal than the top corridor, but it dead-ends. A policy that follows Manhattan distance alone enters the trap, while a sufficiently deep and well-sampled search can represent the necessary backtracking. Let us confirm the geometry before comparing finite-budget planners.
. . . . . . . # # # # . . . . . # . # # # . # . . . . . # . . # # # # G
The interior walls create a top corridor, a right-hand descent, and a bottom-left dead end. Every route out of that dead end must backtrack before reaching the goal. In the fully observed case, a planner can index the exact distance-to-goal map by the current cell. In the partially observed case, the map is still known, but the current cell is not; the controller must evaluate actions across its belief rather than select one state's lookup entry.
Next we compute two reference quantities. The breadth-first distance map gives us the true shortest-path length from every free cell to the goal, which we will use both as a rollout heuristic and as a diagnostic. Value iteration converges to a high-accuracy numerical reference for , which we will use to measure how well MCTS is doing.
FREE = [(r, c) for r in range(H) for c in range(W) if not GRID[r, c]]
N_CELLS = len(FREE)
S_IDX = {s: i for i, s in enumerate(FREE)}
def signature(state):
"""4-bit local wall pattern: up, down, left, right."""
r, c = state
bits = 0
for a, (dr, dc) in enumerate(MOVES):
nr, nc = r + dr, c + dc
blocked = not (0 <= nr < H and 0 <= nc < W) or GRID[nr, nc]
if blocked:
bits |= 8 >> a
return bits
SIG = np.array([signature(s) for s in FREE])
# Transition tensor: T[a][i, j] = P(next = FREE[j] | state = FREE[i], action = a)
T = np.zeros((N_ACTIONS, N_CELLS, N_CELLS))
for i, s in enumerate(FREE):
for a in range(N_ACTIONS):
s2, _, _ = step(s, a)
T[a, i, S_IDX[s2]] = 1.0
# Deterministic observation matrix: O[o, i] = 1 iff cell i emits signature o
O = np.zeros((16, N_CELLS))
for i in range(N_CELLS):
O[SIG[i], i] = 1.0
def bfs_distances(goal=GOAL):
dist = {goal: 0}
queue = deque([goal])
while queue:
s = queue.popleft()
r, c = s
for dr, dc in MOVES:
nr, nc = r + dr, c + dc
nxt = (nr, nc)
if (
0 <= nr < H
and 0 <= nc < W
and not GRID[nr, nc]
and nxt not in dist
):
dist[nxt] = dist[s] + 1
queue.append(nxt)
return dist
DIST = bfs_distances()
def value_iteration(gamma=GAMMA, tol=1e-12):
V = {s: 0.0 for s in FREE}
for _ in range(20000):
delta = 0.0
for s in FREE:
if s == GOAL:
continue
best = -np.inf
for a in range(N_ACTIONS):
s2, r, done = step(s, a)
q = r + (0.0 if done else gamma * V[s2])
best = max(best, q)
delta = max(delta, abs(best - V[s]))
V[s] = best
if delta < tol:
break
return V
V_STAR = value_iteration()
print(f"Free cells: {N_CELLS}")
print(f"Shortest path from {START} to {GOAL}: {DIST[START]} steps")
print(f"Optimal value at the start: {V_STAR[START]:.4f}")
print(f"Value of the dead-end cell (5, 0): {V_STAR[(5, 0)]:.4f}")The asymmetry the value function encodes is easier to read as a picture than as a pair of scalars. The cell below stores the converged value-iteration result for every free cell and the exact shortest-path distance to the goal, so the figure cell can project both without doing any planning of its own.
# Presentation inputs only: converged values and exact distances from V_STAR / DIST.
VALUE_GRID = np.full((H, W), np.nan)
DIST_GRID = np.full((H, W), np.nan)
for s in FREE:
VALUE_GRID[s] = V_STAR[s]
DIST_GRID[s] = DIST[s]
# Fully observed greedy policy from V_STAR, used as a sanity reference only.
def greedy_action_from_value(state):
qs = []
for a in range(N_ACTIONS):
s2, r, done = step(state, a)
qs.append(r + (0.0 if done else GAMMA * V_STAR[s2]))
return int(np.argmax(qs))
GREEDY_ACTION = {}
for s in FREE:
if s == GOAL:
continue
GREEDY_ACTION[s] = greedy_action_from_value(s)
print(f"max V* over free cells: {np.nanmax(VALUE_GRID):.4f}")
print(f"min V* over free cells: {np.nanmin(VALUE_GRID):.4f}")
Both quantities agree with intuition: ten steps is the true shortest route, and the remote dead-end cell is worth only against at the start. An agent that wanders into the bottom-left arm pays for it. The gap is large enough to be decision-relevant, which makes this maze a useful example: the planner must discover the difference from finite rollouts, and under partial observability it must also infer which region it occupies.
We now implement MCTS. The four phases map directly onto the four blocks of the simulation loop, in the order we described them.
class MCTSNode:
__slots__ = (
"state",
"parent",
"reward",
"prior",
"children",
"N",
"W",
"Q",
)
def __init__(self, state, parent=None, reward=0.0, prior=1.0):
self.state = state
self.parent = parent
self.reward = reward # reward received when entering this node
self.prior = prior # P(s, a) in the PUCT formula
self.children = {} # action -> MCTSNode
self.N = 0
self.W = 0.0 # sum of returns
self.Q = 0.0 # W / N
def tree_score(child, c, rng):
"""PUCT score with a forced first visit per action."""
if child.N == 0:
return 1e9 + 100.0 * child.prior + rng.random()
bonus = c * child.prior * math.sqrt(child.parent.N) / (1.0 + child.N)
return child.Q + bonus
def mcts(
root_state,
n_sims,
priors=None,
rollout=None,
gamma=GAMMA,
c=1.5,
max_depth=30,
seed=0,
):
"""Run n_sims simulations from root_state and return the search tree root."""
rng = np.random.default_rng(seed)
root = MCTSNode(root_state)
for _ in range(n_sims):
node, path, depth = root, [root], 0
# --- 1. Selection -------------------------------------------------
while node.children and node.state != GOAL and depth < max_depth:
a = max(
node.children,
key=lambda k: tree_score(node.children[k], c, rng),
)
node = node.children[a]
path.append(node)
depth += 1
# --- 2. Expansion -------------------------------------------------
if node.state != GOAL and depth < max_depth:
for a in range(N_ACTIONS):
s2, r, _ = step(node.state, a)
p = (
1.0 / N_ACTIONS
if priors is None
else float(priors(node.state, a))
)
node.children[a] = MCTSNode(s2, parent=node, reward=r, prior=p)
# Continue through one newly expanded edge before rolling out.
# This gives every child an action return on its first visit.
a = max(
node.children,
key=lambda k: tree_score(node.children[k], c, rng),
)
node = node.children[a]
path.append(node)
depth += 1
# --- 3. Simulation ------------------------------------------------
s, total, disc = node.state, 0.0, 1.0
for _ in range(max_depth - depth):
if s == GOAL:
break
a = (
int(rng.integers(N_ACTIONS))
if rollout is None
else int(rollout(s, rng))
)
s, r, done = step(s, a)
total += disc * r
disc *= gamma
if done:
break
# --- 4. Backpropagation -------------------------------------------
g = total
for n in reversed(path[1:]):
g = n.reward + gamma * g
n.N += 1
n.W += g
n.Q = n.W / n.N
root.N += 1
root.W += g
root.Q = root.W / root.N
return root
def guided_action(state, rng, epsilon=0.3):
"""Rollout policy: mostly follow the BFS shortest path, sometimes wander."""
if rng.random() < epsilon:
return int(rng.integers(N_ACTIONS))
best_a, best_d = 0, None
for a in range(N_ACTIONS):
nxt, _, _ = step(state, a)
d = DIST.get(nxt, 10**6) + (0.5 if nxt == state else 0.0)
if best_d is None or d < best_d:
best_a, best_d = a, d
return best_a
def root_choice(root):
return max(root.children, key=lambda k: root.children[k].N)The 1e9 branch inside tree_score forces every action to be visited once before ordinary PUCT scoring takes over. This safeguard is especially important for zero or numerically tiny priors, whose exploration bonuses may otherwise be absent or negligible. A positive-prior action is not permanently locked out by one unlucky rollout under the displayed bonus, because its exploration term grows as the parent is revisited while its own count stays fixed. Here the prior orders unequal-prior unvisited actions, and the random term breaks ties between equal priors across seeds.
Let us run 400 simulations from the start and see what the search finds.
root = mcts(START, n_sims=400, seed=0)
chosen = root_choice(root)
best_child = root.children[chosen]
summary = {
ACTION_NAMES[a]: (int(root.children[a].N), round(root.children[a].Q, 4))
for a in range(N_ACTIONS)
}Chosen action: right
Estimated value: -0.3891 (true optimum 0.6004)
up: visits= 95 Q=-0.3993
down: visits= 95 Q=-0.3993
left: visits= 100 Q=-0.3951
right: visits= 110 Q=-0.3891With uniform random rollouts and uniform priors, 400 simulations give right, the first step of the shortest path, only a small plurality of visits. The two wall-bumping actions (up and left) still receive almost one quarter of the budget each, and all four finite-horizon value estimates remain negative. This is useful evidence rather than a successful convergence result: a weak rollout policy can leave the search with little signal even when the final action happens to be correct. Visit counts show how the budget was allocated, but only strong concentration would show that search had decisively separated the actions.
Let us look at what that means in the maze. We run a closed-loop episode where MCTS re-plans at every step, then draw the resulting trajectory.
def mcts_episode(
start, n_sims=300, max_steps=30, rollout=None, priors=None, seed=0
):
state, path, total = start, [start], 0.0
for t in range(max_steps):
if state == GOAL:
break
tree = mcts(
state, n_sims=n_sims, rollout=rollout, priors=priors, seed=seed + t
)
a = root_choice(tree)
state, r, done = step(state, a)
total += r
path.append(state)
if done:
break
return path, total
PATH_UNIFORM, RET_UNIFORM = mcts_episode(
START, n_sims=300, rollout=None, seed=1
)
PATH_GUIDED, RET_GUIDED = mcts_episode(
START, n_sims=300, rollout=guided_action, seed=1
)
# Sanity check: both runs should reach the goal.
assert PATH_UNIFORM[-1] == GOAL, (
"uniform-rollout planner failed to reach the goal"
)
assert PATH_GUIDED[-1] == GOAL, (
"guided-rollout planner failed to reach the goal"
)Uniform rollouts: 13 steps, return 0.760 Guided rollouts: 10 steps, return 0.820
Both planners solve the maze, and the guided-rollout run gets there in three fewer steps. That result is consistent with the lower value-estimate error produced by the goal-directed rollout policy in the experiment below. It illustrates the mechanism in this deterministic seeded run, but does not establish a general speedup.


The left panel shows that repeated closed-loop search reaches the goal in this seeded run: the guided rollout follows the ten-step route, while the uniform rollout takes thirteen steps. The right panel explains why this one trajectory should not be mistaken for a well-resolved root estimate. The 400-simulation search spreads visits nearly evenly, including across the two wall-bumping actions. Closed-loop replanning recovers a useful action sequence here even though each individual uniform-rollout search remains uncertain. Read visits and values together: the visit count records the selection rule's allocation, while the value is the sampled mean return on an edge. Neither is a calibrated confidence measure.
How Good Is the Guidance?
We can compare finite-budget root estimates under uniform and guided rollouts. The experiment below measures absolute error relative to over eight seeds. It tests these two implementations on this maze; it does not establish a general sample-complexity result.
BUDGETS = [10, 25, 50, 100, 200, 400, 800]
SEEDS = list(range(8))
GUIDANCE_ERRORS = {"No guidance": [], "Guided rollouts": []}
GUIDANCE_VISIT_SHARE = {"No guidance": [], "Guided rollouts": []}
OPTIMAL_FIRST_ACTION = guided_action(
START, np.random.default_rng(0), epsilon=0.0
)
for label, policy in [
("No guidance", None),
("Guided rollouts", guided_action),
]:
for budget in BUDGETS:
errs, shares = [], []
for s in SEEDS:
tree = mcts(START, n_sims=budget, rollout=policy, seed=s)
a = root_choice(tree)
errs.append(abs(tree.children[a].Q - V_STAR[START]))
shares.append(tree.children[OPTIMAL_FIRST_ACTION].N / budget)
GUIDANCE_ERRORS[label].append(float(np.mean(errs)))
GUIDANCE_VISIT_SHARE[label].append(float(np.mean(shares)))Reference V*(start): 0.6004 No guidance value error: 0.981 0.982 0.982 0.985 0.986 0.988 0.990 Guided rollouts value error: 0.174 0.203 0.220 0.239 0.251 0.265 0.274
The finite-budget result is more cautionary than a textbook convergence curve. At every tested budget, guided rollouts produce much smaller error than uniform rollouts, but neither series approaches zero by 800 simulations. The uniform estimate stays about one unit from , while the guided error rises from about to . One plausible explanation is that more of the fixed 30-step horizon becomes controlled by a still-shallow tree rather than the stronger default policy, but this experiment does not isolate the cause. Asymptotic UCT results require their stated assumptions about horizon, exploration, and sampling; this small implementation and budget are an experiment about finite-compute behavior, not evidence of convergence. Guidance changes where finite compute is useful, while approximation choices can also change the observed value estimate.


The experiment demonstrates a narrower practical point: guidance can materially change finite-budget search. A better rollout policy, leaf evaluator, or action prior can reduce the simulations needed for a chosen decision-quality target, but only when its extra evaluation cost and errors are included. Unguided search remains useful in some domains; guidance changes its sample efficiency rather than defining whether search has value.
One caveat before we move on. Both curves in the first panel are relative to , the value of the fully observed MDP. That is the right benchmark here, but it stops being the right benchmark the moment we take away the agent's knowledge of its own state, which is exactly what we do next. Under partial observability, "estimated minus optimal" would compare a belief-conditioned value estimate with a fully observed state value, so the comparison would no longer mean the same thing. Keep this in mind as you read the next section; the numbers are still informative, but they measure a different quantity.
Key Parameters
The key MCTS parameters in this section are:
- n_sims: Number of simulations per planning call. Controls online cost and often improves decision quality, but finite-budget estimates need not improve monotonically.
- c: Exploration coefficient in the tree policy (UCB1 and PUCT). Larger values encourage exploring under-visited branches.
- max_depth: Maximum simulated horizon. Bounds the cost of each simulation and prevents infinite loops.
- prior: PUCT action prior. Concentrates search when informative, but can suppress exploration if overly confident.
- rollout policy: Default policy used inside simulations. A cheap, accurate heuristic can reduce the simulation budget for a chosen quality target, while a biased heuristic can steer estimates in the wrong direction.
Planning Under Partial Observability
Everything in the previous section assumed the planner knows the state . In a maze rendered as a grid of characters, that assumption is invisible because it is satisfied by construction. Many real systems violate it: a robot may have a drifting odometer, a dialogue agent may not know what the user knows, and a recommender may not know what the user has already seen. This section explains why that violation is not a technicality and what replaces the MDP.
The physical state does not become a distribution; it remains the latent state of the environment. What changes is the planner's information state. The planner replaces direct access to with a belief over possible states, evaluates a belief value , and combines prediction with Bayesian conditioning. Under the assumed POMDP model, the belief is a controlled Markov information state, so Bellman reasoning can be applied in belief space.
The POMDP and Why MDP Search Breaks
Recall from Markov and Partially Observable Decision Processes that a partially observable MDP adds an observation space and an observation model to the MDP tuple: . After taking action in state , the environment moves to and emits . Critically, the agent sees but not .
The immediate consequence is that the planner cannot index its decision by one known physical state. Suppose the agent assigns probability to both and , two cells with the same local wall signature. Moving right is on the goal route from but moves toward the dead-end branch from . Planning from an arbitrarily chosen candidate discards both the belief weights and the way future observations can separate the candidates. Its error rate is not generically one half; it depends on the belief, on the rewards, and on the candidate-state action values.
A second consequence is subtler and, for planning purposes, more important. Once actions can change what you know, an action may be valuable partly because of its observations. Turning around in a corridor may earn no immediate reward, and may even cost time, but it may tell you which way is north. A fully observed MDP planner has no information term with which to value that effect; it would choose the same physical motion only for its transition and reward consequences. In a POMDP, later decisions can make information valuable. This is the structural shift we flagged in the introduction: uncertainty can make policies that pay to observe outperform policies that only chase immediate task progress.
The Belief MDP
The standard resolution is to change what the planner treats as a state. Instead of planning over , plan over the space of probability distributions over . This space is called the belief space and is denoted ; an element assigns a probability to each state. You built the machinery for computing from observation histories in Bayesian Filtering and Belief States. Here we use it as the substrate for planning.
The mathematical shape of contrasts sharply with . When is finite with , is a set of discrete points, but is the -dimensional simplex, a continuous space whose dimension is one less than the number of states. The three-state case gives a triangle; the four-state case gives a tetrahedron; the twenty-two-state case, which is our maze, is a twenty-one-dimensional polytope that we can only visualize through projections. Even a small discrete state space therefore induces a continuous belief space, one major source of POMDP planning complexity alongside action-observation branching and horizon.
The key fact is that a correctly updated belief is sufficient for predicting future rewards and observations under future actions. The belief need not preserve the literal history; it preserves the history's decision-relevant probabilistic information under the assumed model. This means the POMDP induces an MDP over , with:
- Belief states: .
- Actions: the same .
- Belief reward: , the expected immediate reward.
- Belief transition: , defined below.
The belief transition is the composition of a prediction step and a Bayesian correction. The prediction step propagates belief through the dynamics:
Here is the current probability of state , is the transition probability after action , and is the predicted probability of successor before seeing the next observation.
The probability of observing under this predicted belief is
Here is the likelihood of observation after arriving in , and the sum marginalizes the unobserved successor state.
The corrected belief is then Bayes' rule applied cellwise:
The denominator must be positive; a zero-probability observation is outside the conditioning event. The result is the posterior probability of successor state . Before the observation is seen, the next belief is a random variable because different possible observations induce different posteriors. This remains true in our maze even though both the physical dynamics and sensor are deterministic: uncertainty about the current latent cell induces uncertainty about which deterministic successor and signature will occur. Once the action and observation are fixed, the Bayes update itself is deterministic.
Three properties of the belief MDP are worth keeping in mind.
First, an optimal policy can be expressed as a function of the current belief under the standard POMDP assumptions. For a finite horizon it may also depend on the remaining time; for an infinite-horizon discounted problem, a stationary belief policy can be optimal under the usual conditions. The belief is therefore a sufficient information state for control. We discussed sufficient state in Sufficient State and State Abstraction. A controller need not retain the full history when it can update the exact belief and any required time index.
Second, for a finite-state, finite-action, finite-observation POMDP with a finite horizon and expected-reward maximization, the optimal belief value function is piecewise linear and convex in . This means for a finite set of alpha vectors , where is the inner product of the -th vector with the belief. Each alpha vector represents a conditional plan, and the maximizing vector defines a region of belief space. This structural result (Sondik, 1971; Smallwood and Sondik, 1973) underlies exact finite-horizon POMDP methods. The convexity is what makes the structure exploitable: the value function is the upper envelope of a family of linear functions, and the choices of optimal action correspond to the faces of that envelope. A piecewise-linear convex value function is a much more constrained object than a general one, and in principle it can be computed exactly.
Third, the exact representation grows quickly in the worst case. Before pruning, the standard finite-horizon backup can generate a number of candidate alpha vectors that is doubly exponential in horizon when there is more than one observation; the number that survives pruning is problem-dependent. The belief space is also a simplex of dimension rather than a finite collection of states. Pruning helps, but exact methods become impractical as the state, action, observation, or horizon sizes increase. The two-state tiger problem is useful because its belief space is one-dimensional and can be visualized. State count alone does not determine the number of surviving alpha vectors; the structure of transitions, observations, rewards, and horizon also matters.
The Approximations
Large POMDPs usually require approximations, while exact belief-space methods remain useful for small finite problems. It helps to organize approximations by what they discard and to ask which discarded structure is least costly for the problem at hand.
Throw away uncertainty. The crudest family. QMDP computes the MDP Q-function and then evaluates actions by their expectation under the belief:
Here is the optimal fully observed MDP action value and weights each possible state. This is fast but structurally incapable of valuing future information, because it assumes that uncertainty disappears after the current action. For reward maximization, granting the controller that extra future information makes the QMDP value an optimistic upper bound on the corresponding POMDP value, not a lower bound. The resulting policy can favor actions that work only under the assumed future certainty. The observation model does not appear in the QMDP expression, so an otherwise reward-neutral sensing action receives no credit for improving later decisions. QMDP could still select an action called peek for its modeled reward or state transition, but not for the observation it supplies.
A close cousin is most-likely-state planning: take and plan as if were known. It is cheap and reuses an MDP planner, but it discards probability mass on every other state and cannot value observations. It can be adequate when the belief is tightly concentrated and nearby states have similar action values. A multimodal belief is a warning sign rather than a proof of failure: the approximation fails when plausible modes favor materially different actions.
Throw away most beliefs. Point-based methods apply backups at a finite set of representative beliefs rather than across the full simplex. PBVI (Pineau, Gordon, and Thrun, 2003) uses explorative stochastic trajectories to select belief points. SARSOP (Kurniawati, Hsu, and Lee, 2008) focuses sampling on an approximation to the beliefs reachable under optimal policies, not specifically on the boundary of the reachable set. HSVI (Smith and Simmons, 2004) maintains upper and lower bounds and directs trials using those bounds. These methods can produce alpha-vector policy representations. Their tractability depends on more than the raw dimension: reachable-set geometry, sparsity, action and observation counts, and the required error tolerance also matter. A finite sample of reachable beliefs can greatly reduce work, but it can miss decision-relevant regions and therefore does not preserve the instance's optimum automatically.
Throw away the global offline policy. Online methods plan from the current belief with a fixed compute budget, execute one action, and plan again. They may still use a fixed finite search depth or discounted infinite-horizon objective. If the planner only needs the next action, it can concentrate on beliefs reachable from the current one. The belief tree still branches over observations, so sampling and, in continuous spaces, observation progressive widening are used to keep the represented tree finite. POMCP is one online sampling approach.
Let us build the POMDP version of the maze. We keep the deterministic dynamics and replace the position sensor with a local wall signature: the agent perceives a four-bit pattern saying which of its four neighbors are blocked. Many cells share a signature, so the sensor is ambiguous rather than noisy. Ambiguous sensors are useful here because they separate two kinds of partial observability that learners often conflate: noise (the same state produces different observations on different visits) and aliasing (different states produce the same observation). Our maze has only aliasing, and every observation is produced deterministically by its state.
def belief_update(belief, action, obs):
"""Exact Bayes filter for this model."""
predicted = belief @ T[action]
posterior = predicted * O[obs]
total = posterior.sum()
if total <= 1e-12:
raise ValueError(
"observation has zero probability under predicted belief"
)
return posterior / total
def belief_grid(belief):
"""Reshape a belief vector back onto the 2D maze for plotting."""
canvas = np.full((H, W), np.nan)
for i, s in enumerate(FREE):
canvas[s] = belief[i]
return canvas
def entropy(belief):
positive = belief[belief > 0.0]
value = float(-np.sum(positive * np.log(positive)))
return max(0.0, value) # avoid displaying negative zero at a point massNow let us look at how much information the sensor carries. Grouping cells by signature shows how badly aliased the world is.
signature 3 [U=0 D=0 L=1 R=1] -> 6 cells: [(1, 0), (1, 5), (2, 5), (3, 3), (3, 5), (4, 5)] signature 5 [U=0 D=1 L=0 R=1] -> 1 cells: [(4, 3)] signature 6 [U=0 D=1 L=1 R=0] -> 1 cells: [(2, 0)] signature 7 [U=0 D=1 L=1 R=1] -> 2 cells: [(5, 0), (5, 5)] signature 9 [U=1 D=0 L=0 R=1] -> 2 cells: [(0, 5), (2, 3)] signature 10 [U=1 D=0 L=1 R=0] -> 2 cells: [(0, 0), (4, 0)] signature 12 [U=1 D=1 L=0 R=0] -> 8 cells: [(0, 1), (0, 2), (0, 3), (0, 4), (2, 1), (2, 2), (4, 1), (4, 2)]
There are seven distinct signatures for twenty-two free cells, so a signature does not identify the position. Signature 12 is shared by eight cells: four along the top corridor, two in the middle row, and two in the bottom-left arm. Under a uniform prior over free cells, conditioning on an initial observation of 12 gives a uniform belief over those eight cells with entropy nats. That is the largest initial alias class in this maze.
There is no sensor noise to average away; the ambiguity comes from perceptual aliasing. Repeating the same observation without changing viewpoint cannot separate the eight signature-12 cells, but filtering an action-observation sequence can. Noisy sensors and aliased sensors can both require history, and a most-likely-state controller is not guaranteed to become optimal in either case. The important distinction is that repeated independent measurements may reduce noise, whereas resolving aliasing here requires actions that lead candidate cells to different later signatures.
Let us watch a belief evolve under a fixed action sequence, to make the mechanics concrete before we search over them.
initial support: 8 cells, entropy 2.079 after another 'right' and observing 12: 5 cells, entropy 1.609 after another 'right' and observing 12: 2 cells, entropy 0.693 after another 'right' and observing 12: 1 cells, entropy 0.000
Starting from true cell , each right action produces the displayed signature and prunes the posterior support from eight cells to five, then two, then one. This is filtering under a fixed, physically consistent action-observation sequence. It shows how motion can disambiguate aliased positions; deciding whether that information is worth the motion is the planner's separate job.
Belief Trees and Information Gathering
We now know that the right information state for planning is the belief. A belief tree can be indexed by action-observation histories, with the posterior at each node stored explicitly or reconstructed from the root belief and model. POMCP uses the history-indexed form and represents those node beliefs with particles rather than dense vectors.
A history and root belief determine the corresponding posterior under a known model, so an algorithm need not store a dense belief vector at every node. POMCP goes further: it indexes nodes by histories and represents their beliefs through the latent-state particles delivered by simulations. The history alone is not a numerical belief; the root belief and the model, together with the filtering or particle procedure, supply the probabilities.
The Belief Tree
A belief tree alternates action edges and observation edges. A node is a history
where is the action taken at step , is the resulting observation, and is the history length in action-observation pairs. The belief at that node is , the posterior obtained by starting from root belief and applying the Bayes filter once per pair. From , an action edge labeled leads to a chance node; from there, an observation edge labeled leads to the new history .
The alternation of action edges and observation edges is the structural feature that separates a belief tree from a fully observed state tree. At a belief decision node there are up to action choices, and each action can lead to up to observation histories. Thus a complete action-observation layer can grow by at most before reachability and probability-zero branches are removed. A fully observed stochastic tree instead branches on successor states. Neither representation is uniformly smaller; the effective branching factor depends on the model and current support.
Two structural differences from the MDP tree change how the algorithm is implemented.
The first is that branching is on observations, not directly on latent next states. A fully observed state tree branches wherever the dynamics are stochastic. A belief tree branches when one action can produce different observations across states in the current belief. In our deterministic maze there are seven signatures globally. From the initial eight-cell signature-12 belief, left or right can produce three distinct next signatures, while up and down produce one. The corresponding fully observed transition from a known cell has one successor. Partial observability can therefore introduce observation branching even when physical dynamics and sensing are deterministic.
The second is that the same physical state can appear at many history nodes because the agent's information can differ. Before reachability pruning, a horizon of action-observation pairs permits at most histories. This is a worst-case count: zero-probability observations, merged beliefs, and sparse dynamics can reduce it sharply. Partial observability adds a curse of history to the continuous belief-state representation, which is why practical solvers sample, prune, merge, or restrict the histories they represent.
Information Gathering and the Value of Information
With the belief tree defined, information-gathering behavior becomes understandable. Consider a node and two actions and with identical expected immediate reward. The action values in the belief tree are
where:
- : the expected immediate reward at belief
- : the probability of observing after taking from belief
- : the value of the successor history obtained by taking and observing
An action that produces informative observations can create successor beliefs on which the agent chooses better continuation actions. Informativeness alone does not guarantee higher task value: the sensing cost, delay, state transition, and decision relevance of the observation all matter. When the expected improvement in later decisions exceeds those costs, the informative action wins without requiring a separate exploration bonus.
The continuation value depends on the posterior used for later decisions. An observation is valuable when it separates hypotheses that call for different continuation actions. Posterior concentration by itself is not enough: learning a task-irrelevant detail can reduce entropy without changing the maximizing action or its value. In the exact belief-MDP backup, task-directed information value enters through observation-contingent continuation choices rather than through a separate generic information bonus. QMDP omits this mechanism because it assumes full observability after the current action.
For a fixed sensing action , the expected value of sample information compares choosing a continuation action after seeing its observation with committing to one continuation action beforehand:
where evaluates the downstream action after the sensing transition. Both terms use the same observation distribution. The first permits to depend on ; the second requires one before is known. Their difference is non-negative because an observation-contingent decision rule includes every constant decision rule as a special case. It is zero when some fixed continuation action is optimal for all observations with positive probability (allowing ties). The net value of sensing must additionally subtract the sensing action's reward cost and account for its state transition. This subtraction is what makes information gathering a tradeoff rather than a free win: an informative action that costs too much reward or moves you into a bad region will lose to a less informative but cheaper alternative.
Because an exact value-of-information calculation requires the downstream backup, some online planners use a cheaper proxy: the expected reduction in belief entropy, . Adding a weighted information-gain bonus to the action value,
where:
- : the Shannon entropy of belief , measuring how uncertain the agent is
- : a hyperparameter weighting the information-gain bonus against reward
- : the posterior belief after taking and observing
encourages branches expected to reduce entropy. This heuristic has the same shape as intrinsic information-gain rewards discussed in Active Perception, Dual Control, and Exploration, but it is not generally equivalent to task value: entropy can fall for distinctions that do not affect the decision. The weight is a task-dependent hyperparameter, not a quantity supplied by the exact belief-MDP backup. When using this heuristic, remember that it is a shortcut: entropy can fall dramatically on an observation that is irrelevant to the task, and the bonus will reward it, which can lead to agents that obsess over any observation that changes the belief at all.
Worked Example: The Tiger Problem
The tiger problem, presented as a benchmark by Kaelbling, Littman, and Cassandra (1998), gives a compact demonstration of information gathering. You face two doors. Behind one is a tiger; behind the other is a reward of . Opening the tiger door gives . You cannot tell the doors apart, but you can listen for a cost of ; the growl indicates the tiger's side with probability . The classic continuing formulation resets the hidden tiger after a door is opened. For a compact calculation, this chapter uses an episodic variant in which opening either door terminates the episode.
With two latent states and two observation symbols, the tiger belief space is one-dimensional, so the episodic value function can be plotted directly. The useful qualitative feature is a region of beliefs in which paying for another observation improves the later door choice. Larger POMDPs can contain analogous information-gathering regions, but their geometry and even their existence depend on the task.
Let denote the belief that the tiger is on the left, and let denote the belief that the tiger is on the right. The belief space is one-dimensional, so we can approximate the belief-MDP value on a dense grid and look at the whole curve at once. The interpolation and stopping tolerance make this a numerical solution rather than a symbolic exact one, but its symmetry and convergence can be checked directly.
TIGER_GAMMA = 0.95
LISTEN_COST = -1.0
ACC = 0.85 # P(growl on the tiger's side | tiger's side)
p_grid = np.linspace(1e-6, 1 - 1e-6, 4001)
def open_left_value(p):
return p * (-100.0) + (1.0 - p) * 10.0
def open_right_value(p):
return p * 10.0 + (1.0 - p) * (-100.0)
def listen_value(p, V):
q_left = ACC * p + (1 - ACC) * (1 - p) # P(hear "left")
q_right = 1.0 - q_left
p_after_left = ACC * p / q_left # posterior after hearing "left"
p_after_right = (1 - ACC) * p / q_right # posterior after hearing "right"
continuation = q_left * np.interp(
p_after_left, p_grid, V
) + q_right * np.interp(p_after_right, p_grid, V)
return LISTEN_COST + TIGER_GAMMA * continuation
V_tiger = np.maximum(open_left_value(p_grid), open_right_value(p_grid))
for _ in range(3000):
updated = np.maximum(V_tiger, listen_value(p_grid, V_tiger))
if np.max(np.abs(updated - V_tiger)) < 1e-10:
V_tiger = updated
break
V_tiger = updated
listen_vals = listen_value(p_grid, V_tiger)
open_l_vals = open_left_value(p_grid)
open_r_vals = open_right_value(p_grid)
stacked = np.vstack([listen_vals, open_l_vals, open_r_vals])
best_action = np.argmax(stacked, axis=0)
listen_region = p_grid[best_action == 0]
listen_lo, listen_hi = float(listen_region.min()), float(listen_region.max())Listen is optimal for beliefs between p = 0.0240 and p = 0.9760 Below the band the optimal action is open left; above it the other door. Value at p = 0.5 (maximally uncertain): 3.7702 Value at p = 0.0 (certainty): 9.9999
The answer has the expected shape. At maximal uncertainty, listening is worth much more than opening because either door has a one-half chance of the large loss. As the belief approaches certainty, the value of another observation falls and the agent opens the safe door. With symmetric door rewards and a symmetric sensor, the listening band is symmetric about up to grid discretization; swapping left and right maps to without changing the problem. This symmetry is a good sanity check on the implementation: any asymmetry in the displayed listen band is numerical, not structural.


The belief space is one-dimensional here, which lets us draw the whole episodic solution. In a larger problem, information-gathering actions can be optimal on more complicated belief regions. The middle band in this example has a precise interpretation: listening leaves the physical state unchanged but produces an observation that can change the later door choice. Repeated sensing or motion in another task should be called information gathering only after checking the same counterfactual, not merely because the behavior looks hesitant.
POMCP: Monte Carlo Tree Search in Belief Space
We now need an algorithm that can search a belief tree without enumerating it. POMCP, introduced by Silver and Veness (2010), adapts MCTS to partially observable domains using a generative model and sampled latent states. Its central idea is worth stating on its own.
Instead of representing the belief explicitly, sample a state from it.
That is the core idea. POMCP maintains a tree whose nodes are indexed by action-observation histories. At the root, each simulation begins by sampling a single state from the current belief. From there the simulation proceeds like MCTS: select an action by UCB, sample a successor state from the model, sample an observation, and descend to the child indexed by that observation rather than by the latent state. Because different simulations sample different states, they can reach the same history node through different latent trajectories, and the node's accumulated statistics integrate over those sampled possibilities.
For a fixed policy and finite-variance return, independent Monte Carlo standard error scales as . POMCP uses root-state and transition-observation samples to approximate belief-space action values, but its tree policy adapts across simulations, so this elementary rate is not a finite-budget error guarantee for the full algorithm. Histories index the tree, while the sampled latent states reaching a history form its particle approximation.
The reasons this works are worth making explicit:
- The root particles are a belief sample. Each root simulation draws . For a fixed rollout policy and finite horizon, a sample return is an unbiased Monte Carlo estimate under the generative model. Adaptive tree selection changes which policies are sampled, so finite-budget POMCP value estimates need not themselves be unbiased.
- The tree's history structure handles the observation branching automatically. You never have to enumerate observations; you sample one per simulation and let the tree grow where the samples land.
- The transition model is used as a generative model, not as an explicit matrix. You only need to be able to sample and . This makes POMCP applicable when a neural or other simulator can generate those samples even though its transition density is unavailable or inconvenient to evaluate.
The action-value update is a running mean of the returns observed when that action was taken from that node:
where:
- : the running mean return for taking action at history node
- : the discounted return obtained along the current simulated path
- : the number of simulations in which action was taken at history
This is the incremental sample-mean update used in POMCP. The exact belief-MDP backup sums observation branches with weights , whereas POMCP samples them from a generative model. Silver and Veness prove convergence in probability of their value estimate to an -optimal value under the finite-POMDP, bounded-reward, UCT-exploration, and correct-simulator conditions stated in the paper. At small budgets, rare observation branches can remain noisy or unvisited. Model correctness includes both transition and observation behavior; an observation-model error can distort the root belief update as well as simulated continuation values.
Let us implement it. Because our transitions are deterministic, sampling from is a lookup; but the code is written as if were a general distribution, which is how you would write it for a learned model.
class POMCPNode:
__slots__ = ("N", "Na", "Qa", "children")
def __init__(self):
self.N = 0
self.Na = np.zeros(N_ACTIONS)
self.Qa = np.zeros(N_ACTIONS)
self.children = {} # (action, observation) -> POMCPNode
def pomcp_select(node, c, rng):
"""UCB1 over actions at a history node."""
log_n = math.log(max(node.N, 1))
scores = np.empty(N_ACTIONS)
for a in range(N_ACTIONS):
if node.Na[a] == 0:
scores[a] = 1e9 + rng.random()
else:
scores[a] = node.Qa[a] + c * math.sqrt(log_n / node.Na[a])
return int(np.argmax(scores))
def pomcp_rollout(s_idx, rng, remaining, gamma):
"""Cheap default policy from a sampled state, using the BFS shortcut."""
total, disc = 0.0, 1.0
for _ in range(remaining):
if FREE[s_idx] == GOAL:
break
a = guided_action(FREE[s_idx], rng)
s_idx = int(rng.choice(N_CELLS, p=T[a, s_idx]))
if FREE[s_idx] == GOAL:
total += disc * GOAL_REWARD
break
total += disc * STEP_COST
disc *= gamma
return total
def pomcp_simulate(s_idx, node, rng, depth, gamma, c, max_depth):
if depth >= max_depth or FREE[s_idx] == GOAL:
return 0.0
a = pomcp_select(node, c, rng)
s2_idx = int(rng.choice(N_CELLS, p=T[a, s_idx]))
if FREE[s2_idx] == GOAL:
R = GOAL_REWARD
else:
obs = int(rng.choice(16, p=O[:, s2_idx]))
child = node.children.get((a, obs))
if child is None:
child = POMCPNode()
node.children[(a, obs)] = child
R = STEP_COST + gamma * pomcp_rollout(
s2_idx, rng, max_depth - depth - 1, gamma
)
else:
R = STEP_COST + gamma * pomcp_simulate(
s2_idx, child, rng, depth + 1, gamma, c, max_depth
)
node.N += 1
node.Na[a] += 1
node.Qa[a] += (R - node.Qa[a]) / node.Na[a]
return R
def pomcp_plan(belief, n_sims, gamma=GAMMA, c=1.2, max_depth=20, seed=0):
"""Plan from a belief by sampling states from it at the root."""
rng = np.random.default_rng(seed)
root = POMCPNode()
for _ in range(n_sims):
s_idx = int(rng.choice(N_CELLS, p=belief))
pomcp_simulate(s_idx, root, rng, 0, gamma, c, max_depth)
return rootTwo implementation notes. The rollout policy uses the BFS shortcut, which is a fully observed heuristic over the sampled latent state. It does not reason about uncertainty; the history tree above it aggregates sampled returns across latent states. Second, each (a, obs) key names one history child even though many latent successor states can produce that observation. Branching for an action equals the number of positive-probability observations reachable from the current history belief. The maze has seven signatures globally and at most three immediately reachable from one action at the initial signature-12 belief.
For clarity, this compact implementation does not persist a particle bag at every history node. It samples from an externally filtered root belief for each simulation and carries one latent state down the tree. Standard POMCP implementations can retain the states that reach a history as its particle approximation and use particle-based root updating; the exact Bayes filter used here keeps the example's filtering error separate from its search error.
The progressive contraction of the belief support in the demo above shows the mechanism the search exploits. Let us now put the planner inside the maze and let it act.
Key Parameters
The key parameters for POMCP in this chapter are:
- n_sims: Number of simulations per plan. Determines how much of the belief tree is explored.
- c: UCB1 exploration coefficient over actions at a history node.
- max_depth: Maximum simulated horizon from the root history.
- rollout policy: Default policy used to evaluate newly reached history nodes; here, a guided BFS shortcut over the sampled state.
- root belief representation and n_sims: The root belief supplies the state-sampling distribution, while
n_simsdetermines how many root-state draws feed one search. More simulations can cover the belief more thoroughly, but repeated draws need not produce that many distinct particles.
Worked Example: Localizing and Acting in a Hidden-State Maze
We are now ready to put a belief-space agent into the maze. The agent starts at an unknown location, receives only its local wall signature, and must reach the goal. Its initial belief is uniform over the cells consistent with the first observation. Its planner is POMCP, re-planning at every step from the filtered belief. Its environment is exactly the model we built.
The dynamics and sensor are deterministic and match the planner's model; uncertainty about position comes from structural aliasing of the observation. The finite-simulation POMCP computation is still randomized, however, so one seeded successful episode is a worked example rather than an estimate of success probability.
def run_pomcp_episode(
true_start, n_sims=300, max_steps=30, max_depth=20, seed=0
):
"""Closed-loop POMCP control with an exact Bayesian belief filter."""
rng = np.random.default_rng(seed + 12345)
true_idx = S_IDX[true_start]
belief = (O[SIG[true_idx]] > 0).astype(float)
belief /= belief.sum()
trace = {
"belief": [belief.copy()],
"true": [FREE[true_idx]],
"entropy": [entropy(belief)],
"actions": [],
}
total = 0.0
for t in range(max_steps):
if FREE[true_idx] == GOAL:
break
root = pomcp_plan(
belief, n_sims=n_sims, max_depth=max_depth, seed=seed * 977 + t
)
a = int(np.argmax(root.Na))
true_idx = int(rng.choice(N_CELLS, p=T[a, true_idx]))
obs = int(rng.choice(16, p=O[:, true_idx]))
belief = belief_update(belief, a, obs)
total += GOAL_REWARD if FREE[true_idx] == GOAL else STEP_COST
trace["actions"].append(a)
trace["belief"].append(belief.copy())
trace["true"].append(FREE[true_idx])
trace["entropy"].append(entropy(belief))
trace["solved"] = FREE[true_idx] == GOAL
trace["steps"] = len(trace["actions"])
trace["return"] = total
return trace
TRACE = run_pomcp_episode((0, 2), n_sims=300, max_steps=30, seed=0)Initial belief support: 8 cells Initial entropy: 2.079 nats Actions taken: ['right', 'down', 'down', 'left', 'down', 'up', 'left', 'right', 'right', 'right', 'right', 'down', 'down', 'down', 'down', 'down'] Goal reached: True in 16 steps Final entropy: 0.000 nats
In this seeded run, the agent reaches the goal in sixteen actions from an ambiguous start. Its exact filter begins with nats of uncertainty and reaches zero at control step 10. The shortest fully observed route from the true start takes ten actions, so this run uses six additional actions. We should not compare the trace's undiscounted accumulated reward directly with the discounted reported earlier, and this one trace does not establish that POMCP chose actions for their information value. It demonstrates the narrower point that history-based search can act while an external Bayes filter progressively localizes the state.
The two snapshots below show the first update of that localization process.


At step 0, the observation is consistent with eight cells. After the selected right action and next signature, exact filtering reduces the support to five cells. The panels visualize the belief used by the planner at consecutive control steps; they do not by themselves show why right was selected or prove a deliberate information-gathering choice.
The entropy trajectory shows when this particular action-observation sequence disambiguates the state. Entropy need not decrease on every step in a general POMDP, and a decreasing trace does not distinguish deliberate sensing from information obtained incidentally while pursuing reward.

Here movement changes both position and the next observation. The trace shows that localization occurred along the executed route, but establishing active information gathering would require a counterfactual comparison against less informative actions with similar task reward. The episodic tiger calculation supplies that cleaner comparison: listening has an immediate cost and no physical progress, yet it is optimal over the middle belief band because it improves the later door decision.
Key Parameters
The key parameters for the hidden-state maze experiment are:
- initial belief: The probability distribution over cells after the first observation. Its support and weights determine which latent starts the planner must account for.
- n_sims: Simulations per POMCP planning call. This controls how thoroughly the fixed current belief is searched; the real belief narrows only after an action and observation update.
- max_depth: Maximum simulated horizon from the current history node. It bounds cost per simulation and should be long enough to expose the decision-relevant consequences being compared.
- belief filter: The exact Bayes update used between planning calls. A biased or approximate filter propagates error directly into the next plan.
Learned Search Guidance
Everything so far has treated the search as a pure function of the model. Given enough simulations under the relevant consistency assumptions, MCTS can identify a good action; with a weak rollout policy, finite-budget estimates may remain poor. In the earlier experiment, the guided-rollout planner had substantially lower error than the uniform-rollout planner at every tested budget, and the only difference between them was a hand-written heuristic that followed the BFS shortest path.
That heuristic required us to compute a distance map for the maze, which we could do because we knew its finite transition graph. In a larger or learned environment, comparable guidance might be computed from a model, approximated, or learned from data. This section examines the trained-network case and bridges to the decision-centric research lineages in Part VIII.
Compute is scarce, and a prior is a guess about where search should spend it. A useful prior can improve finite-budget decisions. A misleading positive prior can be corrected when exploration and budget are sufficient; a zero prior can block an action under the displayed PUCT rule unless the implementation adds forced visits, noise, or a floor. Prior quality, confidence, model cost, and exploration therefore have to be evaluated together.
Policy Priors and Leaf Values
Three distinct insertion points illustrate how learned guidance can enter search, and they have different costs and failure modes.
In the tree policy, as an action prior. This is the in PUCT. A policy network suggests which actions are worth trying. A useful prior concentrates the search on a smaller subset of actions, so the tree can spend more of its budget on promising branches. A low-prior action can still be explored when its prior is positive, but a zero prior can suppress its exploration bonus entirely unless the implementation adds a floor or explicit initial visit. The prior guides search; by itself, it does not make search safe. In effect, a concentrated and accurate prior can reduce the tree's effective branching factor, an important source of finite-budget savings because branching compounds with depth.
At the leaves, as a value estimate. Long rollouts can dominate per-simulation cost and produce high-variance returns. AlphaZero replaces default-policy rollouts with a network evaluation at newly expanded leaves. This trades trajectory simulation for a forward pass, but it also makes search sensitive to value error away from the network's training distribution. Belief-space planners can use an analogous value estimate over histories, particles, or learned belief representations when that estimate is available. The estimate is available immediately at every leaf without the cost of a rollout, but systematic value error can bias backed-up statistics unless later expansion or terminal evidence corrects it.
As an amortized policy. Once search has run, its root visit counts define a distribution over actions. A policy network can be trained on that distribution so later searches start from a prior shaped by earlier search. AlphaZero uses this policy-improvement loop while training its value head on game outcomes. In the usual amortized setting, one policy evaluation is cheaper than rerunning the search that supplied its target, but its agreement with search depends on training coverage, on optimization, and on model capacity. Improved agreement can reduce the search budget needed for a target quality, but that is an empirical outcome rather than a guaranteed monotonic trend.
The loop has four parts. (1) Run PUCT with a policy head as the prior and a value head for leaf evaluation. (2) Turn the root visit counts into a target distribution, . (3) Train the policy head against and train the value head against the observed game outcome, with regularization. (4) Repeat. Search supplies a policy-improvement target, while self-play outcomes supervise the value estimate that later searches use. The bookkeeping is what makes the loop work: search must be an accurate supervisor and the policy must be an accurate student, or the two will agree on a shared mistake.
Learned Guidance in Practice
Let us train a policy prior for the maze and see what it does to the search. The setup is deliberately small: a one-hot state encoding, a two-hidden-layer MLP, and a supervised target taken from value iteration. A larger system might train on search targets, demonstrations, or offline trajectories rather than an exact tabular solution. The interface remains a function that returns an action distribution for a given state. In our toy setting the network learns a lookup table with extra steps; with structured inputs and incomplete coverage, the same interface can instead generalize across states, provided the learned representation and training data support it.
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(0)
np.random.seed(0)
def optimal_action(state):
qs = []
for a in range(N_ACTIONS):
s2, r, done = step(state, a)
qs.append(r + (0.0 if done else GAMMA * V_STAR[s2]))
return int(np.argmax(qs))
X_states = torch.eye(N_CELLS, dtype=torch.float32)
y_targets = torch.tensor([optimal_action(s) for s in FREE], dtype=torch.long)
policy_net = nn.Sequential(
nn.Linear(N_CELLS, 96),
nn.ReLU(),
nn.Linear(96, 96),
nn.ReLU(),
nn.Linear(96, N_ACTIONS),
)
optimizer = torch.optim.Adam(policy_net.parameters(), lr=4e-3)
training_losses = []
for epoch in range(800):
logits = policy_net(X_states)
loss = F.cross_entropy(logits, y_targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
training_losses.append(float(loss.detach()))
with torch.no_grad():
raw_policy_probs = torch.softmax(policy_net(X_states), dim=-1).numpy()
# Mix in a small uniform floor. Cross-entropy on this separable lookup task can
# otherwise drive non-target float32 probabilities to numerical zero, which
# would remove their ordinary PUCT exploration bonus.
PRIOR_FLOOR_MIX = 0.02
policy_probs = (
1.0 - PRIOR_FLOOR_MIX
) * raw_policy_probs + PRIOR_FLOOR_MIX / N_ACTIONS
match_rate = float((policy_probs.argmax(axis=1) == y_targets.numpy()).mean())
# Full-batch optimization is deterministic here, so the raw epoch loss is
# already smooth enough to show directly.
training_loss_curve = np.asarray(training_losses)Initial loss 1.3934 -> final loss 0.000000 Agreement with the optimal action: 100.0% of states
The network fits the target. That is expected: the state space has twenty-two elements, so this is essentially a lookup table with extra steps. What matters for PUCT is the distribution the network produces, because the exploration term uses action probabilities rather than only the top label. Cross-entropy training drives this tiny separable problem toward numerically one-hot outputs, so the code mixes in two percent uniform probability after training. The floor preserves the learned top-action ranking while giving every alternative a nonzero prior factor in the PUCT bonus; forced first visits provide a second safeguard.
Let us look at the training curve and at the prior the network assigns to a few representative states.


At the start state the floored prior puts almost all mass on right, which agrees with the tabular target. At , a cell at the bottom of the dead-end arm, it concentrates on up, the target's unique maximizer there. Each non-target action retains probability from the explicit floor. That floor does not guarantee rapid recovery from a bad prior, but it prevents the learned distribution itself from assigning an action exactly zero PUCT bonus.
Now we install the prior and re-run the convergence experiment.
def learned_prior(state, action):
return float(policy_probs[S_IDX[state], action])
GUIDANCE_ERRORS["Learned prior"] = []
GUIDANCE_VISIT_SHARE["Learned prior"] = []
for budget in BUDGETS:
errs, shares = [], []
for s in SEEDS:
tree = mcts(START, n_sims=budget, priors=learned_prior, seed=s)
a = root_choice(tree)
errs.append(abs(tree.children[a].Q - V_STAR[START]))
shares.append(tree.children[OPTIMAL_FIRST_ACTION].N / budget)
GUIDANCE_ERRORS["Learned prior"].append(float(np.mean(errs)))
GUIDANCE_VISIT_SHARE["Learned prior"].append(float(np.mean(shares)))No guidance 0.981 0.982 0.982 0.985 0.986 0.988 0.990 Guided rollouts 0.174 0.203 0.220 0.239 0.251 0.265 0.274 Learned prior 0.968 0.936 0.595 0.289 0.142 0.070 0.035
The learned prior has the lowest error of the three configurations at the larger tested budgets and reaches an error of at 800 simulations. It does not require the BFS distance map at inference, but its labels were generated from converged value iteration over all twenty-two states, so topology entered through supervision. The one-hot input and complete training set make this a memorization experiment; it demonstrates the PUCT interface and finite-budget allocation effect, not generalization to unseen states.
<matplotlib.legend.Legend at 0x11aacbed0>


The two guidance mechanisms enter at different points. The hand-coded rollout heuristic changes returns beyond the represented tree. The learned prior changes selection before those returns are observed. They can be combined, although this chapter evaluates them separately. AlphaZero-style search combines a policy prior with a learned leaf value instead of a default rollout. A biased leaf value can then bias backed-up search statistics, while continued expansion and terminal outcomes may provide additional correction depending on the domain and budget.
This experiment does not test a misleading prior: the network's top action matches the exact tabular target at every training state. A prior learned from incomplete data can misrank actions, and at finite budget PUCT may then under-sample a low-prior alternative. The outcome depends jointly on the prior probabilities, exploration coefficient, forced-visit or root-noise mechanism, value estimates, and available simulations. To test whether search tolerates a misleading prior, use deliberately corrupted or out-of-distribution priors; the oracle-trained result here cannot establish that tolerance.
Key Parameters
The key parameters for learned search guidance are:
- policy head architecture: Size and depth of the network producing PUCT action priors. More capacity can represent more complex state-to-action mappings but costs more to train and evaluate.
- lr: Learning rate for the policy network optimizer. Controls how quickly the prior adapts to training targets.
- epochs: Number of training passes over the supervised targets. Too few can underfit; additional epochs reduce training loss here, but held-out evaluation is needed to diagnose overfitting or overconfidence.
- PUCT coefficient c: Exploration coefficient used when the learned prior drives selection. Sets how strongly the prior is allowed to outweigh the sampled Q values.
Limitations and Impact
Search-based planning gives a world model another useful interface: the planner can query a generative simulator without differentiating through it or enumerating its full state space. That makes tree search a natural option for discrete or hybrid choices and for partially observed problems represented by a sampling model. UCT connects bandit selection to Monte Carlo planning; AlphaGo and AlphaZero add learned priors and values. POMCP starts simulations from states sampled from the root belief and indexes its tree by action-observation histories. POMCPOW combines progressive widening with observation-likelihood-weighted particle filtering to address continuous action and observation spaces. These methods still require a usable simulator, a bounded search representation, and adequate coverage of high-value or safety-critical branches.
The limitations below are organized by mechanism, not by a claimed universal frequency ranking; their importance depends on the application.
Search can amplify model error. This is a central caveat for model-based search. MCTS preferentially explores the parts of the model where predicted value is highest. If model error makes a region look unusually good, search can find that region and allocate many simulations to it. This is the same failure mode we discussed under model exploitation in Model-Based Reinforcement Learning, and it interacts badly with partial observability because the belief update also depends on the model. A biased observation model can produce a biased belief and plan, with later observations feeding the same loop. Ensembles for uncertainty quantification (as in PETS, which we cover in PILCO, PETS, Ensembles, and MBPO) and pessimism under uncertainty can mitigate this problem but do not eliminate it. Optimistic model errors are especially damaging because the search procedure favors high predicted values.
The belief tree adds an observation-branching stage after each action. A complete action-observation layer has at most branches, but only positive-probability observations count at a particular belief. In our initial eight-cell belief, left and right each have three possible next signatures, while up and down each have one, for eight reachable action-observation pairs in total rather than . A continuous observation space has uncountably many possible values, while any sampled tree remains finite. Progressive widening and discretization, along with particle clustering, control representation size but can merge or miss decision-relevant observations.
Exact finite-horizon belief-MDP value iteration faces a doubly exponential pre-pruning candidate recurrence in the worst case, over a continuous belief simplex; the number of undominated vectors that remains is instance-dependent. Exact algorithms remain practical for some small structured problems; PBVI and SARSOP, along with online sampling, trade global exactness for selected beliefs or histories. If decision-relevant regions are not represented, the resulting policy can be poor there, so coverage and bound diagnostics should be evaluated explicitly.
Monte Carlo estimates can have high variance at small budgets, especially when return outcomes differ sharply across latent states and observation branches. In a controller, unstable action rankings can cause action switching, although the physical effect is application-dependent. More simulations, variance-reduced rollouts, learned leaf values, and deliberate tie-breaking or action-smoothing policies can help. Choosing by visit count reports the tree policy's allocation rather than the largest sampled mean; which final-action rule behaves better is problem- and budget-dependent.
Computational cost is a hard constraint in real control loops. A 50 Hz controller has 20 milliseconds per control interval. Our POMCP example uses 300 simulations per step with a cheap tabular generative model; replacing it with a neural simulator changes the cost according to batching, hardware, model size, and tree depth. Amortized policies and learned values shift some work from online search into training, but total online and offline cost is not fixed by a universal law. It must be measured for the chosen system and quality target.
Search trades online computation for action selection that is adapted to the current state or belief, provided the simulator is trustworthy on the branches being compared. An amortized policy may be preferable when latency is tight; online search may be valuable when the current belief changes the decision sharply. Safety-critical systems also need a defined failure response when search times out or its assumptions are violated. Whether that response is a fallback policy, safe stop, or supervisory controller is application-specific.
Summary
Search-based planning turns a world model into decisions by exploring selected action consequences rather than enumerating every future. Its result is only as reliable as the model, search coverage, and finite-budget statistics. A deployed controller therefore needs an explicit response to search timeout or invalid assumptions.
UCT-style MCTS replaces uniform expansion with a simulation budget allocated by a bandit rule. The four phases — selection, expansion, simulation, and backpropagation — implement that allocation. UCB-style scores balance sampled value against exploration, while PUCT adds a policy prior. Finite-budget search values and visit counts are different decision statistics, and implementations choose a final-action rule to match their training or control design. Progressive widening extends the scheme to large or continuous action spaces.
Planning under partial observability retains the latent physical state but replaces the planner's known-state input with a belief. Under the assumed model, the belief and any required finite-horizon time index are sufficient for control. When state, action, observation, and horizon are all finite, the optimal reward-maximizing belief value is piecewise linear and convex, with worst-case growth in its alpha-vector representation. QMDP and most-likely-state planning discard future uncertainty; point-based methods back up selected beliefs; online sampling methods plan locally from the current belief under a compute budget.
Belief trees and information gathering make the belief-space structure concrete. A belief tree branches on observations and can index its nodes by action-observation histories; the belief at a node is obtained by filtering along the path from the root. An informative action has task value when its observation changes later decisions enough to repay its sensing and transition costs; entropy reduction alone does not establish that value. The tiger problem isolates this effect through a listening region in which new information changes which door can be opened safely. POMCP samples latent states and observations from a generative model while indexing its tree by observable history.
Learned search guidance addresses finite-budget allocation. Priors enter PUCT selection, value estimates can replace default rollouts at leaves, and search visit distributions can supervise an amortized policy. In this seeded toy experiment, both the BFS rollout heuristic and the oracle-trained action prior reduce value error relative to uniform rollouts over the tested budgets; only the learned prior approaches the fully observed reference value. Because the network sees one-hot encodings of every state and exact tabular labels, the result demonstrates search guidance but not generalization.
Two threads carry forward. Policies Learned in Imagination and the Dreamer family amortize decisions learned through model interaction rather than running this tree search at every action. Active Perception, Dual Control, and Exploration develops the information-action tradeoff beyond the value-of-information framing used here. These methods share the objective-design lessons from Chapters 37 and 38 while representing alternatives and uncertainty differently.
Quiz
Ready to test your understanding? Take this quick quiz to reinforce what you've learned about search-based planning, Monte Carlo Tree Search, and planning under partial observability.
Search and Belief-Space Planning
Reference
Citation details
Cite or share this article.
Continue with the full handbook
This chapter is part of World Models Handbook. Use the handbook page to browse the complete table of contents and continue reading in sequence.
Explore World Models HandbookStay up to date
Get articles, book updates, and news delivered to your inbox.
No spam, unsubscribe anytime.
Join the community
Sign in to remove popups, track your reading progress, and join the discussion.

Comments
No comments yet. Be the first to share your thoughts!