Skip to content

Bridges: DSA to LLMs

Topological sort and DAGs to backpropagation

Ordering a computation graph to differentiate it

A neural network is a computational DAG: the forward pass topologically sorts it, and backprop replays that very sort in reverse to hand every node its gradient - just in time.

Two lessons you have already met turn out to be the same lesson. In Topological sort, MST, and Bellman-Ford you learned to topologically sort a DAG - order a directed acyclic graph so every edge points forward, so nothing is processed before its dependencies. In Backpropagation you built backpropagation - one reverse sweep that hands every weight its gradient. Here is the punchline that makes training a network feel inevitable rather than magical: backprop is topological sort run in reverse over a computational graph. The forward pass is a topological sort; the backward pass is its reverse. That is the whole engine behind every model you have studied.

Training is a graph algorithm

A network - even a trillion-parameter one - is a directed acyclic graph of tiny operations: one multiply, one add, one square, each a node. Running it forward means evaluating each node only once its inputs exist - that is exactly a topological sort. Backprop then walks that same order backward, so every node's gradient is finished before the nodes feeding it ever ask for it. No new idea is needed: it is a reverse topological sweep with a little arithmetic at each stop.

A network is a DAG of operations

Before you can differentiate a computation, you rewrite it as a computational graph: break the whole thing into elementary ops, each a node whose edges are its data dependencies. An edge means “ is computed from ” - so must come first. Because there are no cycles, a topological order always exists: line the nodes up so every edge points forward, and you can evaluate left to right without ever meeting an unfilled input. Our toy expression takes three inputs and, crucially, reuses one intermediate value:

The expression, node by node

Node is a shared node: it fans out to both and . Each node's local derivative (how its output reacts to a wiggle of one input) is elementary:

Because influences through two paths, its gradient is a sum over those paths - the multivariable chain rule:

Forward is topological order; backward reverses it

Press ▶ Forward to fill every node's value in topological order (inputs first, loss last), then ◀ Backward to watch the gradient flow back in reverse topological order - each edge multiplying in its local derivative as it goes. Or walk it with Next. Watch node : on the way back it collects a gradient from , then a second one from , and the two accumulate. Click any node to inspect its local derivatives and the chain rule that assembles its gradient. Drag a slider and everything recomputes live.

Forward = topo order. Backward = reverse topo. Step or play the two passes, or click a node to inspect its local derivative and the chain rule that assembles its gradient. Drag the sliders and every number recomputes live.
value (forward)gradient (backward)× local derivative on each edge
Forward order · topological - a node lights once its inputs are ready
abcepqL
Backward order · reverse topological - a node lights once it holds a gradient
Lpqecab
Forward pass

Forward pass, in topological order. The inputs a = 2, b = 3, c = 1 have in-degree 0 - no dependencies - so they are known first.

Click any node to inspect its local derivative and how the chain rule assembles its gradient.
loss L13
∂L / ∂e2
∂L / ∂c7
∂L / ∂a6
∂L / ∂b4

Gradients accumulate at shared nodes

Watch node . It feeds two consumers, so two gradients flow back into it - and you add them: . That is the multivariable chain rule in action: when one value influences the loss through several paths, its total gradient is the sum over paths. In autodiff code this is a single += at every fan-out. Overwrite instead of add, and any network with a reused activation - which is all of them - trains wrong.

The same idea, in code

This is what a framework does automatically, but by hand it is a dozen lines with the shape you just watched: forward in topological order, then backward in reverse, gradients starting at zero and accumulating with +=.

# --- forward: evaluate in topological order (inputs first, loss last) ---
a, b, c = 2.0, 3.0, 1.0
e = a * b            # 6.0   shared node: feeds BOTH p and q
p = e + c            # 7.0
q = e * c            # 6.0
L = p + q            # 13.0  the loss (graph sink)

# --- backward: reverse topological order, gradients accumulate from 0 ---
gL = 1.0              # seed dL/dL
gp = gL * 1            # + node copies the gradient through
gq = gL * 1
ge  = gp * 1           # from p = e + c   (local d/de = 1)
gc  = gp * 1
ge += gq * c          # from q = e * c   ACCUMULATE at shared e
gc += gq * e
ga  = ge * b          # from e = a * b   (times swaps the other input)
gb  = ge * a
# ge = 2.0, gc = 7.0, ga = 6.0, gb = 4.0

Two invariants keep the sweep correct

Order. A node's gradient can only be computed after every node it feeds already has one - that is precisely why the pass is reverse topological, not merely right-to-left by screen position. Accumulation. Initialize each gradient to and += every contribution, because a value reused times receives gradients. Frameworks enforce both automatically: they record the graph as you compute the forward pass, then replay it backward.

Check yourself

Backprop processes the computational graph's nodes in which order?

A node whose output feeds two later nodes ends up with a gradient equal to:

Recall: how are the forward and backward passes related to topological sort?

Try to state it, then check.

Lock it in

  • A neural network is a computational DAG of elementary ops; the forward pass evaluates it in topological order (inputs first, loss last).
  • Backprop is that same topological order run in reverse, so every node's gradient is finished before the nodes feeding it are visited.
  • At a shared (fan-out) node the multivariable chain rule sums the gradients from every path - a single +=; overwrite instead and any reused activation trains wrong.
  • Two invariants keep it correct: reverse-topological order and gradient accumulation from zero - exactly what autodiff frameworks record and replay.

Primary source

3Blue1Brown's Backpropagation calculus builds the reverse chain-rule intuition frame by frame - the “backward sweep” half of this lesson. For the “forward sweep is a topological sort” half, see MIT 6.006 - Introduction to Algorithms (Spring 2020) and its treatment of DAGs and topological sort.

Ask your teacher

This is the deepest bridge in the course: backprop is topological sort run in reverse over the computational graph. Training a neural network is a graph algorithm - a forward topological sweep to fill values, then one reverse sweep that hands every parameter its gradient, summed wherever a value fanned out. Ask me how frameworks build and record that graph automatically, why reverse mode beats forward mode when there is one loss and millions of weights, or how a very long dependency chain is exactly where vanishing and exploding gradients come from.