PIXELBANKv9.1.0
Menu

n-step Returns and the Lambda Return

Problem Statement

Compute the n-step return at a time step, and the lambda return that geometrically averages all of them.

Background

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)G_{t:t+n} = R_{t+1} + \gamma R_{t+2} + \cdots + \gamma^{n-1} R_{t+n} + \gamma^{n} V(S_{t+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(1-\lambda)\lambda^{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:TG_t^{\lambda} = (1-\lambda) \sum_{n=1}^{T-t-1} \lambda^{n-1} G_{t:t+n} \; + \; \lambda^{T-t-1} G_{t:T}

Sanity checks worth remembering: λ=0\lambda = 0 collapses to the one-step TD return, and λ=1\lambda = 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.

Your Task

The episode has T = len(rewards) steps: rewards[k] is Rk+1R_{k+1}, and values[k] is V(Sk)V(S_k) for k in 0..T-1. The episode terminates after rewards[T-1], so V(ST)=0V(S_T) = 0.

def n_step_return(rewards, values, t, n, gamma):
    ...

def lambda_return(rewards, values, t, gamma, lam):
    ...

Both return a float.

Input / Output Format

Two lists of floats plus ints/floats in; a float out, rounded to 4 decimals by the grader.

Sample

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.

Example:

Input:
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)
Output:
11.0
2.75
Reasoning:

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.

Constraints:

  • 1 <= T <= 500, 0 <= t < T, 1 <= n
  • n 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.0
  • lambda_return must satisfy: lam = 0 gives the 1-step return, lam = 1 gives the full Monte Carlo return.
  • Do not round inside the functions.
solution.py

Test Results

0/0
Run code to see test results.
n-step Returns and the Lambda Return - Hard | PixelBank