Skip to content
AI360Xpert
Beta

Value Iteration

Value iteration converges directly to the optimal state values by updating each state with the best possible immediate action and next-state return in a single Bellman backup.

Value iteration repeatedly applies the Bellman optimality backup across all states, contracting directly toward the optimal value function without evaluating intermediate policies to convergence.
Value iteration repeatedly applies the Bellman optimality backup across all states, contracting directly toward the optimal value function without evaluating intermediate policies to convergence.

Why Does This Exist?

In reinforcement learning, when an agent possesses complete knowledge of the environment's transition dynamics and reward model—formalized as a Markov Decision Process—it can compute the optimal policy directly using dynamic programming.

The classic approach, Policy Iteration, decomposes this goal into two strict, alternating phases:

  1. Policy Evaluation: Compute the exact state values VπV^\pi for the current policy π\pi, which requires either inverting a ∣S∣×∣S∣|\mathcal{S}| \times |\mathcal{S}| transition matrix or running many iterative sweeps until values converge to high precision.
  2. Policy Improvement: Greedily update the policy with respect to the freshly calculated VπV^\pi.

In practice, full policy evaluation is computationally wasteful. The greedy action choices often lock into their optimal choices after only a few sweeps, long before the numerical value estimates converge to multiple decimal places.

Value Iteration solves this inefficiency by truncating policy evaluation after exactly one sweep. Instead of evaluating a candidate policy to convergence before improving it, Value Iteration merges evaluation and greedy improvement into a single update. Every sweep directly applies the Bellman optimality equation with a max⁡\max operator over all possible actions. The algorithm operates entirely in value space, deferring explicit policy extraction until the value function has contracted to near-optimality.

Think of It Like This

Filling a lake with water: propagation to equilibrium

Imagine a tiered network of mountain reservoirs and dry riverbeds down-slope from a glacial waterfall (the primary reward source).

At the start (k=0k=0), every dry basin across the landscape has an estimated water level of zero (V0=0V_0 = 0).

On the first day, the waterfall pours directly into the top tier of reservoirs immediately adjacent to it, raising their water level to reflect the immediate influx. On the second day, those newly elevated reservoirs spill outward into the next tier of reservoirs downstream. Water levels propagate outward, one elevation step per cycle, driven by hydraulic gradients.

Each basin updates its water height based strictly on the highest inflow sluice gate connected to it (the max⁡\max over actions), discounted by the frictional resistance of distance (the discount factor γ\gamma).

Crucially, hydraulic engineers do not need to pause and simulate microscopic eddy currents until perfect molecular stillness (full policy evaluation) before allowing water to spill forward. Each discrete surge propagates the highest incoming level to the next pool. Cycle after cycle, the flood front advances across the entire mountain until water levels everywhere stabilize in hydrostatic equilibrium (V∗V^*).

Where the analogy stops: Physical fluids conserve mass, obey momentum, and follow continuous Navier-Stokes equations. Value Iteration operates through discrete mathematical projections over state spaces, where future returns are geometrically discounted by γ∈[0,1)\gamma \in [0, 1) rather than governed by physical mass conservation.

How It Actually Works

The Bellman optimality operator and truncated policy evaluation

Consider a finite Markov Decision Process (S,A,p,γ)(\mathcal{S}, \mathcal{A}, p, \gamma), where:

  • S\mathcal{S} is the finite set of environmental states.
  • A(s)\mathcal{A}(s) is the set of actions available in state ss.
  • p(s′,r∣s,a)=P(St+1=s′,Rt+1=r∣St=s,At=a)p(s', r \mid s, a) = \mathbb{P}(S_{t+1} = s', R_{t+1} = r \mid S_t = s, A_t = a) is the joint transition and reward probability function.
  • γ∈[0,1)\gamma \in [0, 1) is the temporal discount factor.

The optimal state-value function V∗(s)V^*(s) represents the maximum expected discounted return attainable from state ss under any policy. It satisfies the non-linear Bellman Optimality Equation:

V∗(s)=max⁡a∈A(s)∑s′∈S∑rp(s′,r∣s,a)[r+γV∗(s′)]V^*(s) = \max_{a \in \mathcal{A}(s)} \sum_{s' \in \mathcal{S}} \sum_{r} p(s', r \mid s, a) \left[ r + \gamma V^*(s') \right]

Equivalently, letting expected immediate reward be R(s,a)=∑s′,rr p(s′,r∣s,a)\mathcal{R}(s, a) = \sum_{s', r} r\, p(s', r \mid s, a) and transition dynamics be P(s′∣s,a)=∑rp(s′,r∣s,a)\mathcal{P}(s' \mid s, a) = \sum_{r} p(s', r \mid s, a):

V∗(s)=max⁡a∈A(s)[R(s,a)+γ∑s′∈SP(s′∣s,a)V∗(s′)]V^*(s) = \max_{a \in \mathcal{A}(s)} \left[ \mathcal{R}(s, a) + \gamma \sum_{s' \in \mathcal{S}} \mathcal{P}(s' \mid s, a) V^*(s') \right]

Value Iteration turns this mathematical identity into an iterative update rule. Starting with an arbitrary initial value array V0V_0 (typically all zeros), it repeatedly updates each state:

Vk+1(s)←max⁡a∈A(s)[R(s,a)+γ∑s′∈SP(s′∣s,a)Vk(s′)]∀s∈SV_{k+1}(s) \leftarrow \max_{a \in \mathcal{A}(s)} \left[ \mathcal{R}(s, a) + \gamma \sum_{s' \in \mathcal{S}} \mathcal{P}(s' \mid s, a) V_k(s') \right] \quad \forall s \in \mathcal{S}

The Bellman optimality operator (T∗\mathcal{T}^*)

We can define the Bellman optimality backup as an operator T∗:R∣S∣→R∣S∣\mathcal{T}^*: \mathbb{R}^{|\mathcal{S}|} \to \mathbb{R}^{|\mathcal{S}|}:

(T∗V)(s)=max⁡a∈A(s)[R(s,a)+γ∑s′∈SP(s′∣s,a)V(s′)](\mathcal{T}^* V)(s) = \max_{a \in \mathcal{A}(s)} \left[ \mathcal{R}(s, a) + \gamma \sum_{s' \in \mathcal{S}} \mathcal{P}(s' \mid s, a) V(s') \right]

Value iteration is simply the successive application of this operator: Vk+1=T∗VkV_{k+1} = \mathcal{T}^* V_k.

Contraction mapping and convergence guarantee

Under the supremum norm (infinity norm) ∥V∥∞=max⁡s∈S∣V(s)∣\|V\|_\infty = \max_{s \in \mathcal{S}} |V(s)|, the operator T∗\mathcal{T}^* is a γ\gamma-contraction mapping:

∥T∗U−T∗V∥∞≤γ∥U−V∥∞∀U,V∈R∣S∣\|\mathcal{T}^* U - \mathcal{T}^* V\|_\infty \le \gamma \|U - V\|_\infty \quad \forall U, V \in \mathbb{R}^{|\mathcal{S}|}

Because 0≤γ<10 \le \gamma < 1, the Banach Fixed-Point Theorem delivers three vital guarantees:

  1. Uniqueness: There is exactly one fixed-point value function V∗V^* such that T∗V∗=V∗\mathcal{T}^* V^* = V^*.
  2. Global convergence: Starting from any arbitrary initial vector V0V_0, the sequence Vk+1=T∗VkV_{k+1} = \mathcal{T}^* V_k converges to V∗V^* as k→∞k \to \infty.
  3. Geometric rate: The distance to the optimal value function shrinks by at least factor γ\gamma on every sweep:

∥Vk+1−V∗∥∞≤γ∥Vk−V∗∥∞≤γk+1∥V0−V∗∥∞\|V_{k+1} - V^*\|_\infty \le \gamma \|V_k - V^*\|_\infty \le \gamma^{k+1} \|V_0 - V^*\|_\infty

Stopping threshold and policy extraction

In practice, sweeps continue until the maximum change across all states falls below a small positive tolerance θ\theta:

Δ=max⁡s∈S∣Vk+1(s)−Vk(s)∣<θ\Delta = \max_{s \in \mathcal{S}} |V_{k+1}(s) - V_k(s)| < \theta

Once convergence is reached, the deterministic optimal policy π∗(s)\pi^*(s) is extracted through a single one-step greedy lookahead:

π∗(s)=arg⁡max⁡a∈A(s)[R(s,a)+γ∑s′∈SP(s′∣s,a)V(s′)]\pi^*(s) = \arg\max_{a \in \mathcal{A}(s)} \left[ \mathcal{R}(s, a) + \gamma \sum_{s' \in \mathcal{S}} \mathcal{P}(s' \mid s, a) V(s') \right]

Worked numerical example

Consider an MDP with 3 states S={s1,s2,s3}\mathcal{S} = \{s_1, s_2, s_3\} and discount factor γ=0.8\gamma = 0.8.

  • State s3s_3 is a terminal absorption state: V(s3)≡0.0V(s_3) \equiv 0.0.
  • Actions available in non-terminal states are A={a1,a2}\mathcal{A} = \{a_1, a_2\}:
    • From s1s_1:
      • Action a1a_1 advances to s2s_2 with r=0.0r = 0.0: Q(s1,a1)=0.0+0.8 V(s2)Q(s_1, a_1) = 0.0 + 0.8\, V(s_2).
      • Action a2a_2 exits immediately to terminal s3s_3 with r=2.0r = 2.0: Q(s1,a2)=2.0+0.8 V(s3)=2.0Q(s_1, a_2) = 2.0 + 0.8\, V(s_3) = 2.0.
    • From s2s_2:
      • Action a1a_1 exits directly to terminal s3s_3 with high reward r=10.0r = 10.0: Q(s2,a1)=10.0+0.8 V(s3)=10.0Q(s_2, a_1) = 10.0 + 0.8\, V(s_3) = 10.0.
      • Action a2a_2 loops back to s1s_1 with minor reward r=1.0r = 1.0: Q(s2,a2)=1.0+0.8 V(s1)Q(s_2, a_2) = 1.0 + 0.8\, V(s_1).

Initialization (k=0k = 0)

V0(s1)=0.0,V0(s2)=0.0,V0(s3)=0.0V_0(s_1) = 0.0, \quad V_0(s_2) = 0.0, \quad V_0(s_3) = 0.0

Sweep 1 (k=1k = 1)

Calculate candidate action values for each state:

  • For s1s_1: Q0(s1,a1)=0.0+0.8×V0(s2)=0.0+0.8(0.0)=0.0Q_0(s_1, a_1) = 0.0 + 0.8 \times V_0(s_2) = 0.0 + 0.8(0.0) = 0.0 Q0(s1,a2)=2.0+0.8×V0(s3)=2.0+0.8(0.0)=2.0Q_0(s_1, a_2) = 2.0 + 0.8 \times V_0(s_3) = 2.0 + 0.8(0.0) = 2.0 V1(s1)=max⁡(0.0,2.0)=2.0(Greedy choice: a2)V_1(s_1) = \max(0.0, 2.0) = 2.0 \quad (\text{Greedy choice: } a_2)
  • For s2s_2: Q0(s2,a1)=10.0+0.8×V0(s3)=10.0+0.8(0.0)=10.0Q_0(s_2, a_1) = 10.0 + 0.8 \times V_0(s_3) = 10.0 + 0.8(0.0) = 10.0 Q0(s2,a2)=1.0+0.8×V0(s1)=1.0+0.8(0.0)=1.0Q_0(s_2, a_2) = 1.0 + 0.8 \times V_0(s_1) = 1.0 + 0.8(0.0) = 1.0 V1(s2)=max⁡(10.0,1.0)=10.0(Greedy choice: a1)V_1(s_2) = \max(10.0, 1.0) = 10.0 \quad (\text{Greedy choice: } a_1)

Max change: Δ1=max⁡(∣2.0−0.0∣,∣10.0−0.0∣)=10.0\Delta_1 = \max(|2.0 - 0.0|, |10.0 - 0.0|) = 10.0.

Sweep 2 (k=2k = 2)

Apply the Bellman optimality backup using updated values V1=[2.0,10.0,0.0]V_1 = [2.0, 10.0, 0.0]:

  • For s1s_1: Q1(s1,a1)=0.0+0.8×V1(s2)=0.0+0.8(10.0)=8.0Q_1(s_1, a_1) = 0.0 + 0.8 \times V_1(s_2) = 0.0 + 0.8(10.0) = 8.0 Q1(s1,a2)=2.0+0.8×V1(s3)=2.0+0.8(0.0)=2.0Q_1(s_1, a_2) = 2.0 + 0.8 \times V_1(s_3) = 2.0 + 0.8(0.0) = 2.0 V2(s1)=max⁡(8.0,2.0)=8.0(Greedy choice flips to a1!)V_2(s_1) = \max(8.0, 2.0) = 8.0 \quad (\text{Greedy choice flips to } a_1!)
  • For s2s_2: Q1(s2,a1)=10.0+0.8×V1(s3)=10.0+0.8(0.0)=10.0Q_1(s_2, a_1) = 10.0 + 0.8 \times V_1(s_3) = 10.0 + 0.8(0.0) = 10.0 Q1(s2,a2)=1.0+0.8×V1(s1)=1.0+0.8(2.0)=1.0+1.6=2.6Q_1(s_2, a_2) = 1.0 + 0.8 \times V_1(s_1) = 1.0 + 0.8(2.0) = 1.0 + 1.6 = 2.6 V2(s2)=max⁡(10.0,2.6)=10.0(Greedy choice: a1)V_2(s_2) = \max(10.0, 2.6) = 10.0 \quad (\text{Greedy choice: } a_1)

Max change: Δ2=max⁡(∣8.0−2.0∣,∣10.0−10.0∣)=6.0\Delta_2 = \max(|8.0 - 2.0|, |10.0 - 10.0|) = 6.0.

The high downstream reward at s2s_2 has backed up into s1s_1. The greedy choice at s1s_1 flipped from the immediate short-term reward of a2a_2 (r=2.0r = 2.0) to the delayed path a1a_1 (Q=8.0Q = 8.0).

Sweep 3 (k=3k = 3)

  • For s1s_1: V3(s1)=max⁡(0.0+0.8(10.0),2.0)=8.0V_3(s_1) = \max(0.0 + 0.8(10.0), 2.0) = 8.0.
  • For s2s_2: V3(s2)=max⁡(10.0,1.0+0.8(8.0))=max⁡(10.0,7.4)=10.0V_3(s_2) = \max(10.0, 1.0 + 0.8(8.0)) = \max(10.0, 7.4) = 10.0.

Max change: Δ3=max⁡(∣8.0−8.0∣,∣10.0−10.0∣)=0.0\Delta_3 = \max(|8.0 - 8.0|, |10.0 - 10.0|) = 0.0.

The values have converged exactly in 3 sweeps:

  • Optimal values: V∗(s1)=8.0,  V∗(s2)=10.0,  V∗(s3)=0.0V^*(s_1) = 8.0, \; V^*(s_2) = 10.0, \; V^*(s_3) = 0.0.
  • Optimal policy: π∗(s1)=a1,  π∗(s2)=a1\pi^*(s_1) = a_1, \; \pi^*(s_2) = a_1.

Code

from typing import Dict, List, Tuple
def value_iteration(    states: List[int],    actions: List[int],    transitions: Dict[Tuple[int, int], List[Tuple[float, int, float]]],    gamma: float = 0.8,    theta: float = 1e-6,) -> Tuple[Dict[int, float], Dict[int, int]]:    """    Computes the optimal value function and policy using Value Iteration.
    Args:        states: List of state identifiers.        actions: List of action identifiers.        transitions: Mapping of (s, a) -> list of (probability, s_next, reward).        gamma: Discount factor in range [0, 1).        theta: Convergence threshold for stopping sweeps.
    Returns:        V: Optimal state values mapping state to value.        policy: Optimal deterministic policy mapping state to best action.    """    V: Dict[int, float] = {s: 0.0 for s in states}
    while True:        delta: float = 0.0        V_new = V.copy()
        for s in states:            q_values: Dict[int, float] = {}            for a in actions:                outcomes = transitions.get((s, a), [])                if outcomes:                    q_values[a] = sum(                        prob * (reward + gamma * V[s_next])                        for prob, s_next, reward in outcomes                    )
            if q_values:                best_value = max(q_values.values())                delta = max(delta, abs(best_value - V[s]))                V_new[s] = best_value
        V = V_new        if delta < theta:            break
    # Extract optimal policy via 1-step greedy lookahead    policy: Dict[int, int] = {}    for s in states:        q_values = {}        for a in actions:            outcomes = transitions.get((s, a), [])            if outcomes:                q_values[a] = sum(                    prob * (reward + gamma * V[s_next])                    for prob, s_next, reward in outcomes                )        if q_values:            policy[s] = max(q_values, key=lambda a: q_values[a])
    return V, policy

# Environment configuration: 3-state MDP matching worked example# States: 0 (s1), 1 (s2), 2 (s3 terminal)# Actions: 0 (a1), 1 (a2)transitions: Dict[Tuple[int, int], List[Tuple[float, int, float]]] = {    (0, 0): [(1.0, 1, 0.0)],   # (s1, a1) -> s2, r=0.0    (0, 1): [(1.0, 2, 2.0)],   # (s1, a2) -> s3, r=2.0    (1, 0): [(1.0, 2, 10.0)],  # (s2, a1) -> s3, r=10.0    (1, 1): [(1.0, 0, 1.0)],   # (s2, a2) -> s1, r=1.0}
states = [0, 1, 2]actions = [0, 1]
optimal_values, optimal_policy = value_iteration(    states=states,    actions=actions,    transitions=transitions,    gamma=0.8,    theta=1e-6,)
print("Optimal Values:", {f"s{s+1}": round(v, 2) for s, v in optimal_values.items()})print("Optimal Policy:", {f"s{s+1}": f"a{a+1}" for s, a in optimal_policy.items()})# -> Optimal Values: {'s1': 8.0, 's2': 10.0, 's3': 0.0}# -> Optimal Policy: {'s1': 'a1', 's2': 'a1'}

Watch Out For

Stopping before value differences are small enough

A common failure mode is assuming that when successive sweep differences fall below ϵ\epsilon (∥Vk+1−Vk∥∞<ϵ\|V_{k+1} - V_k\|_\infty < \epsilon), the current values VkV_k are within ϵ\epsilon of the true optimal values V∗V^*.

Because errors accumulate across future horizons through the discount factor γ\gamma, the true distance to optimality satisfies:

∥Vk−V∗∥∞≤γ1−γ∥Vk−Vk−1∥∞\|V_k - V^*\|_\infty \le \frac{\gamma}{1 - \gamma} \|V_k - V_{k-1}\|_\infty

More dangerously, the policy π\pi derived greedily from VkV_k has an amplified suboptimality bound:

∥Vπ−V∗∥∞≤2γ1−γ∥Vk−V∗∥∞≤2γϵ1−γ\|V^\pi - V^*\|_\infty \le \frac{2\gamma}{1 - \gamma} \|V_k - V^*\|_\infty \le \frac{2\gamma \epsilon}{1 - \gamma}

When γ=0.99\gamma = 0.99, the multiplier 2γ1−γ=1.980.01=198\frac{2\gamma}{1 - \gamma} = \frac{1.98}{0.01} = 198. Stopping with a loose threshold like ϵ=0.05\epsilon = 0.05 can yield an extracted policy that is up to 198×0.05=9.9198 \times 0.05 = 9.9 units of return worse than the true optimal policy.

The Fix: When requiring a policy within target suboptimality tolerance δ\delta, calibrate your stopping threshold θ\theta to:

θ≤δ(1−γ)2γ\theta \le \frac{\delta(1 - \gamma)}{2\gamma}

The Quick Version

  • Value Iteration truncates policy evaluation after a single sweep, directly combining evaluation and greedy improvement into a single Bellman optimality backup.
  • It operates strictly in value space without maintaining or evaluating intermediate policies; an optimal policy is extracted via greedy lookahead once values converge.
  • The Bellman optimality operator T∗\mathcal{T}^* is a γ\gamma-contraction mapping under the infinity norm, guaranteeing geometric convergence to a unique optimal value function V∗V^*.
  • Calibrate the stopping threshold θ\theta against δ(1−γ)2γ\frac{\delta(1 - \gamma)}{2\gamma} to prevent terminating prematurely when γ\gamma is close to 1.