AI-330 · Lesson 3 of 12 · 28 min

Dynamic programming

When the MDP is known, meaning the transition probabilities and rewards are available, optimal policies can be computed rather than learned. Dynamic programming (DP), developed by Richard Bellman in the 1950s, solves the Bellman equations by turning them into update rules and iterating. DP is rarely applied directly to large problems, because it needs a complete model and sweeps over every state, but it is the conceptual foundation of all of RL: Monte Carlo, temporal-difference, Q-learning and actor-critic methods can all be understood as ways of approximating DP without a model and without visiting every state. This lesson covers policy evaluation, policy improvement, policy iteration and value iteration, their convergence, generalized policy iteration, and the curse of dimensionality.

Policy evaluation

Policy evaluation computes \(v_\pi\) for a given policy. For small problems the Bellman equations can be solved directly as a linear system, as in Lesson 1, but that costs \(O(|\mathcal S|^3)\). Iterative policy evaluation instead turns the Bellman equation into an update applied to every state in a sweep:

\[v_{k+1}(s) = \sum_a \pi(a \mid s)\sum_{s'} p(s' \mid s, a)\big[r(s, a) + \gamma v_k(s')\big]\]

Starting from any \(v_0\), for example all zeros, the sequence converges to \(v_\pi\) as \(k \to \infty\). The reason is that the Bellman operator \(T_\pi\), which maps a value function to the right-hand side, is a \(\gamma\)-contraction in the maximum norm: \(\|T_\pi v - T_\pi u\|_\infty \le \gamma\|v - u\|_\infty\). Each sweep shrinks the error by at least a factor of \(\gamma\), so the error after \(k\) sweeps is at most \(\gamma^k\) times the initial error. In practice, sweeps stop when the largest change in any state falls below a small threshold.

Each update replaces the estimate of a state's value with an expectation over successor states using their current estimates. This idea, updating estimates on the basis of other estimates, is called bootstrapping, and it is central to most RL methods. Updating in place, using new values as soon as they are computed within a sweep (like Gauss-Seidel in ELE-380), usually converges faster than keeping two arrays.

Two backup diagrams. The left, for the Bellman expectation equation for v pi, shows an open circle for state s at the top, branching to filled dots for each action weighted by pi, each branching to open circles for successor states s prime with probabilities p and rewards r. The right, for the Bellman optimality equation, has the same structure but with an arc across the action branches indicating a maximum instead of an average.
Backup diagrams: policy evaluation averages over actions; optimality takes the maximum.

Policy improvement

Knowing \(v_\pi\), can we find a better policy? Compute the action values \(q_\pi(s, a) = \sum_{s'} p(s' \mid s, a)[r(s, a) + \gamma v_\pi(s')]\) and act greedily:

\[\pi'(s) = \arg\max_a q_\pi(s, a)\]

The policy improvement theorem guarantees that \(\pi'\) is at least as good as \(\pi\) in every state: \(v_{\pi'}(s) \ge v_\pi(s)\). Intuitively, choosing a better action in one state and then following \(\pi\) is better than following \(\pi\) throughout, and repeating the argument at every step shows that following \(\pi'\) throughout is better still. If the greedy policy is no better than \(\pi\) anywhere, then \(v_\pi\) satisfies the Bellman optimality equation and \(\pi\) is optimal.

Policy iteration

Policy iteration alternates the two steps: evaluate the current policy, improve it greedily, and repeat until the policy stops changing. Because a finite MDP has a finite number of deterministic policies and each iteration produces a strictly better policy until the optimum, policy iteration converges in a finite number of iterations, usually very few, even for large state spaces.

\[\pi_0 \xrightarrow{E} v_{\pi_0} \xrightarrow{I} \pi_1 \xrightarrow{E} v_{\pi_1} \xrightarrow{I} \pi_2 \longrightarrow \cdots \longrightarrow \pi_* \xrightarrow{E} v_*\]
Policy iteration and value iteration on the machine maintenance MDP
import numpy as np

P = {0: np.array([[0.8, 0.2, 0.0], [0.0, 0.7, 0.3], [0.0, 0.0, 1.0]]),
     1: np.array([[1.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 0.0, 0.0]])}
R = {0: np.array([10.0, 6.0, 0.0]), 1: np.array([-4.0, -4.0, -12.0])}
gamma, names = 0.95, ["run", "repair"]

def q_values(V):
    return np.array([R[a] + gamma * P[a] @ V for a in (0, 1)])     # shape (actions, states)

# policy iteration: evaluate exactly, then improve greedily
policy = np.array([0, 0, 0])                                         # start: never repair
for it in range(1, 10):
    P_pi = np.array([P[policy[s]][s] for s in range(3)])
    R_pi = np.array([R[policy[s]][s] for s in range(3)])
    V = np.linalg.solve(np.eye(3) - gamma * P_pi, R_pi)
    new = q_values(V).argmax(axis=0)
    print(f"PI iteration {it}: policy {[names[a] for a in policy]}  V = {np.round(V, 2)}")
    if np.array_equal(new, policy):
        break
    policy = new

# value iteration on the same MDP
V = np.zeros(3)
for k in range(1, 1000):
    V_new = q_values(V).max(axis=0)
    if np.max(np.abs(V_new - V)) < 1e-6:
        break
    V = V_new
print(f"value iteration: {k} sweeps to converge, V = {np.round(V, 2)}, policy {[names[a] for a in q_values(V).argmax(axis=0)]}")
Output
PI iteration 1: policy ['run', 'run', 'run']  V = [55.85 17.91  0.  ]
PI iteration 2: policy ['run', 'repair', 'repair']  V = [155.29 143.53 135.53]
value iteration: 310 sweeps to converge, V = [155.29 143.53 135.53], policy ['run', 'repair', 'repair']

Starting from "never repair", one round of evaluation and improvement finds the optimal policy, "run when good, repair when worn or broken", and the second evaluation confirms that it no longer changes. Value iteration, described next, reaches the same values but needs hundreds of cheap sweeps, because with \(\gamma = 0.95\) the error shrinks by only 5% per sweep.

Value iteration

Policy iteration evaluates each policy fully, which can be wasteful when the policy will soon change anyway. Value iteration combines a single sweep of evaluation with improvement, by applying the Bellman optimality equation as an update:

\[v_{k+1}(s) = \max_a \sum_{s'} p(s' \mid s, a)\big[r(s, a) + \gamma v_k(s')\big]\]

The Bellman optimality operator is also a \(\gamma\)-contraction, so value iteration converges to \(v_*\) from any start. When the values have converged to within a tolerance, the greedy policy with respect to them is optimal or near-optimal; in fact the greedy policy often becomes optimal long before the values have converged.

Value iteration on a gridworld with slippery moves, a goal and a pit
import numpy as np

# 4 x 5 gridworld: G goal (+10, terminal), X pit (-10, terminal), # wall, step reward -1.
grid = ["....G",
        ".#..X",
        ".....",
        "S...."]
H, W = len(grid), len(grid[0])
moves = {"^": (-1, 0), "v": (1, 0), "<": (0, -1), ">": (0, 1)}
perp = {"^": "<>", "v": "<>", "<": "^v", ">": "^v"}
gamma, slip = 0.95, 0.2                       # intended move with prob 0.8, each perpendicular 0.1

def step(r, c, a):
    dr, dc = moves[a]
    r2, c2 = r + dr, c + dc
    if not (0 <= r2 < H and 0 <= c2 < W) or grid[r2][c2] == "#":
        return r, c
    return r2, c2

def outcomes(r, c, a):
    res = [(1 - slip, step(r, c, a))]
    res += [(slip / 2, step(r, c, b)) for b in perp[a]]
    return res

V = np.zeros((H, W)); sweeps = 0
while True:
    delta = 0.0
    for r in range(H):
        for c in range(W):
            if grid[r][c] in "GX#":
                continue
            best = -1e9
            for a in moves:
                q = 0.0
                for p, (r2, c2) in outcomes(r, c, a):
                    term = {"G": 10.0, "X": -10.0}.get(grid[r2][c2])
                    q += p * (-1 + (term if term is not None else gamma * V[r2, c2]))
                best = max(best, q)
            delta = max(delta, abs(best - V[r, c])); V[r, c] = best
    sweeps += 1
    if delta < 1e-6:
        break

print(f"value iteration converged in {sweeps} sweeps")
for r in range(H):
    row = []
    for c in range(W):
        ch = grid[r][c]
        if ch in "GX#":
            row.append(f"  {ch}   "); continue
        qs = {}
        for a in moves:
            q = 0.0
            for p, (r2, c2) in outcomes(r, c, a):
                term = {"G": 10.0, "X": -10.0}.get(grid[r2][c2])
                q += p * (-1 + (term if term is not None else gamma * V[r2, c2]))
            qs[a] = q
        row.append(f"{max(qs, key=qs.get)}{V[r, c]:5.1f}")
    print(" ".join(row))
Output
value iteration converged in 20 sweeps
>  3.0 >  4.7 >  6.3 >  8.2   G
^  1.6   #    ^  4.7 ^  4.7   X
^  0.4 >  1.4 ^  3.0 ^  2.9 <  0.2
^ -0.8 >  0.2 ^  1.4 ^  1.3 <  0.0

The arrows show the optimal action in each cell and the numbers its value. With a step cost of −1 and a 20% chance of slipping sideways, the agent heads for the goal along the top row, and the cells next to the pit point away from it: in the second row, the agent next to the pit moves up rather than right, accepting a longer route to avoid a 10% chance of slipping into the pit. In the bottom-right corner, the agent moves left rather than up, since moving up passes beside the pit. The policy accounts for risk without any explicit rule, because the values encode expected returns.

Gridworld of 4 rows and 5 columns drawn as a heat map of state values, with the goal in the top-right corner shaded green, a pit below it shaded red, and a wall in the second row. Each free cell shows an arrow for the optimal action and its value: the top row has arrows pointing right with values rising from 3.0 to 8.2 toward the goal; cells near the pit point up or left, away from it; the start cell in the bottom-left corner has value minus 0.8.
Optimal values and policy for the slippery gridworld.

Worked problem

One sweep of value iteration by hand

A corridor of three states 1, 2, 3 leads to a goal on the right. Each move costs −1, except that moving right from state 3 reaches the goal, which gives +10 and ends the episode. Actions are left and right, deterministic; moving left from state 1 stays in state 1. With \(\gamma = 1\) and \(v_0 = 0\), compute \(v_1\) and \(v_2\) with synchronous updates.

Show solution
  1. Sweep 1: in state 3, right reaches the goal for +10 and left gives \(-1 + 0 = -1\), so \(v_1(3) = 10\). In states 1 and 2 the best is \(-1 + 0 = -1\).
  2. Sweep 2: \(v_2(3) = 10\); \(v_2(2) = -1 + v_1(3) = 9\); \(v_2(1) = -1 + v_1(2) = -2\).
  3. Sweep 3 gives \(v_3(1) = -1 + v_2(2) = 8\).

Answer: Values propagate back from the goal one state per sweep: \(v_1 = (-1, -1, 10)\), \(v_2 = (-2, 9, 10)\), converging to \((8, 9, 10)\). This backward propagation is the essence of DP, and in learning methods it is why rewards far from their causes take many updates to propagate.

Asynchronous DP and generalized policy iteration

DP need not sweep all states systematically. Asynchronous DP updates states in any order, as long as every state continues to be updated, and still converges. This allows focusing computation on the states that matter: those visited by the agent, those near recent changes (prioritized sweeping), or those relevant to the current decision (real-time DP). Learning methods carry this further by updating only states the agent actually experiences.

Policy iteration, value iteration and almost all RL methods share a common structure, generalized policy iteration (GPI): a value function is driven toward the value of the current policy (evaluation), and the policy is driven toward being greedy with respect to the value function (improvement). The two processes compete, since improving the policy makes the value function inaccurate and correcting the values may make the policy no longer greedy, but they converge jointly to the optimal value function and an optimal policy. Methods differ in how much evaluation they do before improving, and in whether they use a model, samples or function approximation.

Diagram of generalized policy iteration. Two lines converge toward a point labeled v star and pi star at the top. One line represents v equals v pi, the other pi equals greedy of v. A zigzag path alternates between the two lines, each step labeled evaluation or improvement, climbing toward the optimum.
Generalized policy iteration: evaluation and improvement interact and converge to the optimum.

The curse of dimensionality

DP's cost per sweep is roughly \(O(|\mathcal S|^2|\mathcal A|)\) for dense transitions, or \(O(|\mathcal S||\mathcal A|b)\) where \(b\) is the number of possible successor states. This is polynomial in the number of states, much better than searching all \(|\mathcal A|^{|\mathcal S|}\) policies. The problem is that the number of states itself grows exponentially with the number of state variables: a robot arm with 7 joints, each discretized into 100 positions and 100 velocities, has \(10^{28}\) states. Bellman called this the curse of dimensionality. Backgammon has about \(10^{20}\) states and Go about \(10^{170}\), far beyond any table.

Two further obstacles block direct use of DP: the model is often unknown, and even when it exists (a simulator), it may only produce samples rather than explicit probabilities. Lessons 5 to 12 address both. Sample-based methods learn from experience without a model and concentrate on states that actually occur, and function approximation generalizes from visited states to similar unvisited ones.

Worked problem

Counting states

A warehouse robot's state consists of its position on a 50 × 50 grid, its heading (4 values), whether it carries a package (2 values) and the positions of 3 other robots on the same grid. How many states are there? How much memory would a table of action values with 6 actions need at 4 bytes per value?

Show solution
  1. Own state: \(2500 \times 4 \times 2 = 20{,}000\).
  2. Other robots: \(2500^3 = 1.56 \times 10^{10}\).
  3. Total: \(20{,}000 \times 1.56 \times 10^{10} = 3.1 \times 10^{14}\) states; table: \(3.1 \times 10^{14} \times 6 \times 4 = 7.5 \times 10^{15}\) bytes.

Answer: About \(3 \times 10^{14}\) states and 7.5 petabytes for the table, impractical even to store, let alone sweep. Adding agents multiplies the state space, which is why multi-agent and real-world problems need function approximation and structure.

Lesson 4 examines how to formulate the MDPs that dynamic programming solves, and Lesson 6 shows how planning with learned models brings these ideas to problems where the model must be learned.

Common mistakes

  • MistakeWaiting for values to converge exactly before trusting the greedy policy.

    InsteadThe greedy policy often becomes optimal well before the values converge.

  • MistakeAssuming value iteration converges quickly for γ near 1.

    InsteadError shrinks by a factor of γ per sweep; γ = 0.99 needs hundreds of sweeps for modest accuracy.

  • MistakeApplying DP without a model.

    InsteadDP needs transition probabilities and rewards; without them, use sample-based methods.

  • MistakeDiscretizing many continuous variables finely for tabular DP.

    InsteadStates grow exponentially with dimension; use function approximation.

  • MistakeTreating policy iteration and value iteration as unrelated.

    InsteadBoth are instances of generalized policy iteration with different amounts of evaluation.

Summary and key terms

  • DP computes optimal policies from a known model by iterating Bellman equations.
  • Iterative policy evaluation converges because the Bellman operator is a γ-contraction; updates bootstrap from current estimates.
  • Policy improvement: acting greedily with respect to q_π gives a policy at least as good.
  • Policy iteration alternates full evaluation and improvement, converging in few iterations.
  • Value iteration applies the Bellman optimality update; the greedy policy is optimal at convergence.
  • Asynchronous DP updates states in any order, focusing computation where it matters.
  • Generalized policy iteration describes almost all RL methods.
  • The curse of dimensionality and unknown models motivate sampling and function approximation.
Dynamic programming
Methods that compute optimal policies from a known model using Bellman equations.
Policy evaluation
Computing the value function of a given policy.
Bootstrapping
Updating estimates on the basis of other estimates.
Contraction
A mapping that brings any two points closer by at least a fixed factor.
Policy improvement theorem
Acting greedily with respect to q_π yields a policy at least as good as π.
Policy iteration
Alternating full policy evaluation and greedy improvement.
Value iteration
Iterating the Bellman optimality update to find v_*.
Backup diagram
A diagram showing which successor values an update uses.
Asynchronous DP
DP that updates states in any order rather than full sweeps.
Prioritized sweeping
Updating states in order of the expected size of their value change.
Generalized policy iteration
The interaction of evaluation and improvement processes converging to optimality.
Curse of dimensionality
The exponential growth of the state space with the number of state variables.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. After how many sweeps of policy evaluation with γ = 0.9 is the error guaranteed below 1% of its initial value?

    Show answer

    0.9^k < 0.01 → k > 43.7, so 44 sweeps.

  2. What does bootstrapping mean in DP?

    Show answer

    Each state's new estimate uses the current estimates of its successor states.

  3. In a state, q_π(s, ·) = (3.2, 4.1, 2.7) for actions a1, a2, a3; π chooses a1. What does policy improvement choose?

    Show answer

    a2, the action with the highest q_π.

  4. Why does policy iteration terminate in a finite number of iterations?

    Show answer

    There are finitely many deterministic policies and each iteration strictly improves until the optimal policy is reached.

  5. State the value iteration update.

    Show answer

    v_{k+1}(s) = max_a Σ_{s′} p(s′|s,a)[r(s,a) + γ v_k(s′)].

  6. In the corridor example with 5 states instead of 3, how many sweeps until the leftmost state has a correct value?

    Show answer

    5 sweeps; values propagate one state per sweep from the goal.

  7. Why does the gridworld agent next to the pit move away from it?

    Show answer

    Moving alongside the pit risks slipping into it (−10); the values make the safer, longer route better in expectation.

  8. What is generalized policy iteration?

    Show answer

    The interplay of making values consistent with the policy and making the policy greedy with respect to the values, converging to optimality.

  9. A system has 10 state variables, each with 20 values. How many states?

    Show answer

    20¹⁰ ≈ 1.0 × 10¹³.

  10. Give two reasons DP is not applied directly to large real problems.

    Show answer

    The model is unknown or only available as a sampler; the state space is too large to sweep or store.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz