1. Background Knowledge
In reinforcement learning, the discounted return G is defined as the sum of future rewards, each scaled by a discount factor γt where 0≤γ<1. This discounting ensures that G remains finite even in infinite-horizon tasks and reflects the principle that immediate rewards are more valuable than distant ones. The return is a random variable because the rewards Rt are stochastic.
A fundamental property of probability theory states that for independent random variables, the variance of their sum equals the sum of their variances. Specifically, if X and Y are independent, then Var(aX+bY)=a2Var(X)+b2Var(Y). Note that the scaling factor is squared. This is distinct from the mean, where E[aX+bY]=aE[X]+bE[Y]. The mean μ does not appear in the variance calculation because variance measures spread around the mean, not the location of the mean itself.
Therefore, for the discounted return G=∑t=0T−1γtRt with independent rewards, the variance decomposes as:
Var(G)=t=0∑T−1γ2tVar(Rt)
This formula is central to understanding risk in RL: even if the expected return is high, a high variance indicates unpredictable outcomes, which is critical for risk-sensitive policy optimization.
2. Algorithm Approach
The problem reduces to a straightforward weighted sum computation. You are given an array of variances var and a scalar gamma. The goal is to compute:
t=0∑T−1(γ2)t⋅var[t]
This is a geometric-series-like weighted sum where the weight for each term is γ2t. The most direct approach is to iterate through the var array, maintaining a running power of γ2, and accumulating the product with each variance value. No complex data structures or dynamic programming are needed; this is a linear scan with constant extra state.
3. Step-by-Step Strategy
- Initialize a variable total_variance to 0.0 and a variable power to 1.0. The power variable will track γ2t.
- Iterate over each element v in the var array with index t.
- Accumulate: Add power * v to total_variance.
- Update power: Multiply power by γ2 for the next iteration. This avoids recalculating γ2t from scratch each time, which would be less efficient and more prone to floating-point drift.
- Return total_variance as a float.
Pseudocode:
def return_variance(var, gamma):
total = 0.0
power = 1.0
gamma_sq = gamma * gamma
for v in var:
total += power * v
power *= gamma_sq
return total
4. Common Pitfalls
- Forgetting to square gamma: The variance formula uses γ2t, not γt. Using γt will give an incorrect result. Always square the discount factor when dealing with variance.
- Using mu unnecessarily: The problem explicitly states that mu is not needed. Including it in the calculation will lead to errors. Variance is independent of the mean.
- Floating-point precision: For large T and γ close to 1, γ2t may underflow to 0.0 in floating-point arithmetic. This is generally acceptable for practical purposes, but be aware that very small terms may be lost.
- Off-by-one errors: Ensure you iterate over all elements in var. The sum is from t=0 to T−1, where T=len(var).
- Negative gamma: While γ is typically in [0,1), if negative values are allowed, γ2 is still positive, so the formula holds. However, standard RL assumes 0≤γ<1.
5. Time & Space Complexity
- Time Complexity: O(T), where T is the length of the var array. Each element is visited exactly once, and each iteration performs a constant number of arithmetic operations.
- Space Complexity: O(1) extra space. Only a few scalar variables (total, power, gamma_sq) are used, regardless of the input size. The input array is not modified.