Eligibility Traces
One reward should credit the whole trail that led to it, with recent steps getting more credit than old ones. Eligibility traces are that fading memory.
Why Does This Exist?
A reward often arrives long after the choices that caused it. One-step temporal-difference learning updates only the last state, so credit crawls back one step per episode. Monte Carlo waits until the episode ends and then credits everything, which fails when episodes never end and jumps around a lot.
Eligibility traces split the difference. Each state keeps a trace that marks how recently and how often it was visited. When the one-step error arrives, every state learns at once in proportion to its trace. You get multi-step credit on every step without waiting.
Think of It Like This
Footprints filling with gold dust
You walk across a beach and each step leaves a print. Wind softens old prints while fresh ones stay sharp. Stepping twice in the same spot digs it deeper.
When you find a coin at the end, someone sprinkles gold dust over the whole trail. Deep fresh prints catch a lot, faint old prints catch a little, untouched sand catches nothing. The dusting happens once, right when the coin appears.
Where it stops: beach prints fade unevenly. Traces fade by exactly each step, where discounts the future and sets how far credit reaches.
How It Actually Works
Start each episode with for all states . On step in state , decay every trace by and bump the visited state. Two bump rules are standard.
Accumulating traces add one on every visit:
Replacing traces reset the visited state to one, which stops loops from piling up:
The one-step error uses reward , discount , and current value estimates :
Then every state moves a little along the error, scaled by step size and its trace:
Setting keeps credit for one step and recovers one-step TD. Setting spreads credit across the whole episode like Monte Carlo but still updates online. Values in between blend the two.
Worked example
Use , , so decay is , with and all values starting at 0. The agent walks to to to , then earns 10 and terminates.
- After visiting : .
- After : , .
- After revisiting : accumulating gives , replacing gives . For : .
- Final step to termination with : decay once more. Accumulating ends at , , . Replacing ends at with the other two the same.
The final error is , so each update is :
- Accumulating: , , .
- Replacing: , the other two match.
One reward updated three states at once. Revisiting earned extra credit under accumulating traces and capped credit under replacing traces. The forward and backward views prove this backward broadcast matches the forward lambda return offline.
Code
Three lines carry the method: decay all traces, bump the visited state, then scale one error by every trace.
def step_traces(z: dict, state: str, decay: float, mode: str) -> dict: for s in z: # fade every trace by gamma times lambda z[s] *= decay z[state] = z[state] + 1.0 if mode == "accumulating" else 1.0 return z
z = step_traces({"A": 1.5184, "B": 0.72, "C": 0.0}, "C", 0.72, "accumulating")print(f"{z['A']:.4f} {z['B']:.4f} {z['C']:.4f}")# -> 1.0932 0.5184 1.0000The printout is the final trace row from the worked example. Multiply by and you get the value updates above.
Watch Out For
Letting accumulating traces blow up in loops
Each revisit adds another 1.0 before decay removes it. In a task with tight cycles and near 1, traces climb past 5 or 10 and sit there. The next nonzero error then hits like a huge step size and values swing wildly.
Use replacing traces when states recur often, or keep clearly below 1 so the geometric bound stays small. Zero all traces at each terminal state.
Carrying traces across episode boundaries
Traces are episode memory, not lifetime memory. If you forget to reset to zero at termination, the first states of the next episode inherit credit from the last episode's reward. Values leak across unrelated episodes and early states drift.
Reset unconditionally on done. If your loop has timeout truncations as well as true terminations, reset on both unless your algorithm treats them differently on purpose.
The Quick Version
- Eligibility traces store recency and frequency for every state in a vector .
- Each step decays traces by and bumps the visited state.
- One TD error updates all states through .
- Accumulating traces add on revisits while replacing traces reset to 1.0.
- Lambda 0 is one-step TD and lambda 1 behaves like Monte Carlo, done online.