Module 2. State, Value, and Bellman Equations
Try each exercise first. Expand worked answers or project guidance when needed; their open state is shared between RU/EN.
Download course files (.zip) 382.1 KBThe archive preserves the source folder structure, both languages, and supporting files.
State, observation, and hidden dynamics
Classify each case using the most accurate label:
- A. the observation is already a sufficient Markov state;
- B. the observation is incomplete, so partial observability is the natural model.
-
Only a ball's position is visible, while velocity is hidden and the dynamics have inertia.
-
A chess position includes the side to move, castling rights, and the en-passant status.
-
Pure autoregressive generation exposes the prompt and complete prefix, and the transition only appends the selected token.
-
An agent sees only the last two messages. An earlier tool message identified the open file, but it has been dropped from context; the next response depends on that file.
Write 1-?, 2-?, 3-?, 4-?. Then explain why “state is a compressed history” is a useful construction but not a universal definition of the environment state.
Show answer and solution
Answer: 1-B, 2-A, 3-A, 4-B.
-
Equal positions with different velocities induce different next-position distributions.
-
The complete chess position, including rule-relevant flags, is sufficient for the next legal transition.
-
Under the stated abstraction, the prompt and full prefix are sufficient: the selected token determines the next prefix, while token sampling is represented by the policy.
-
Two complete histories can identify different open files yet share the same last two messages. The omitted observation changes the prediction of the next response, so the short window is insufficient.
In MDP theory, a state is a variable relative to which the Markov property holds. A representation constructed from history may serve as that state, but it can be incomplete, redundant, or different from the physical state of the environment.
What belongs to an MDP
Choose three correct statements about a finite Markov decision process (MDP).
-
The policy is part of and cannot change without changing the MDP.
-
The mean is obtained by averaging over next states with probabilities ; no conditional independence is needed.
-
The Markov property requires state to retain past information that matters for the next transition once the action is known.
-
A text transcript of tool use is automatically a complete state.
-
The same MDP can be paired with different policies.
-
A reward received on entry to a terminal state must be discarded because the terminal value is zero.
Show answer and solution
Answers: 2, 3, and 5.
The law of total expectation gives . Equality of all next-state conditional means would be an additional assumption, but averaging is always valid for integrable rewards. Markov sufficiency concerns future dynamics given the current state and action. A policy belongs to the agent's behavior, so different policies can operate in the same MDP.
Statement 1 conflates agent and environment. Statement 4 fails for an arbitrary text window that may omit relevant earlier observations; hidden state alone does not make the complete history insufficient. Statement 6 confuses reward on the terminal transition with continuation after that transition: the reward remains in , while the terminal continuation value is zero.
Termination versus truncation
For each transition, choose the correct one-step TD target. Let , , and .
-
The task reaches its terminal goal.
-
Data collection stops at an external limit although the process could continue.
-
The task is defined as “finish within 100 steps”; remaining budget is part of state and has been exhausted.
Options:
- A. ;
- B. .
Write 1-?, 2-?, 3-?, and explain why a single legacy done flag is insufficient.
Show answer and solution
Answer: 1-A, 2-B, 3-A.
Using
cases 1 and 3 have , while external truncation in case 2 has . Therefore their targets are , , and .
A single done flag does not reveal whether continuation should be masked or bootstrapped.
V, Q, and advantage
Choose three correct statements that follow from the definitions without changing the MDP.
-
always equals .
-
.
-
means the action is better than the current policy's average action in that state.
-
Arbitrary reward changes leave unchanged.
-
for every policy.
-
Adding a common constant to every in one state, then recomputing , leaves its advantages unchanged.
Select all applicable statements.
Show answer and solution
Answers: 2, 3, and 6.
They follow from
Statement 6 is a useful consequence: both and the policy average shift by , so their difference is unchanged.
Statement 5 is missing policy weights; the correct identity is . An arbitrary reward modification can change advantages throughout the MDP.
Bellman equations and operators
Choose five correct statements.
-
The Bellman expectation equation for a fixed policy is linear in .
-
The optimality operator replaces policy averaging over actions with a maximum.
-
A Bellman equation is itself a complete neural-network training algorithm.
-
For , and are -contractions in the max norm.
-
At , some proper episodic problems remain solvable, but the usual strict-contraction proof no longer applies.
-
A small Bellman residual always implies an equally small value error, independently of .
-
The fixed point of is the value of the fixed policy.
Show answer and solution
Answers: 1, 2, 4, 5, and 7.
The fixed-policy operator is affine (linear only when ), while its fixed-point equation is a linear system in ; the optimality operator takes a maximum; and for both are contractions in . The fixed point of is .
Statement 3 is false because Bellman consistency does not specify data collection, parameterization, or optimization. Statement 5 records the important boundary. Statement 6 is false because
Monte Carlo, TD(0), and multi-step targets
Match each method to its target.
| Method | Target |
|---|---|
| A. Monte Carlo | 1. |
| B. TD(0) | 2. the complete observed |
| C. -step target | 3. several observed rewards followed by |
Write A-?, B-?, C-?.
Then choose the most accurate statement:
-
MC always has lower variance than TD.
-
TD is always more accurate at every data budget.
-
The trade-off depends on the environment, horizon, representation, step size, and data budget.
-
Bootstrapping means resampling episodes with replacement.
Show answer and solution
Matching: A-2, B-1, C-3.
Additional answer: 3.
MC waits for an observed trajectory tail. TD(0) substitutes a current continuation estimate after one transition. An -step target observes several rewards before bootstrapping.
In RL, bootstrapping means updating an estimate from another current estimate. It is not the statistical bootstrap. Bias, variance, and update delay depend on the protocol, so there is no universal ranking.
Why Q-learning is off-policy
Actions are collected by an -greedy policy. Choose the single most accurate statement.
-
SARSA and Q-learning are both off-policy because exploratory actions are random.
-
SARSA uses the actually selected , whereas Q-learning uses ; Q-learning therefore evaluates a greedy target policy from -greedy behavior data.
-
Q-learning becomes off-policy only when a replay buffer is added.
-
SARSA cannot use -greedy exploration.
Show answer and solution
Answer: 2.
SARSA's target follows the next action of the behavior policy. Q-learning's target follows a greedy policy even when behavior remains exploratory. That mismatch defines the off-policy relationship; a replay buffer is neither necessary nor sufficient as a definition.
Group baselines and maximization bias
Choose four correct statements.
-
The group mean reward in canonical GRPO is an exact token-level for every prefix.
-
Group normalization creates a relative signal without a learned critic, while remaining a sample statistic over complete responses.
-
The maximum of noisy unbiased estimates can exhibit positive selection bias.
-
Double Q-learning separates action selection from evaluation across two estimators.
-
Double Q-learning is exactly unbiased under every error dependence structure.
-
Selecting the highest-scoring LLM response under a noisy reward model shares a statistical mechanism with maximization bias, but is not literally tabular Q-learning.
Show answer and solution
Answers: 2, 3, 4, and 6.
Statement 6 is a limited analogy: the selection mechanism is shared, while the algorithms and objects are not identical.
Canonical GRPO uses response-group statistics rather than an exact token-level critic. Maximizing noisy estimates favors positive noise. Double Q-learning weakens that coupling by selecting with one estimator and evaluating with another, but it does not remove every source of error and may underestimate in some settings.
Compute V and A
At state ,
and
Compute and both advantages. Verify the policy-weighted zero-mean identity.
Show answer and solution
Hence
The weighted check is
The unweighted sum is ; it is the policy-weighted average that must vanish.
One Bellman optimality backup
State has two actions.
- deterministically reaches with reward , where .
- reaches with probability , reward , and ; or reaches with probability , reward , and .
Let . Compute both one-step action values, , and the greedy action.
Show answer and solution
For ,
Therefore and the greedy action is .
A one-state Bellman system
There is one non-terminal state and one terminal state. Under a fixed policy, state
- moves to the terminal with probability and reward ;
- returns to with probability and reward .
With , write and solve the Bellman equation for .
Show answer and solution
Thus
A TD update with a terminal mask
Let
Compute the new for
-
an ordinary non-terminal transition;
-
a true terminal transition;
-
an external truncation while the process could continue.
Show answer and solution
The update is .
-
, so .
-
, so .
-
External truncation retains the continuation, so the result is again .
A three-step target
Observed rewards are , , and . Compute
What changes if the third transition truly terminates the task?
Show answer and solution
For a non-terminal end of the window,
At a true terminal, only the continuation is removed:
Standard and Double-Q targets
At the next state,
Let and .
-
Compute a standard Q-learning target using for both selection and evaluation.
-
Compute a Double-Q target that selects with and evaluates with .
-
Explain the difference.
Show answer and solution
Standard Q-learning uses :
Double Q selects the second index with and evaluates that same index with :
The selector regards action 2 as best, while the independent evaluator assigns it a low value. Selection noise is therefore not automatically reused as evaluation noise.
Compute V from Q and form advantages
Implement two functions over arrays of shape (n_states, n_actions).
import numpy as np
def v_from_q(q_values: np.ndarray, policy: np.ndarray) -> np.ndarray:
"""V(s) = sum_a policy[s,a] * q_values[s,a]."""
raise NotImplementedError
def advantage(q_values: np.ndarray, policy: np.ndarray) -> np.ndarray:
"""A(s,a) = Q(s,a) - V(s)."""
raise NotImplementedErrorUse the public checks below to verify shapes and the policy-weighted zero mean; the reference module provides further examples.
Open checks:
Q = np.array([[1.0, 3.0], [0.0, 2.0]])
pi = np.array([[0.5, 0.5], [0.2, 0.8]])
np.testing.assert_allclose(v_from_q(Q, pi), [2.0, 1.6])
np.testing.assert_allclose(advantage(Q, pi), [[-1.0, 1.0], [-1.6, 0.4]])
np.testing.assert_allclose((pi * advantage(Q, pi)).sum(axis=1), 0.0, atol=1e-12)Show answer and solution
import numpy as np
def v_from_q(q_values: np.ndarray, policy: np.ndarray) -> np.ndarray:
q = np.asarray(q_values, dtype=float)
pi = np.asarray(policy, dtype=float)
if q.ndim != 2 or pi.shape != q.shape:
raise ValueError("q_values and policy must have the same 2D shape")
if np.any(pi < 0.0) or not np.allclose(pi.sum(axis=1), 1.0):
raise ValueError("each policy row must be a probability distribution")
return np.sum(pi * q, axis=1)
def advantage(q_values: np.ndarray, policy: np.ndarray) -> np.ndarray:
q = np.asarray(q_values, dtype=float)
return q - v_from_q(q, policy)[:, None]The extra axis turns the state-value vector into a column, allowing one to be subtracted from every action in that state.
Exact policy evaluation
Solve the Bellman linear system over non-terminal states.
def exact_policy_value(
transitions: np.ndarray,
rewards: np.ndarray,
policy: np.ndarray,
gamma: float,
terminals: np.ndarray,
) -> np.ndarray:
"""Return zero for terminal-state values."""
raise NotImplementedErrorConstruct and , then solve on the non-terminal index set .
Open check:
P = np.zeros((2, 1, 2))
R = np.zeros_like(P)
P[0, 0] = [0.5, 0.5]
R[0, 0] = [1.0, 0.0]
P[1, 0, 1] = 1.0
pi = np.ones((2, 1))
terminal = np.array([False, True])
np.testing.assert_allclose(
exact_policy_value(P, R, pi, 0.9, terminal),
[10.0 / 11.0, 0.0],
)Show answer and solution
import numpy as np
def exact_policy_value(transitions, rewards, policy, gamma, terminals):
p = np.asarray(transitions, dtype=float)
r = np.asarray(rewards, dtype=float)
pi = np.asarray(policy, dtype=float)
terminal = np.asarray(terminals, dtype=bool)
if p.ndim != 3 or r.shape != p.shape:
raise ValueError("P and R must have shape (nS, nA, nS)")
if pi.shape != p.shape[:2] or terminal.shape != (p.shape[0],):
raise ValueError("policy or terminal mask has the wrong shape")
p_pi = np.einsum("sa,san->sn", pi, p)
r_pi = np.einsum("sa,san,san->s", pi, p, r)
nonterminal = np.flatnonzero(~terminal)
values = np.zeros(p.shape[0], dtype=float)
if nonterminal.size:
p_nn = p_pi[np.ix_(nonterminal, nonterminal)]
values[nonterminal] = np.linalg.solve(
np.eye(nonterminal.size) - gamma * p_nn,
r_pi[nonterminal],
)
return valuesReward on entry to a terminal is already contained in the predecessor's reward equation. Only continuation after the terminal is zero.
One Bellman optimality sweep
Implement one synchronous value-iteration backup.
def bellman_optimality_sweep(
transitions: np.ndarray,
rewards: np.ndarray,
values: np.ndarray,
gamma: float,
terminals: np.ndarray,
) -> np.ndarray:
"""Return T_* V with zero terminal components."""
raise NotImplementedErrorEvery new state value must be computed from the same old vector values.
Open check for one synchronous sweep:
P = np.zeros((3, 2, 3))
R = np.zeros_like(P)
P[0, 0, 1] = 1.0
P[0, 1, 2] = 1.0
R[0, 0, 1] = 1.0
R[0, 1, 2] = 2.0
P[1, :, 1] = 1.0
P[2, :, 2] = 1.0
V = np.array([0.0, 3.0, 1.0])
out = bellman_optimality_sweep(P, R, V, 0.9, np.zeros(3, dtype=bool))
assert abs(out[0] - 3.7) < 1e-12Show answer and solution
import numpy as np
def bellman_optimality_sweep(transitions, rewards, values, gamma, terminals):
p = np.asarray(transitions, dtype=float)
r = np.asarray(rewards, dtype=float)
v = np.asarray(values, dtype=float)
terminal = np.asarray(terminals, dtype=bool)
continuation = v.copy()
continuation[terminal] = 0.0
q = np.sum(
p * (r + gamma * continuation[None, None, :]),
axis=2,
)
updated = np.max(q, axis=1)
updated[terminal] = 0.0
return updatedRepeated application with a stopping rule gives value iteration. The notebook implements that complete experiment and stores the full propagation trace.
TD targets with explicit termination
Implement one-step and -step targets. An external truncated=True flag must not mask the continuation by itself.
def td_target(reward, next_value, gamma, *, terminated, truncated=False):
raise NotImplementedError
def n_step_target(rewards, bootstrap_value, gamma, *, terminated_at_end):
raise NotImplementedErrorThe numerical checks are , , for ordinary/terminal/truncated one-step transitions and , for the two three-step cases in Task B5.
Open checks:
assert td_target(1, 2, 0.9, terminated=False) == 2.8
assert td_target(1, 2, 0.9, terminated=True) == 1.0
assert td_target(1, 2, 0.9, terminated=False, truncated=True) == 2.8
assert abs(n_step_target([1, 2, 3], 4, 0.5, terminated_at_end=False) - 3.25) < 1e-12
assert abs(n_step_target([1, 2, 3], 4, 0.5, terminated_at_end=True) - 2.75) < 1e-12Show answer and solution
import math
def td_target(reward, next_value, gamma, *, terminated, truncated=False):
if not math.isfinite(reward) or not math.isfinite(gamma):
raise ValueError("reward and gamma must be finite")
if not 0.0 <= gamma <= 1.0:
raise ValueError("gamma must be in [0, 1]")
if not isinstance(terminated, bool) or not isinstance(truncated, bool):
raise TypeError("flags must be boolean")
if terminated:
return float(reward)
if not math.isfinite(next_value):
raise ValueError("next_value must be finite for a non-terminal target")
return float(reward + gamma * next_value)
def n_step_target(rewards, bootstrap_value, gamma, *, terminated_at_end):
if not math.isfinite(gamma) or not 0.0 <= gamma <= 1.0:
raise ValueError("gamma must be finite and in [0, 1]")
if not isinstance(terminated_at_end, bool):
raise TypeError("terminated_at_end must be boolean")
total = 0.0
discount = 1.0
for reward in rewards:
reward = float(reward)
if not math.isfinite(reward):
raise ValueError("rewards must be finite")
total += discount * reward
discount *= gamma
if terminated_at_end:
return total
if not math.isfinite(bootstrap_value):
raise ValueError("bootstrap_value must be finite for a non-terminal target")
return total + discount * float(bootstrap_value)truncated is retained in the interface to make the stopping reason visible. The bootstrap mask is controlled by task termination.
SARSA and Q-learning targets
Implement the local targets for a known next-state action-value vector.
def q_learning_target(reward, next_q_values, gamma, *, terminated):
raise NotImplementedError
def sarsa_target(reward, next_q_values, next_action, gamma, *, terminated):
raise NotImplementedErrorQ-learning uses a maximum; SARSA uses the action actually selected by the behavior policy. Neither should bootstrap at a true terminal.
Open checks:
q_next = np.array([1.0, 4.0, 3.0])
assert q_learning_target(0.5, q_next, 0.9, terminated=False) == 4.1
assert sarsa_target(0.5, q_next, 2, 0.9, terminated=False) == 3.2
assert q_learning_target(1.0, np.array([]), 0.9, terminated=True) == 1.0
assert sarsa_target(1.0, np.array([]), 99, 0.9, terminated=True) == 1.0Show answer and solution
import numpy as np
def q_learning_target(reward, next_q_values, gamma, *, terminated):
if terminated:
return float(reward)
q_next = np.asarray(next_q_values, dtype=float)
if q_next.ndim != 1 or q_next.size == 0:
raise ValueError("next_q_values must be a non-empty vector")
return float(reward + gamma * np.max(q_next))
def sarsa_target(reward, next_q_values, next_action, gamma, *, terminated):
if terminated:
return float(reward)
q_next = np.asarray(next_q_values, dtype=float)
if q_next.ndim != 1 or not 0 <= next_action < q_next.size:
raise ValueError("invalid next action")
return float(reward + gamma * q_next[next_action])The full SARSA loop must choose next_action using the same behavior policy that will act on the next transition.
Selection and evaluation in Double Q-learning
Implement a Double-Q target. One estimator selects the action index; the other evaluates that selected index.
def double_q_target(
reward: float,
selector_q: np.ndarray,
evaluator_q: np.ndarray,
gamma: float,
*,
terminated: bool,
) -> float:
raise NotImplementedErrorFor selector=[1,4,3], evaluator=[10,2,8], , and , the non-terminal result must be .
Open checks:
qa = np.array([1.0, 4.0, 3.0])
qb = np.array([10.0, 2.0, 8.0])
assert double_q_target(0.5, qa, qb, 0.9, terminated=False) == 2.3
assert double_q_target(0.5, qa, qb, 0.9, terminated=True) == 0.5Show answer and solution
import numpy as np
def double_q_target(reward, selector_q, evaluator_q, gamma, *, terminated):
if terminated:
return float(reward)
selector = np.asarray(selector_q, dtype=float)
evaluator = np.asarray(evaluator_q, dtype=float)
if selector.ndim != 1 or evaluator.shape != selector.shape or selector.size == 0:
raise ValueError("Q vectors must be non-empty and have the same shape")
selected = int(np.argmax(selector))
return float(reward + gamma * evaluator[selected])Taking np.max(evaluator) would let the second table choose a different action. Double Q-learning evaluates the action selected by the first table.