Mathematical Foundations

III.10 · Calculus

How does a program compute exact derivatives of itself?

Break a computation into elementary operations, evaluate it forward, then send derivatives backward along every edge. When one input reaches the output along two paths, its contributions add.

Differentiate a computation, one edge at a time

Differentiation mode

Computational graph of z = (x + y)·x with inputs x = 2, y = 3. u = x + y = 5; z = u × x = 10. Edges carry local derivatives: ∂u/∂x=1; ∂u/∂y=1; ∂z/∂u=2; ∂z/∂x=5. One backward pass gives every ∂z/∂input: ∂z/∂x = 7, ∂z/∂y = 2. x reaches z along two paths (through u and directly); their contributions add to 2x + y.

Result

One backward pass gives every ∂z/∂input: ∂z/∂x = 7, ∂z/∂y = 2. x reaches z along two paths (through u and directly); their contributions add to 2x + y.

∂z∂x=7,∂z∂y=2\frac{\partial z}{\partial x}=7,\quad \frac{\partial z}{\partial y}=2

One backward pass gives every ∂z/∂input: ∂z/∂x = 7, ∂z/∂y = 2. x reaches z along two paths (through u and directly); their contributions add to 2x + y.

Input x
2
Input y
3
Output z
10
Reverse mode: adjoint of x
7
Contributions reaching x
2 via u + 5 via z
Analytic formula for ∂z/∂x
7
Reverse mode: adjoint of y
2
Analytic formula for ∂z/∂y
2
Central difference, h = 10⁻⁶ (numerical evidence)
7.000000

Exact values use =; binary64 approximations use ≈. Derivatives come from the graph; the analytic and finite-difference rows are independent checks.

z=(x+y) xz=(x+y)\,x
vˉ=∑edges v→wwˉ ∂w∂v,zˉ=1\bar v=\sum_{\text{edges } v\to w}\bar w\,\frac{\partial w}{\partial v},\qquad \bar{z}=1
Cost of a full gradient/Jacobian: forward mode needs one pass per INPUT, reverse mode one pass per OUTPUT
inputs noutputs mforward passesreverse passes
2121

from −4 to 4, up to 2 decimal places

from −4 to 4, up to 2 decimal places

Edit the inputs, choose reverse or forward mode, and step through the trace. Every value, local derivative, contribution and adjoint on the graph comes from evaluating the graph itself.

The opening graph computes z=(x+y) xz=(x+y)\,x through an intermediate node u=x+yu=x+y. In the trace controls under the graph, press Reset and then Next: u=5u=5, then z=10z=10. Keep stepping backward through zz: it sends 1×2=21\times2=2 to uu and 1×5=51\times5=5 directly to xx. Through uu, another 2×1=22\times1=2 reaches xx. The adjoint of xx is the sum, 5+2=7=2x+y5+2=7=2x+y, and the adjoint of yy is 2=x2=x.

Intuition: derivatives travel along edges

A program is a chain of small operations whose derivatives are known: ∂(a+b)/∂a=1\partial(a+b)/\partial a=1, ∂(ab)/∂a=b\partial(ab)/\partial a=b, ∂sin⁡a/∂a=cos⁡a\partial\sin a/\partial a=\cos a. Record the operations as a directed acyclic graph: nodes are values, edges say which values feed which operation. Each edge carries its local derivative. The chain rule (III.6) says a derivative along a path is the product of its edge derivatives, and the total derivative is the sum over paths. Automatic differentiation organises that sum so it is computed once, efficiently.

Definition

A computational graph lists nodes v1,…,vNv_1,\dots,v_N in a topological order: inputs first, every operation after its arguments. Each edge v→wv\to w carries the local partial derivative ∂w/∂v\partial w/\partial v, evaluated at the forward values.

  • Forward mode fixes one input xkx_k and propagates tangents w˙=∑v→w∂w∂v v˙\dot w=\sum_{v\to w}\frac{\partial w}{\partial v}\,\dot v with x˙k=1\dot x_k=1.
  • Reverse mode fixes one output yy and propagates adjoints backward:
vˉ=∑edges v→wwˉ ∂w∂v,yˉ=1.\bar v=\sum_{\text{edges }v\to w}\bar w\,\frac{\partial w}{\partial v},\qquad \bar y=1 .

After the reverse pass, xˉk=∂y/∂xk\bar x_k=\partial y/\partial x_k for every input at once.

Mechanics: what the explorer computes

The graph engine evaluates nodes in a deterministic topological order (ties broken by declaration order). Values stay exact rationals while every operation is rational; sin⁡\sin switches to binary64. Each edge stores its local derivative. Reverse mode visits nodes in reverse order and adds each contribution wˉ⋅∂w/∂v\bar w\cdot\partial w/\partial v into vˉ\bar v; forward mode adds ∂w/∂v⋅v˙\partial w/\partial v\cdot\dot v into w˙\dot w. The graph view draws exactly the selected immutable trace frame: which values exist yet, which adjoints or tangents have been accumulated, and what each active edge sends.

Two checks are independent of the graph engine: a hand-written analytic derivative for each example, and a central finite difference with step 10−610^{-6}, which is numerical evidence with its own error.

Derivation: why contributions add

For z=u xz=u\,x with u=x+yu=x+y, the variable xx influences zz directly and through uu. By the multivariable chain rule,

∂z∂x=∂z∂u∂u∂x+∂z∂x∣u=x⋅1+u.\begin{aligned}\frac{\partial z}{\partial x}&=\frac{\partial z}{\partial u}\frac{\partial u}{\partial x}+\frac{\partial z}{\partial x}\Big|_{u}\\ &=x\cdot1+u .\end{aligned}

With u=x+yu=x+y this is 2x+y2x+y, and ∂z/∂y=∂z∂u∂u∂y=x\partial z/\partial y=\frac{\partial z}{\partial u}\frac{\partial u}{\partial y}=x. Reverse mode computes each product once and adds them where paths meet; a node that uses the same input twice, such as q=x⋅xq=x\cdot x, has two edges and receives two contributions, x+x=2xx+x=2x.

Worked example

At x=2x=2, y=3y=3: forward, u=5u=5 and z=10z=10. Local derivatives: ∂u/∂x=∂u/∂y=1\partial u/\partial x=\partial u/\partial y=1, ∂z/∂u=x=2\partial z/\partial u=x=2, ∂z/∂x=u=5\partial z/\partial x=u=5. Backward from zˉ=1\bar z=1: uˉ=2\bar u=2; the direct edge sends 55 to xx; through uu, xˉ\bar x gains 22 and yˉ\bar y gains 22. So ∂z/∂x=7\partial z/\partial x=7 and ∂z/∂y=2\partial z/\partial y=2, matching 2x+y=72x+y=7 and x=2x=2.

Replay z = (x + y)·x at x = 2, y = 3

Computational graph of z = (x + y)·x with inputs x = 2, y = 3. u = x + y = 5; z = u × x = 10. Edges carry local derivatives: ∂u/∂x=1; ∂u/∂y=1; ∂z/∂u=2; ∂z/∂x=5. One backward pass gives every ∂z/∂input: ∂z/∂x = 7, ∂z/∂y = 2. x reaches z along two paths (through u and directly); their contributions add to 2x + y.

Inputs

Set x = 2, y = 3.

x=2,y=3x=2,\quad y=3
Replay the forward pass and the reverse accumulation for z = (x + y)·x at x = 2, y = 3.

Forward or reverse: shapes and cost

Choose 3 inputs → 1 loss: one reverse pass returns all three partial derivatives, while forward mode needs one pass per input (select each seed in turn). Choose 1 input → 3 outputs: now one forward pass returns all three derivatives, while reverse mode needs one pass per output. In general, for F:Rn→RmF:\mathbb R^n\to\mathbb R^m, forward mode builds the Jacobian one column per pass and reverse mode one row per pass. Training a model differentiates one scalar loss with respect to many parameters (m=1m=1, nn huge), which is why backpropagation is reverse mode.

Not symbolic, not finite differences

Automatic differentiation never builds a formula for the derivative: it multiplies and adds numbers along the executed operations, so its cost is a small multiple of evaluating the function. Symbolic differentiation manipulates expressions and can grow them enormously. A finite difference perturbs the input and divides by a step hh; it has truncation and rounding error (III.14) and needs one extra evaluation per input direction. AD derivatives are exact up to the arithmetic of the operations themselves.

When a node is undefined — try x / (x − y) at x = y — every value and derivative downstream is undefined too. The stage reports it and does not show a finite difference across the singular point, because such a quotient measures nothing about a derivative there.

Executable reference code

The pedagogical reference implements forward mode with dual numbers and reverse mode with an explicit tape, independently of the browser engine, and checks both against 2x+y2x+y and xx. The NumPy version vectorises a scalar loss over many parameters and compares a reverse-mode gradient with central differences.

code/python/calculus_autodiff.py
"""Forward mode with dual numbers and reverse mode with a tape, written independently (III.10).

z = (x + y) * x at x = 2, y = 3: dz/dx = 2x + y = 7 and dz/dy = x = 2.
"""


class Dual:
    """a + b*eps with eps**2 = 0: b carries the derivative with respect to the seeded input."""
    def __init__(self, a, b=0.0):
        self.a, self.b = a, b

    def __add__(self, o):
        o = o if isinstance(o, Dual) else Dual(o)
        return Dual(self.a + o.a, self.b + o.b)

    def __mul__(self, o):
        o = o if isinstance(o, Dual) else Dual(o)
        return Dual(self.a * o.a, self.a * o.b + self.b * o.a)


def z_of(x, y):
    u = x + y
    return u * x


# Forward mode: one pass per input.
assert z_of(Dual(2, 1), Dual(3, 0)).b == 7
assert z_of(Dual(2, 0), Dual(3, 1)).b == 2

# Reverse mode: record (node, [(argument, local derivative)]) on a tape, then accumulate adjoints backward.
values = {"x": 2, "y": 3}
tape = []
values["u"] = values["x"] + values["y"]; tape.append(("u", [("x", 1), ("y", 1)]))
values["z"] = values["u"] * values["x"]; tape.append(("z", [("u", values["x"]), ("x", values["u"])]))
adjoint = {name: 0 for name in values}
adjoint["z"] = 1
for node, edges in reversed(tape):
    for arg, local in edges:
        adjoint[arg] += adjoint[node] * local          # ADD: x receives one contribution per path
assert (adjoint["x"], adjoint["y"]) == (7, 2)
code/python/calculus_autodiff_numpy.py
"""Reverse-mode gradient of a scalar loss over many parameters versus central differences (III.10)."""
import numpy as np

rng = np.random.default_rng(1012)
A = rng.normal(size=(20, 50))
b = rng.normal(size=20)
w = rng.normal(size=50)

def loss(w):
    r = A @ w - b          # forward: r, then L = 0.5 * r.r
    return 0.5 * r @ r

r = A @ w - b
grad = A.T @ r             # backward: r_bar = r, w_bar = A^T r_bar  (one pass for all 50 parameters)

h = 1e-6
fd = np.array([(loss(w + h * e) - loss(w - h * e)) / (2 * h) for e in np.eye(50)])   # 100 evaluations
assert np.max(np.abs(grad - fd)) < 1e-5 * max(1.0, np.max(np.abs(grad)))

Explore

Switch the opening graph to forward mode and seed yy: one pass gives ∂z/∂y\partial z/\partial y only. Edit xx to 00: the direct contribution uu and the path contribution xx change independently. In x·x, step the reverse pass and watch both parallel edges send their share.

Common mistakes

Overwriting an adjoint instead of adding to it, which silently drops paths. Evaluating a node before its arguments. Confusing the direction of passes: forward mode moves tangents with the computation; reverse mode moves adjoints against it, after the forward values are known. Believing AD is approximate like a finite difference.

Numerical considerations

Reverse mode must store forward values (or recompute them) for the backward pass; memory, not arithmetic, is often its limit. Products of many local derivatives can underflow or overflow (vanishing and exploding gradients). Finite-difference checks of an AD implementation need a well-chosen step and a tolerance that reflects their own error, and they are meaningless where the function is not differentiable.

Engineering and ML connections

Deep-learning frameworks record a graph (or tape) while running the forward computation and then run exactly this reverse accumulation to obtain the gradient of the loss with respect to every parameter. The same machinery differentiates physics simulators, rendering and probabilistic programs. Book II returns to it when gradient descent (VI.4) uses these gradients.

Exercises

calculation

Evaluate forward

z = (x + y)·x with u = x + y. For x = 2, y = 3 give u and z.

calculation

Accumulate adjoints

Same graph at x = 2, y = 3. Give ∂z/∂x and ∂z/∂y.

calculation

One node, two edges

q = x·x at x = 3, computed as a multiplication node with the same input twice. Give each edge contribution and dq/dx.

prediction

Which mode?

A loss depends on one million parameters. Why use reverse mode?

Choose one answer

prediction

What a finite difference is

How does automatic differentiation differ from a finite difference?

Choose one answer

Summary and checkpoints

A computational graph evaluates elementary operations in topological order; each edge carries a local derivative. Forward mode propagates tangents for one input per pass; reverse mode accumulates adjoints for one output per pass, adding contributions over every path, including repeated uses of the same input. For z=(x+y)xz=(x+y)x this gives ∂z/∂x=2x+y\partial z/\partial x=2x+y and ∂z/∂y=x\partial z/\partial y=x. Next, III.11 differentiates once more: second derivatives and curvature.

The map of the book

97 of 97 chapters written · eight Parts

demo Foundation demo Try the live vector example Open as a page

Part I

Mathematical Language

The notation and mental objects everything else uses.

9 of 9 chapters written

  1. I.1 Scalars, quantities, units, powers and roots available
  2. I.2 Coordinates and points available
  3. I.3 Vectors: components, magnitude, and direction reference chapter available
  4. I.4 Algebraic expressions, equations and inequalities available
  5. I.5 Functions as input → transformation → output available
  6. I.6 Essential function families available
  7. I.7 Sets, intervals, and relations available
  8. I.8 Indexed quantities and summation available
  9. I.9 The notation map for ML available

Part II

Linear Algebra

Matrices as transformations: the strongest foundation in the book.

19 of 19 chapters written

  1. II.1 Vector addition and subtraction available
  2. II.2 Scalar multiplication and vector scaling available
  3. II.3 Norms, magnitude, and normalization available
  4. II.4 Dot product, angle, and orthogonality available
  5. II.5 Projection and distance to a direction available
  6. II.6 Linear combinations and span available
  7. II.7 Linear independence, basis, and coordinates available
  8. II.8 Matrices as linear transformations available
  9. II.9 Matrix × vector available
  10. II.10 Matrix × matrix as composition available
  11. II.11 Transpose and orthogonality available
  12. II.12 Determinant: orientation and area/volume scaling available
  13. II.13 Linear systems as intersecting constraints available
  14. II.14 Gaussian elimination and row operations available
  15. II.15 Rank and invertibility available
  16. II.16 Inverse matrices available
  17. II.17 Eigenvalues and eigenvectors available
  18. II.18 Orthogonal bases and least-squares geometry available
  19. II.19 Singular Value Decomposition available

Part III

Calculus

Change, local approximation, and sensitivity made visible.

15 of 15 chapters written

  1. III.1 Limits through approach available
  2. III.2 Continuity and local behavior available
  3. III.3 Derivative as secant → tangent available
  4. III.4 Derivative as rate of change and local linear model available
  5. III.5 Derivative rules available
  6. III.6 Chain rule available
  7. III.7 Multivariable functions and partial derivatives available
  8. III.8 Gradient and directional derivatives available
  9. III.9 Jacobian available
  10. III.10 Computational graphs and automatic differentiation available
  11. III.11 Hessian and curvature available
  12. III.12 Integrals as accumulation available
  13. III.13 Fundamental derivative/integral connection available
  14. III.14 Numerical differentiation available
  15. III.15 Numerical integration available

Part IV

Probability

Uncertainty through sample spaces, evidence, and repetition.

16 of 16 chapters written

  1. IV.1 Random experiments, outcomes, and sample spaces available
  2. IV.2 Events and probability mass available
  3. IV.3 Counting and finite probability where needed available
  4. IV.4 Conditional probability as restricted sample space available
  5. IV.5 Independence available
  6. IV.6 Bayes' theorem as probability-mass update available
  7. IV.7 Random variables available
  8. IV.8 PMF, PDF, and CDF available
  9. IV.9 Bernoulli and Binomial distributions available
  10. IV.10 Uniform and Gaussian distributions available
  11. IV.11 Expectation available
  12. IV.12 Variance and standard deviation available
  13. IV.13 Joint, marginal, and conditional distributions available
  14. IV.14 Covariance and correlation available
  15. IV.15 Law of Large Numbers available
  16. IV.16 Central Limit Theorem available

Part V

Statistics

From observed data to estimates, intervals, and likelihood.

10 of 10 chapters written

  1. V.1 Data summaries: mean, median, mode available
  2. V.2 Spread: variance, standard deviation, robust interpretation available
  3. V.3 Population, sample, and sampling variability available
  4. V.4 Estimators and estimation available
  5. V.5 Confidence intervals through repeated sampling available
  6. V.6 Covariance matrices and multivariate spread available
  7. V.7 Regression fundamentals available
  8. V.8 Likelihood available
  9. V.9 Maximum Likelihood Estimation available
  10. V.10 Maximum A Posteriori estimation available

Part VI

Optimization

Learning as repeated parameter updates governed by an objective.

10 of 10 chapters written

  1. VI.1 Objective functions and optimization landscapes available
  2. VI.2 Local vs global optima and stationary points available
  3. VI.3 Convexity available
  4. VI.4 Gradient descent flagship chapter available
  5. VI.5 Learning rate and convergence behavior available
  6. VI.6 Momentum available
  7. VI.7 Stochastic and mini-batch gradient descent available
  8. VI.8 Adam intuition available
  9. VI.9 Constraints and projected/penalized intuition available
  10. VI.10 Numerical stopping and optimization diagnostics available

Part VII

Information Theory

Logarithms, entropy, and the loss behind token prediction.

8 of 8 chapters written

  1. VII.1 Logarithms and log probabilities in computation available
  2. VII.2 Self-information available
  3. VII.3 Entropy available
  4. VII.4 Cross entropy and negative log-likelihood available
  5. VII.5 KL divergence available
  6. VII.6 Logits and softmax available
  7. VII.7 Numerical stability: log-sum-exp and stable softmax available
  8. VII.8 From token logits to language-model loss available

Part VIII

Numerical Computing

Why equivalent expressions behave differently on real machines.

10 of 10 chapters written

  1. VIII.1 Floating-point representation available
  2. VIII.2 Rounding and representation error available
  3. VIII.3 Error propagation and conditioning available
  4. VIII.4 Catastrophic cancellation available
  5. VIII.5 Overflow and underflow available
  6. VIII.6 Stable algorithms available
  7. VIII.7 Numerical linear algebra realities available
  8. VIII.8 Sparse matrices and sparse structure available
  9. VIII.9 Vectorized computation available
  10. VIII.10 Reproducibility, random seeds, and nondeterminism available