Asynchronous Dynamic Programming
Update one state at a time in place, reusing fresh values at once. The good news spreads in the same pass instead of waiting for the next full sweep.
Why Does This Exist?
Classic dynamic programming sweeps every state with two buffers. Read from , write to , repeat. That is clean but wasteful. Rare states get equal work, memory doubles, and a goal reward needs one full sweep per hop to walk backward.
Async DP drops the lockstep. Keep one array and back up whichever state you pick:
Here holds transition probabilities, the reward, and the discount. Fresh writes are visible at once, so one well ordered pass can push a reward across many hops. This page covers the in place trick and ordering. Neighbors cover the full theory in dynamic programming, the optimality sweep in value iteration, and the evaluate improve loop in policy iteration.
You need Bellman equations first: values defined in terms of successor values.
Think of It Like This
Spot cleaning a house versus a locked whole house pass
A strict cleaner must finish rooms 1 to 50 in order before starting pass two, even when guests keep dirtying the entry. Mud waits a full pass before the hallway notices the clean entry.
Spot cleaning fixes the entry the moment it gets dirty, and the next room benefits right away. High traffic rooms get extra visits, spare rooms get skipped, and one bucket set stays in use.
Where it stops: cleaning one room never dirties another, but Bellman backups couple states. Updating changes the target for every predecessor , which is why order matters here and not in the house.
How It Actually Works
Sync keeps frozen while it builds . Async overwrites in place. Pick then in a chain and the second backup already sees the first result.
Three orderings cover most uses. Cyclic sweeps walk a fixed order but write in place. Prioritized sweeping queues states by Bellman error and processes predecessors of big movers first. Real time DP backs up only states the agent actually visits, ignoring unreachable branches.
Convergence still holds for discounted tasks when every state keeps getting picked. The Bellman operator contracts with factor , so arbitrary orders with infinite visits reach .
Worked example
Chain with one action, , start , terminal . Rewards: from , from . True values are:
Sync sweep one reads and writes , . The start learns nothing because it read the stale . Sweep two then gives . Cost: sweeps, backups.
Async in reverse order writes in place. First , memory becomes . Then . Cost: backups in one pass, exact.
Code
Minimal replay of the chain above.
from typing import List
def backup(reward: float, gamma: float, v_next: float) -> float: """One deterministic Bellman backup: r plus discounted next value.""" return reward + gamma * v_next
gamma = 0.90v = [0.0, 0.0, 0.0]v[1] = backup(10.0, gamma, v[2])print(v) # -> [0.0, 10.0, 0.0]v[0] = backup(0.0, gamma, v[1])print(v) # -> [9.0, 10.0, 0.0]The prints show the in place cascade: then .
Watch Out For
Starving states you stopped visiting
Async converges only when each reachable state keeps getting updates. A greedy rollout plus trajectory backups can loop on one path while a shortcut keeps stale zeros.
Symptom: Bellman error looks zero on visited states yet the policy sticks in a loop. Fix: mix epsilon greedy visits or schedule background sweeps so no reachable state waits forever.
The Quick Version
- Sync DP reads one buffer and writes another across all states each sweep.
- Async DP writes in place to one buffer, so fresh values feed the next backup at once.
- Order by cycle, by Bellman error queue, or by live trajectory depending on the task.
- The 3-state chain with hits in 2 backups async versus 4 sync.
- Keep visiting every reachable state or the guarantee lapses.