Transition Dynamics
Transition dynamics are the environment's physics written as probabilities: for each state and action, they say how likely every possible next state is.
Why Does This Exist?
Real environments ignore your intentions. A robot issues a drive command and hits slippery ice. A delivery drone banks right and meets a gust. A router forwards a packet and a buffer drops it. If your planner assumes each action lands exactly one next state, the first patch of noise shreds the plan.
Transition dynamics are the fix: for every state and action , they give a probability distribution over next states . With that distribution you can compute expected returns, hedge against bad outcomes, and plan in uncertain worlds. Without it, the core machinery of Markov decision processes, Bellman equations, and value functions cannot even state what "good" means, because every one of them averages over what happens next.
Think of It Like This
Driving on an icy road
You approach an intersection on a winter highway and turn the wheel 30 degrees right. That command is your action ; your position and velocity are your state .
On dry asphalt the outcome is near certain: you enter the right lane. On ice, traction physics decouples intention from outcome, and one command produces a distribution. Say 70 percent of the time the tires bite and you track into the right lane. 15 percent of the time the wheels lose grip and momentum skids you straight into the intersection. 15 percent of the time slush catches the left tires and pulls you onto the shoulder.
You do not control which outcome occurs on any single attempt. The ice, the rubber, and the laws of friction decide. Your only lever is choosing which gamble to take.
Where the analogy stops: a human driver corrects continuously with live feedback. A discrete-time MDP agent commits to one action for the whole step, and the transition kernel samples in one atomic move before the next observation arrives.
How It Actually Works
The kernel: one distribution per state and action
Write for the probability that the environment lands in at time given state and action at time :
This rests on the Markov property: the distribution depends only on the current pair , never on the longer history. That is what makes the object small enough to work with.
The textbook joint form adds the reward into the same distribution: the probability of landing in collecting . You recover the transition kernel by summing the reward away, , and the expected immediate reward by weighting rewards the same way, . One object feeds both planning and evaluation.
Rows must sum to one
Because is a probability distribution, every row sums to exactly 1 and no entry goes negative:
For a finite state space with states, each action owns an transition matrix whose entry is . Every row sums to 1, which makes it a right-stochastic matrix. Follow a fixed policy and the whole system collapses to one matrix, , so a state distribution evolves by plain multiplication, . Probability mass is never created or destroyed, only moved.
Worked example: two steps down an icy corridor
Three states: Safe Road, Icy Patch, Goal (absorbing, so it keeps itself with probability 1). One action, Forward, with matrix:
Row check: , , . Start certain in , so .
After one step, , just the first row. After two steps, multiply again:
So , summing to 1.00, with a 57 percent chance of already holding the goal. These are the numbers in the diagram above.
Now use the same row to price an action. With values , step reward , and discount :
That weighting, probabilities times future values, is exactly what a Bellman update does. Without the dynamics row, the expectation cannot be written down.
Code
The snippet propagates the distribution two steps and prices the action, printing the same numbers the worked example derived.
from typing import List
def step_distribution(mu: List[float], row_of: List[List[float]]) -> List[float]: """One distribution step: mu_{t+1}[j] = sum_i mu_t[i] * P[i][j].""" n = len(row_of) return [sum(mu[i] * row_of[i][j] for i in range(n)) for j in range(n)]
if __name__ == "__main__": P = [[0.10, 0.70, 0.20], [0.20, 0.30, 0.50], [0.00, 0.00, 1.00]] mu0 = [1.0, 0.0, 0.0] mu1 = step_distribution(mu0, P) mu2 = step_distribution(mu1, P) print([round(p, 2) for p in mu1]) # -> [0.1, 0.7, 0.2] print([round(p, 2) for p in mu2]) # -> [0.15, 0.28, 0.57] values = [2.0, 5.0, 10.0] expected_next = sum(p * v for p, v in zip(P[0], values)) q = -1.0 + 0.9 * expected_next print(round(expected_next, 2)) # -> 5.7 print(round(q, 2)) # -> 4.13Watch Out For
Planning on deterministic physics, deploying on noise
The symptom: a planner finds a brilliant trajectory that threads hazards with zero margin (driving along the cliff edge because the planned path technically never touches it), then the hardware version falls apart on the first gust, friction patch, or control delay.
The cause is a simulator or model that treats physics as deterministic, for one successor. The fix: put the noise in before planning, not after. Randomize friction, mass, and latency across rollouts, or plan against the stochastic kernel directly so the optimizer pays for risk. If your sim-to-real gap appears exactly where margins were thinnest, this was it.
Rows that do not sum to one
The symptom: value estimates drift to infinity or decay toward zero for no visible reason. The cause is a dynamics table or learned model whose rows sum to 1.05 (inventing probability mass every Bellman backup) or 0.95 (leaking it).
The fix: assert the invariant where the dynamics are built. Every row must sum to within tolerance and hold no negatives. For a learned model, project successor logits through a softmax so normalization holds by construction.
The Quick Version
- Transition dynamics assign every state-action pair a probability distribution over next states, which is the environment's physics in equation form.
- The Markov property keeps the object small: the next distribution depends only on the current state and action, not the history.
- Every row of every transition matrix sums to exactly 1, so state distributions evolve by multiplication with no mass created or lost.
- Bellman updates weight future values by these probabilities (here giving ); model-based RL plans with the matrix while model-free methods sample from it.
- Deterministic planning on stochastic hardware fails at the thinnest margin, and rows that do not sum to one corrupt every value built on them.