MDPs, Bellman Equations & Value Iteration
Derive the Markov property, the Bellman expectation and optimality recursive equations, the Banach fixed-point contraction mapping proof, and zero-dependency implementations in Python and Rust.
Reinforcement Learning (RL) formalizes how an autonomous agent learns to make optimal decisions through trial-and-error interactions with an environment. Unlike supervised learning where target outputs are provided, the agent receives only scalar reward signals feedback.
The mathematical foundation of all reinforcement learning is the Markov Decision Process (MDP) and the recursive decomposition formalized by Richard Bellman in the Bellman Equations.
The Bellman optimality operator is a gamma-contraction, guaranteeing convergence to a unique optimal value function.
1. The Markov Decision Process (MDP) Framework#
An MDP is formally defined by the 5-tuple :
- : Set of all valid environment states.
- : Set of all valid agent actions.
- : State transition probability function .
- : Expected reward function .
- : Discount factor balancing immediate versus delayed future rewards.
The Markov Property#
A state transition process is Markovian if the conditional probability distribution of future states depends solely upon the present state and action, completely independent of past historical trajectories:
The present state constitutes a sufficient statistic of the complete history.
The Cumulative Discounted Return#
The goal of the agent is to maximize the expected cumulative discounted return :
For bounded rewards , the discount factor guarantees that the infinite geometric series converges to a finite maximum bound:
2. Derivation of the Bellman Expectation Equations#
Let define a stochastic policy.
We define two fundamental value functions:
- State-Value Function : Expected return starting from state under policy :
- Action-Value Function : Expected return starting from state , taking action , and thereafter following policy :
Step 1: Decompose Return Recursively
Notice that return can be unrolled into immediate reward plus discounted future return:
Step 2: Expand the Expectation for $V^\pi(s)$
Substitute this recursive relation into the definition of :
Apply the Law of Total Expectation by marginalizing over action and subsequent state :
Step 3: Substitute the Value of Next State $V^\pi(s')$
By definition, . Substituting this yields the Bellman Expectation Equation for :
Step 4: Formulate the Action-Value Equation $Q^\pi(s, a)$
Similarly, for a fixed initial action :
Because :
3. Bellman Optimality Equations & Contraction Mapping#
The optimal state-value function and optimal action-value function represent the maximum return achievable under any policy.
Under an optimal policy, the agent greedily selects the action that maximizes expected future return, replacing the expectation with the operator:
Mathematical Proof: The Contraction Mapping Theorem#
Let denote the Bellman optimality operator mapping value functions :
We prove that is a contraction mapping in the infinity norm .
For any two value functions and :
Using the algebraic inequality :
Since :
4. From-Scratch Implementation: Zero Dependencies#
The following implementations construct an exact Value Iteration Algorithm for a deterministic GridWorld environment from scratch in pure Python and pure Rust.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061from typing import List, Dict, Tuple class GridWorldFromScratch: def __init__(self, size: int = 4, gamma: float = 0.9, tol: float = 1e-4): self.size = size self.gamma = gamma self.tol = tol # Actions: Up, Down, Left, Right self.actions = [(-1, 0), (1, 0), (0, -1), (0, 1)] self.terminal_states = {(0, 0), (size - 1, size - 1)} def is_terminal(self, r: int, c: int) -> bool: return (r, c) in self.terminal_states def step(self, r: int, c: int, action: Tuple[int, int]) -> Tuple[int, int, float]: if self.is_terminal(r, c): return r, c, 0.0 dr, dc = action next_r = max(0, min(self.size - 1, r + dr)) next_c = max(0, min(self.size - 1, c + dc)) reward = -1.0 # Step cost return next_r, next_c, reward def value_iteration(self) -> List[List[float]]: # Initialize value function table with zeros V = [[0.0] * self.size for _ in range(self.size)] while True: delta = 0.0 new_V = [[0.0] * self.size for _ in range(self.size)] for r in range(self.size): for c in range(self.size): if self.is_terminal(r, c): continue # Bellman Optimality: max over all actions [R + gamma * V(s')] action_values = [] for act in self.actions: next_r, next_c, reward = self.step(r, c, act) val = reward + self.gamma * V[next_r][next_c] action_values.append(val) best_val = max(action_values) new_V[r][c] = best_val delta = max(delta, abs(V[r][c] - best_val)) V = new_V if delta < self.tol: break return V if __name__ == "__main__": grid = GridWorldFromScratch(size=4, gamma=0.9) optimal_V = grid.value_iteration() print("Optimal State-Value Function V*(s) for 4x4 GridWorld:") for row in optimal_V: print(" ", [round(v, 2) for v in row])
5. Active Knowledge Checks#
Why does the Contraction Mapping Theorem guarantee that Value Iteration converges to a unique optimal value function V*?
In a Markov Decision Process, what is the defining structural property that distinguishes the Bellman Optimality Equation from the Bellman Expectation Equation?