III.6 · Calculus
How does a change travel through nested functions?
Nudge the input of a two-stage pipeline and follow the change through the intermediate value to the output. Each stage multiplies it by its own local slope.
Propagate a change through nested functions
Inner: u = 0.5x² − 1
u = 0.5x² − 1; at x = 2, u = 1 and the local factor du/dx = 2. A step Δx = 0.5 changes u by 1.125.
Outer: y = 0.25u³
y = 0.25u³; at u = 1, y = 0.25 and dy/du = 0.75. The change Δu produces Δy = 2.14892578125.
Composite: y = f(g(x))
Composite y = f(g(x)); its tangent slope at x = 2 is the product 0.75 × 2 = 1.5.
- Input
- 2
- Intermediate value g(x)
- 1
- Output f(u)
- 0.25
- Inner sensitivity du/dx
- 2
- Outer sensitivity dy/du, at u
- 0.75
- Chain-rule product dy/dx
- 1.5
- Derivative of the composed formula
- 1.5
- Exact agreement
- yes, exactly equal
- Actual output change
- 2.14892578125
- Linearized output change
- 0.75
Exact values use =; binary64 approximations use ≈. Undefined values state their reason.
Sensitivities multiply: dy/dx = f′(u)·g′(x), here 0.75 × 2 = 1.5 exactly. The outer slope is evaluated at u = g(x), not at x.
Forward: inner stage
u = g(2) = 1.
from −2.5 to 2.5, up to 2 decimal places
from −1.5 to 1.5, up to 2 decimal places
At the inner function gives , and its tangent slope is : a small change in is doubled. The outer function has slope at . The composite slope is , and the inspector confirms it exactly by differentiating the composed polynomial. Now choose Inner slope 0: whatever the outer function does, a flat inner stage stops the change.
Intuition: sensitivities multiply
In a pipeline , a small change becomes , and that becomes . Combining,
Each stage contributes its local amplification factor, and factors multiply — just as two gearboxes in a row multiply their ratios.
Definition
If is differentiable at and is differentiable at , then is differentiable at and
The outer derivative is evaluated at the intermediate value , not at .
Mechanics: what the explorer computes
The three planes share one state. The inner plane shows , its tangent at and the actual change ; the outer plane shows , its tangent at and the actual change ; the composite plane shows and its tangent with the chain-rule slope. When both stages are polynomials, the inspector also composes them exactly and differentiates the result — an independent route that must agree exactly. For and , values are binary64 and marked .
Derivation
Write the outer function’s local model at as
where as (this is differentiability of ). Put and divide by :
As , (because is continuous), so and . Hence . This form avoids dividing by , which could be zero.
Worked example
Take , , :
- forward: , ;
- local factors: , ;
- backward product: .
Composed directly, and , which is at . For the linearized change is , while the actual change is : the chain rule is exact for rates, approximate for finite steps.
Replay the worked derivation
Forward: inner stage
u = g(2) = 1.
Toward computational graphs
The replay ends by multiplying backward: start with , multiply by , then by . In a longer chain , the same backward product needs one multiplication per stage. When an input feeds several paths, the contributions of the paths add. Chapter III.10 turns this into an algorithm on a graph of elementary operations — reverse-mode automatic differentiation — the computation behind backpropagation. No neural network is needed to understand it.
Executable reference code
The reference composes polynomials exactly with Fraction and checks against the derivative of the composition. The NumPy version evaluates on a grid and compares the chain-rule derivative with a centered difference whose error is bounded.
"""Chain rule on exact polynomials: f'(g(x)) * g'(x) equals the derivative of the composition (III.6)."""
from fractions import Fraction as F
def ev(c, x):
return sum(ck * x**k for k, ck in enumerate(c))
def der(c):
return [k * ck for k, ck in enumerate(c)][1:]
def compose(f, g):
out = [F(0)]
for ck in reversed(f): # Horner: out = out * g + ck
prod = [F(0)] * (len(out) + len(g) - 1)
for i, a in enumerate(out):
for j, b in enumerate(g):
prod[i + j] += a * b
prod[0] += ck
out = prod
return out
g = [F(-1), F(0), F(1, 2)] # x**2/2 - 1
f = [F(0), F(0), F(0), F(1, 4)] # u**3/4
x = F(2)
u = ev(g, x)
chain = ev(der(f), u) * ev(der(g), x)
assert (u, ev(der(g), x), ev(der(f), u), chain) == (1, 2, F(3, 4), F(3, 2))
assert ev(der(compose(f, g)), x) == chain"""e**sin(x): chain-rule derivative versus a centered difference with a bounded error (III.6)."""
import numpy as np
x = np.linspace(-3, 3, 61)
chain = np.exp(np.sin(x)) * np.cos(x) # f'(u) at u = sin x, times g'(x)
h = 1e-5
centered = (np.exp(np.sin(x + h)) - np.exp(np.sin(x - h))) / (2 * h)
# Truncation ~ h**2 |h'''|/6 (|h'''| < 20 here) plus rounding ~ eps*e/h.
assert np.max(np.abs(chain - centered)) < 20 * h**2 / 6 + 4 * np.finfo(float).eps * np.e / hExplore
Swap the inner and outer roles: versus are different functions with different derivatives. Find an where the outer slope is zero but the inner slope is not. Increase and watch the actual leave the linear prediction.
Common mistakes
Evaluating at instead of . Forgetting the inner factor: , not . Treating as cancelling fractions without the differentiability conditions that make it valid.
Numerical considerations
Long chains multiply many factors. Factors with magnitude below shrink the product toward zero, factors above inflate it — the vanishing and exploding gradients of deep networks. In binary64 the product can underflow or overflow even when each factor is ordinary, which is why implementations often work with logarithms or normalised quantities (VII.7).
Engineering and ML connections
Every layer of a neural network is a stage ; the gradient of the loss with respect to an early parameter is a chain-rule product through all later layers. The same rule propagates measurement uncertainty through a sequence of formulas and units through a pipeline of conversions.
Exercises
Summary and checkpoints
For nested functions, local rates multiply: , with the outer derivative evaluated at the intermediate value. The backward product of local factors is the seed of automatic differentiation. Next, III.7 lets a function depend on two inputs at once.