Compute the n-step return at a time step, and the lambda return that geometrically averages all of them.
TD(0) bootstraps after one reward; Monte Carlo waits for the whole episode. Those are the two ends of one dial, and the n-step return is the dial:
Gt:t+n=Rt+1+γRt+2+⋯+γn−1Rt+n+γnV(St+n)
Take real rewards for n steps, then bootstrap. If t + n reaches or passes the terminal step, there is nothing to bootstrap from — the return is simply the full remaining discounted reward, with no value term at all. That truncation is the single most common bug here.
The lambda return refuses to choose an n. It averages every n-step return with geometrically decaying weights (1−λ)λn−1, and gives the entire leftover weight to the full return so the coefficients sum to exactly 1:
Gtλ=(1−λ)∑n=1T−t−1λn−1Gt:t+n+λT−t−1Gt:T
Sanity checks worth remembering: λ=0 collapses to the one-step TD return, and λ=1 collapses to the Monte Carlo return. Everything interesting is in between, and this same geometric average reappears verbatim as GAE in the actor-critic chapter.
The episode has T = len(rewards) steps: rewards[k] is Rk+1, and values[k] is V(Sk) for k in 0..T-1. The episode terminates after rewards[T-1], so V(ST)=0.
def n_step_return(rewards, values, t, n, gamma):
...
def lambda_return(rewards, values, t, gamma, lam):
...
Both return a float.
Two lists of floats plus ints/floats in; a float out, rounded to 4 decimals by the grader.
rewards = [1.0, 2.0, 3.0]
values = [10.0, 20.0, 30.0]
print(round(n_step_return(rewards, values, 0, 1, 0.5), 4))
print(round(n_step_return(rewards, values, 0, 3, 0.5), 4))
Output:
11.0
2.75
The 1-step return is 1.0 + 0.5V(S_1) = 1.0 + 0.520.0 = 11.0. The 3-step return reaches the terminal step, so it bootstraps from nothing: 1.0 + 0.52.0 + 0.253.0 = 2.75.
n_step_return([1.0, 2.0, 3.0], [10.0, 20.0, 30.0], 0, 1, 0.5) and n_step_return([1.0, 2.0, 3.0], [10.0, 20.0, 30.0], 0, 3, 0.5)
11.0 2.75
With n=1 the return takes one real reward then bootstraps: 1.0 + 0.5V(S_1) = 1.0 + 0.520.0 = 11.0. With n=3 the window reaches the terminal step, so there is no state left to bootstrap from and the return is the full discounted reward 1.0 + 0.52.0 + 0.253.0 = 2.75.
1 <= T <= 500, 0 <= t < T, 1 <= nn may exceed the number of remaining steps; in that case the return is the full remaining discounted reward with no bootstrap term.0.0 <= gamma <= 1.0, 0.0 <= lam <= 1.0lambda_return must satisfy: lam = 0 gives the 1-step return, lam = 1 gives the full Monte Carlo return.