Skip to content
The Lumenary
Grades 6–8Ages 11–14 55 min

Diagrams where paths agree

Two routes from the same start to the same finish — do they always lead to the same place? Squares of functions that say “yes” describe unit conversions, weekdays, prices and the very idea of preserving an operation.

Formally verified · 19 LeanComputationally tested · 1 PythonAI-drafted · awaiting human reviewMathematically reviewed: Awaiting human review

Your guides: Chloe, Margaret, Gideon

MotivationH

Two routes to the same price

Wanjiru sells hand-woven baskets in Nairobi. A basket costs 10001000 Kenyan shillings before tax, and Kenya adds 16%16\% value-added tax (VAT). A visitor wants to know the price in US dollars. To keep the numbers simple, suppose the exchange rate is 125125 shillings to the dollar (real rates change every day).

There are two routes from “price before tax, in shillings” to “price with tax, in dollars”:

  • add VAT, then convert: 1000×1.16=11601000 \times 1.16 = 1160 shillings, and 1160÷125=9.281160 \div 125 = 9.28 dollars;
  • convert, then add VAT: 1000÷125=81000 \div 125 = 8 dollars, and 8×1.16=9.288 \times 1.16 = 9.28 dollars.

Same answer! Now Wanjiru adds a delivery fee of 200200 shillings. “Add the fee, then convert” gives 1200÷125=9.601200 \div 125 = 9.60 dollars. But “convert, then add 200200” gives 8+200=2088 + 200 = 208 dollars — absurd. The fee has to be converted too: on the dollar route we must add 200÷125=1.60200 \div 125 = 1.60 dollars.

Pictures of routes like these, and the question “do the routes always agree?”, are the subject of this lesson. They are called commutative diagrams, and they are one of the most widely used pictures in modern mathematics.

IntuitionH

Squares with two routes

Draw each set as a corner and each function as an arrow. The VAT story becomes a square:

shillings\text{shillings}
shillings\text{shillings}
dollars\text{dollars}
dollars\text{dollars}
×1.16\times 1.16
÷125\div 125
÷125\div 125
×1.16\times 1.16
Across then down equals down then across: adding VAT and converting can be done in either order.

Start at the top left. One route goes across, then down; the other goes down, then across. Both end at the bottom right. The square commutes if the two routes always give the same result.

With the delivery fee, the square only commutes if the bottom arrow adds the converted fee:

shillings\text{shillings}
shillings\text{shillings}
dollars\text{dollars}
dollars\text{dollars}
+200+200
÷125\div 125
÷125\div 125
+1.60+1.60
With +200 on the bottom the routes disagree; with +1.60 they agree for every price.
DefinitionsH

Definitions

Definition— diagram of functions

A diagram of functions shows sets at its corners and functions as arrows between them. A route is a sequence of arrows, each starting where the previous one ends; following a route means applying its functions one after another (see function machines in sequence).

Definition— commuting square

A square of functions

A→  f  Bh↓↓gC→  k  D\begin{array}{ccc} A & \xrightarrow{\ \ f\ \ } & B \\ {\scriptstyle h}\downarrow & & \downarrow{\scriptstyle g} \\ C & \xrightarrow{\ \ k\ \ } & D \end{array}

commutes if the two routes from AA to DD give the same output for every input:

g(f(a))=k(h(a))for every a∈A.g\big(f(a)\big) = k\big(h(a)\big) \quad \text{for every } a \in A.

Definition— commuting triangle

A triangle with f:A→Bf : A \to B, g:B→Cg : B \to C and h:A→Ch : A \to C commutes if the two-step route equals the direct one: g(f(a))=h(a)g(f(a)) = h(a) for every a∈Aa \in A. More generally, a diagram commutes when any two routes with the same start and the same end give the same function.

Note

“For every input” is essential. To show that a square commutes we need an argument that covers all inputs. To show that it does not commute, one input where the routes differ is enough.

Worked examplesH

Worked examples

Example— Doubling and adding

Z\Z
Z\Z
Z\Z
Z\Z
×2\times 2
+1+1
+2+2
×2\times 2
Double, then add 2, equals add 1, then double.

Across then down: x↦2x+2x \mapsto 2x + 2. Down then across: x↦2(x+1)=2x+2x \mapsto 2(x + 1) = 2x + 2. By the distributive law these agree for every integer, so the square commutes. If instead the right arrow were “+1+1”, the routes would give 2x+12x + 1 and 2x+22x + 2: they differ at every input, so that square does not commute.

Example— A triangle of units

Hours to minutes is ×60\times 60, minutes to seconds is ×60\times 60, and hours to seconds is ×3600\times 3600. The triangle commutes, because 60⋅(60⋅t)=3600 t60 \cdot (60 \cdot t) = 3600\, t for every number of hours tt.

hours\text{hours}
minutes\text{minutes}
seconds\text{seconds}
×60\times 60
×60\times 60
×3600\times 3600
Two steps or one: the same conversion.

Example— What day is it in 100 days?

Number the days 0,1,2,…0, 1, 2, \dots and let the weekday of day nn be its remainder on division by 77 (so if day 00 is a Monday, weekday 00 means Monday, 11 Tuesday, and so on). Since 100=14⋅7+2100 = 14 \cdot 7 + 2, moving on 100100 days moves the weekday on by 22:

day\text{day}
day\text{day}
weekday\text{weekday}
weekday\text{weekday}
+100+100
 mod 7\bmod 7
 mod 7\bmod 7
+2 mod 7+2 \bmod 7
Add 100 days, then find the weekday = find the weekday, then move on 2 weekdays.

So if today is a Saturday (weekday 55), in 100100 days it will be weekday (5+2) mod 7=0(5 + 2) \bmod 7 = 0: a Monday. The square lets us skip the big number entirely.

ExplanationH

Preserving an operation

A carpenter in Kumasi measures two planks: 1.21.2 m and 0.850.85 m. Laid end to end they make 2.052.05 m, which is 205205 cm. Measured in centimetres they are 120120 cm and 8585 cm, which make 205205 cm. Converting and adding can be done in either order:

100⋅(a+b)=100a+100b.100 \cdot (a + b) = 100a + 100b.

This is a commuting square too — but its left-hand corners hold pairs of lengths (a,b)(a, b):

pairs of lengths in m\text{pairs of lengths in m}
lengths in m\text{lengths in m}
pairs of lengths in cm\text{pairs of lengths in cm}
lengths in cm\text{lengths in cm}
add\text{add}
×100 each\times 100 \text{ each}
×100\times 100
add\text{add}
Add then convert, or convert both then add: a function preserves addition when this square commutes.

Definition— preserving addition

A function ff preserves addition if f(a+b)=f(a)+f(b)f(a + b) = f(a) + f(b) for all inputs aa and bb — that is, if “add, then apply ff” equals “apply ff to both, then add”.

Some functions preserve addition and many do not:

  • x↦100xx \mapsto 100x (metres to centimetres) preserves addition: that is the distributive law.
  • x↦x+1x \mapsto x + 1 does not: with a=b=0a = b = 0, “add then apply” gives 11 but “apply then add” gives 1+1=21 + 1 = 2.
  • x↦x2x \mapsto x^2 does not: (1+1)2=4(1 + 1)^2 = 4 but 12+12=21^2 + 1^2 = 2.
  • x↦100xx \mapsto 100x preserves addition but not multiplication: 100⋅(1⋅1)=100100 \cdot (1 \cdot 1) = 100, while (100⋅1)⋅(100⋅1)=10 000(100 \cdot 1) \cdot (100 \cdot 1) = 10\,000. That is why 1 m2=10 000 cm21\ \mathrm{m}^2 = 10\,000\ \mathrm{cm}^2, not 100 cm2100\ \mathrm{cm}^2: an area is a product of two lengths.
  • Celsius to Fahrenheit, C↦1.8 C+32C \mapsto 1.8\,C + 32, does not preserve addition: 10 ∘C10\,^\circ\mathrm{C} and 20 ∘C20\,^\circ\mathrm{C} give 5050 and 6868, which add to 118118, but 30 ∘C30\,^\circ\mathrm{C} is 86 ∘F86\,^\circ\mathrm{F}. (The differences of temperatures do convert by ×1.8\times 1.8 alone.)
  • “Take the last digit” preserves addition if the bottom route adds digits with wrap-around (keeping only the last digit of the sum): the last digit of 47+38=8547 + 38 = 85 is 55, and 7+8=157 + 8 = 15 also ends in 55.
  • Squares can even change the operation. 2a+b=2a⋅2b2^{a + b} = 2^a \cdot 2^b: “add, then raise 22 to that power” equals “raise 22 to each power, then multiply”.
ProofH

Proofs

Theorem— Theorem 1 (metres to centimetres preserves addition)

For all numbers aa and bb:   100(a+b)=100a+100b\;100(a + b) = 100a + 100b.

Proof

This is the distributive law c(a+b)=ca+cbc(a + b) = ca + cb with c=100c = 100.

∎

Theorem— Theorem 2 (which straight-line rules preserve addition?)

Let mm and cc be integers. The function x↦mx+cx \mapsto mx + c on Z\Z preserves addition exactly when c=0c = 0. In particular, x↦x+1x \mapsto x + 1 does not preserve addition.

Proof

The two routes give m(a+b)+c=ma+mb+cm(a + b) + c = ma + mb + c and (ma+c)+(mb+c)=ma+mb+2c(ma + c) + (mb + c) = ma + mb + 2c.

If c=0c = 0, these are equal for all a,ba, b.

If the function preserves addition, the routes agree in particular for a=b=0a = b = 0, which gives c=2cc = 2c, so c=0c = 0.

∎

Theorem— Theorem 3 (pasting squares)

Suppose that in the diagram

A→  f  B→  g  Cp↓↓q↓rD→  f′  E→  g′  F\begin{array}{ccccc} A & \xrightarrow{\ \ f\ \ } & B & \xrightarrow{\ \ g\ \ } & C \\ {\scriptstyle p}\downarrow & & \downarrow{\scriptstyle q} & & \downarrow{\scriptstyle r} \\ D & \xrightarrow{\ \ f'\ \ } & E & \xrightarrow{\ \ g'\ \ } & F \end{array}

the left square commutes, q(f(x))=f′(p(x))q(f(x)) = f'(p(x)) for all x∈Ax \in A, and the right square commutes, r(g(y))=g′(q(y))r(g(y)) = g'(q(y)) for all y∈By \in B. Then the outer rectangle commutes: r(g(f(x)))=g′(f′(p(x)))r(g(f(x))) = g'(f'(p(x))) for all x∈Ax \in A.

Proof

Take any x∈Ax \in A. The right square, applied to the input y=f(x)∈By = f(x) \in B, gives r(g(f(x)))=g′(q(f(x)))r(g(f(x))) = g'(q(f(x))). The left square gives q(f(x))=f′(p(x))q(f(x)) = f'(p(x)), so

r(g(f(x)))=g′(q(f(x)))=g′(f′(p(x))).r\big(g(f(x))\big) = g'\big(q(f(x))\big) = g'\big(f'(p(x))\big).

∎

In words: we slide the route across the rectangle one square at a time, and each slide is allowed because that square commutes.

Note

The converse is false. The outer rectangle can commute even if the left square does not. Use integers at every corner, let ff, gg, f′f' and pp be “do nothing”, let qq be “add 11”, and let rr and g′g' send every number to 00. Both outer routes send everything to 00, so the rectangle commutes, but the left square would need x+1=xx + 1 = x.

Theorem— Theorem 4 (addition-preserving functions are multiplications)

If f:Z→Zf : \Z \to \Z preserves addition, then f(x)=f(1)⋅xf(x) = f(1) \cdot x for every integer xx.

Proof

First, f(0)=f(0+0)=f(0)+f(0)f(0) = f(0 + 0) = f(0) + f(0), so f(0)=0f(0) = 0.

Next, f(n+1)=f(n)+f(1)f(n + 1) = f(n) + f(1) for every nn. Starting from f(0)=0f(0) = 0 and adding f(1)f(1) at each step, f(1)=1⋅f(1)f(1) = 1 \cdot f(1), f(2)=2⋅f(1)f(2) = 2 \cdot f(1), f(3)=3⋅f(1)f(3) = 3 \cdot f(1), and so on: f(n)=n⋅f(1)f(n) = n \cdot f(1) for every natural number nn. (Strictly, this “and so on” is a proof by induction.)

Finally, f(x)+f(−x)=f(x+(−x))=f(0)=0f(x) + f(-x) = f(x + (-x)) = f(0) = 0, so f(−x)=−f(x)f(-x) = -f(x). For a negative integer −n-n this gives f(−n)=−n⋅f(1)f(-n) = -n \cdot f(1).

∎

So among all functions from Z\Z to Z\Z, the ones that preserve addition are exactly the multiplications x↦mxx \mapsto mx. A single value, f(1)f(1), determines everything.

Formal mathematicsF

Commuting squares in Lean

A square is described by its four arrows; it commutes when the two routes agree at every input. In Lean that is a definition, word for word:

SquareCommutesLean 4Formally verified
/-- The square with `top : A → B`, `right : B → D`, `left : A → C` and `bottom : C → D`
**commutes** when the two routes from `A` to `D` agree for every input: going along the top and
then down the right gives the same as going down the left and then along the bottom. -/
def SquareCommutes {A B C D : Type} (top : A → B) (right : B → D) (left : A → C)
    (bottom : C → D) : Prop :=
  ∀ a, right (top a) = bottom (left a)
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
TriangleCommutesLean 4Formally verified
/-- The triangle with `f : A → B`, `g : B → C` and `h : A → C` **commutes** when the two-step
route equals the direct route: `g (f a) = h a` for every `a`. -/
def TriangleCommutes {A B C : Type} (f : A → B) (g : B → C) (h : A → C) : Prop :=
  ∀ a, g (f a) = h a
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
double_add_squareLean 4Proved here from basic factsFormally verified
/-- "Double, then add 2" equals "add 1, then double": `2x + 2 = 2(x + 1)` for every integer. -/
theorem double_add_square :
    SquareCommutes (fun x : Int => 2 * x) (fun x => x + 2) (fun x => x + 1) (fun x => 2 * x) := by
  intro a
  show 2 * a + 2 = 2 * (a + 1)
  omega
Axioms used: propext, Quot.soundformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
add_double_not_squareLean 4Proved here from basic factsFormally verified
/-- "Add 1, then double" is **not** "double, then add 1": at `0` the routes give `2` and `1`.
One input where the routes disagree is enough to show a square does not commute. -/
theorem add_double_not_square :
    ¬ SquareCommutes (fun x : Int => x + 1) (fun x => 2 * x) (fun x => 2 * x) (fun x => x + 1) := by
  intro h
  have h0 := h 0
  revert h0
  decide
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
agree_twice_not_squareLean 4Proved here from basic factsFormally verified
/-- Agreeing at some inputs is not enough. The routes "square" and "double" agree at `0` and at
`2` (`0² = 2·0` and `2² = 2·2`), but the square does not commute: at `1` they give `1` and `2`. -/
theorem agree_twice_not_square :
    (0 * 0 = 2 * 0 ∧ 2 * 2 = 2 * (2 : Int)) ∧
      ¬ SquareCommutes (fun x : Int => x * x) id id (fun x => 2 * x) := by
  refine ⟨by decide, ?_⟩
  intro h
  have h1 := h 1
  revert h1
  decide
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
hours_triangleLean 4Proved here from basic factsFormally verified
/-- Hours to minutes (`× 60`), then minutes to seconds (`× 60`), is hours to seconds (`× 3600`). -/
theorem hours_triangle :
    TriangleCommutes (fun h : Nat => 60 * h) (fun m => 60 * m) (fun h => 3600 * h) := by
  intro h
  show 60 * (60 * h) = 3600 * h
  omega
Axioms used: propext, Quot.soundformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
weekday_squareLean 4Proved here from basic factsFormally verified
/-- **What day is it in 100 days?** Number the days, and let a day's remainder on division by `7`
be its weekday. The square "add 100 days, then take the weekday" = "take the weekday, then move
on 2 weekdays" commutes, because `100 = 14 · 7 + 2`. -/
theorem weekday_square :
    SquareCommutes (fun n : Nat => n + 100) (fun n => n % 7) (fun n => n % 7)
      (fun r => (r + 2) % 7) := by
  intro n
  show (n + 100) % 7 = (n % 7 + 2) % 7
  omega
Axioms used: propext, Quot.soundformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor

Preserving addition, and the fact that it is a commuting square (the corners on the left hold pairs of integers, Int × Int):

PreservesAddLean 4Formally verified
/-- `f` **preserves addition** if `f (a + b) = f a + f b` for all `a` and `b`. -/
def PreservesAdd (f : Int → Int) : Prop := ∀ a b, f (a + b) = f a + f b
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
preserves_add_iff_squareLean 4Proved here from basic factsFormally verified
/-- Preserving addition **is** a commuting square. Its corners hold pairs of numbers on the left
and single numbers on the right: along the top, add the pair, then apply `f`; down the left,
apply `f` to both numbers, then add. -/
theorem preserves_add_iff_square (f : Int → Int) :
    PreservesAdd f ↔
      SquareCommutes (fun p : Int × Int => p.1 + p.2) f (fun p => (f p.1, f p.2))
        (fun p => p.1 + p.2) := by
  constructor
  · intro h p
    exact h p.1 p.2
  · intro h a b
    exact h (a, b)
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
cm_preserves_addLean 4Applies a library theoremFormally verified
/-- Converting metres to centimetres, `x ↦ 100x`, preserves addition: `100(a + b) = 100a + 100b`.
This is the distributive law, core Lean's `Int.mul_add`. -/
theorem cm_preserves_add : PreservesAdd (fun x => 100 * x) :=
  fun a b => Int.mul_add 100 a b
Axioms used: propextformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
add_one_not_preservesLean 4Proved here from basic factsFormally verified
/-- `x ↦ x + 1` does **not** preserve addition: with `a = b = 0`, the routes give
`(0 + 0) + 1 = 1` and `(0 + 1) + (0 + 1) = 2`. -/
theorem add_one_not_preserves : ¬ PreservesAdd (fun x => x + 1) := by
  intro h
  have h00 := h 0 0
  revert h00
  decide
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
affine_preserves_add_iffLean 4Proved here from basic factsFormally verified
/-- Exactly which functions `x ↦ mx + c` preserve addition? Those with `c = 0`.
The two routes give `m(a + b) + c` and `(ma + c) + (mb + c)`, which differ by `c`. -/
theorem affine_preserves_add_iff (m c : Int) : PreservesAdd (fun x => m * x + c) ↔ c = 0 := by
  constructor
  · intro h
    have h00 : m * (0 + 0) + c = (m * 0 + c) + (m * 0 + c) := h 0 0
    rw [Int.zero_add, Int.mul_zero, Int.zero_add] at h00
    omega
  · intro hc a b
    show m * (a + b) + c = (m * a + c) + (m * b + c)
    rw [hc, Int.mul_add, Int.add_zero, Int.add_zero, Int.add_zero]
Axioms used: propext, Quot.soundformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
square_not_preservesLean 4Proved here from basic factsFormally verified
/-- Squaring does not preserve addition: `(1 + 1)² = 4`, but `1² + 1² = 2`. -/
theorem square_not_preserves : ¬ PreservesAdd (fun x => x * x) := by
  intro h
  have h11 := h 1 1
  revert h11
  decide
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
cm_not_preserves_mulLean 4Proved here from basic factsFormally verified
/-- `x ↦ 100x` preserves addition but **not** multiplication: `100 · (1 · 1) = 100`, while
`(100 · 1) · (100 · 1) = 10000`. This is why `1 m² = 10 000 cm²`, not `100 cm²`. -/
theorem cm_not_preserves_mul : ¬ ∀ a b : Int, 100 * (a * b) = (100 * a) * (100 * b) := by
  intro h
  have h11 := h 1 1
  revert h11
  decide
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor

Theorem 4, with the induction written out:

preserves_add_is_mulLean 4Proved here from basic factsFormally verified
/-- **Every addition-preserving function `ℤ → ℤ` is multiplication by a fixed number**, namely
by `f 1`. Steps: `f 0 = 0` (from `f (0 + 0) = f 0 + f 0`); `f (n + 1) = f n + f 1`, so by induction
`f n = f 1 · n` for every natural number `n`; and `f (−x) = −f x` (because
`f x + f (−x) = f 0 = 0`), which handles the negative numbers. -/
theorem preserves_add_is_mul (f : Int → Int) (h : PreservesAdd f) : ∀ x, f x = f 1 * x := by
  have h0 : f 0 = 0 := by
    have e := h 0 0
    rw [Int.add_zero] at e
    omega
  have hnat : ∀ n : Nat, f n = f 1 * n := by
    intro n
    induction n with
    | zero =>
      show f 0 = f 1 * 0
      rw [h0, Int.mul_zero]
    | succ k ih =>
      have hk : ((k + 1 : Nat) : Int) = (k : Int) + 1 := by omega
      rw [hk, h, ih, Int.mul_add, Int.mul_one]
  have hneg : ∀ x, f (-x) = -f x := by
    intro x
    have e := h x (-x)
    rw [Int.add_right_neg, h0] at e
    omega
  intro x
  obtain ⟨n, hn | hn⟩ := Int.eq_nat_or_neg x
  · rw [hn, hnat]
  · rw [hn, hneg, hnat, Int.mul_neg]
Axioms used: propext, Quot.soundformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor

Two squares that change one operation into another — remainders, and powers of 22:

remainder_preserves_addLean 4Applies a library theoremFormally verified
/-- Taking remainders on division by `7` turns `+` into "add, then take the remainder":
`(a + b) % 7 = (a % 7 + b % 7) % 7`. This applies core Lean's `Nat.add_mod`. -/
theorem remainder_preserves_add (a b : Nat) : (a + b) % 7 = (a % 7 + b % 7) % 7 :=
  Nat.add_mod a b 7
Axioms used: propextformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
pow_turns_add_into_mulLean 4Applies a library theoremFormally verified
/-- A square that turns addition into multiplication: `2^(a + b) = 2^a · 2^b`. This applies core
Lean's `Nat.pow_add`. -/
theorem pow_turns_add_into_mul (a b : Nat) : 2 ^ (a + b) = 2 ^ a * 2 ^ b :=
  Nat.pow_add 2 a b
Axioms used: propextformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor

Finally, pasting — the calc block is the human proof, one square per line — and the counterexample to its converse:

pasteLean 4Proved here from basic factsFormally verified
/-- **Pasting.** Put two commuting squares side by side, sharing the middle arrow `b`:

    A --f--> B --g--> C
    |a       |b       |c
    v        v        v
    D --f'-> E --g'-> F

If the left square (`b (f x) = f' (a x)`) and the right square (`c (g y) = g' (b y)`) commute,
then so does the outer rectangle: `c (g (f x)) = g' (b (f x)) = g' (f' (a x))`. -/
theorem paste {A B C D E F : Type} {f : A → B} {g : B → C} {f' : D → E} {g' : E → F}
    {a : A → D} {b : B → E} {c : C → F}
    (hleft : SquareCommutes f b a f') (hright : SquareCommutes g c b g') :
    SquareCommutes (fun x => g (f x)) c a (fun x => g' (f' x)) := by
  intro x
  calc c (g (f x)) = g' (b (f x)) := hright (f x)
    _ = g' (f' (a x)) := by rw [hleft x]
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor
paste_converse_falseLean 4Proved here from basic factsFormally verified
/-- The converse fails: the outer rectangle can commute although the left square does not.
Take every map to be the identity, except `b = (· + 1)` and `c = g' = 0` (constant). The outer
routes both give `0`, but the left square needs `x + 1 = x`. -/
theorem paste_converse_false :
    ∃ f g f' g' a b c : Int → Int,
      SquareCommutes (fun x => g (f x)) c a (fun x => g' (f' x)) ∧ ¬ SquareCommutes f b a f' := by
  refine ⟨id, id, id, fun _ => 0, id, fun x => x + 1, fun _ => 0, ?_, ?_⟩
  · intro x
    rfl
  · intro h
    have h0 := h 0
    revert h0
    decide
Axioms used: No axiomsformal/Lumenary/CommutativeDiagramsIntro.leanTry it in the Lean web editor

What is formalised: every theorem and worked example of this lesson for integers and natural numbers, using core Lean only. In Mathlib, Lean's large mathematical library, functions that preserve addition are called additive homomorphisms (AddMonoidHom), and commuting squares in any category are described by CategoryTheory.CommSq.

ComputationC

Testing squares by computer

Do the paths agree? Testing squares of functionsPythonExhaustive finite checkCounterexampleExact computationComputationally tested
"""Do the paths agree? Testing squares of functions by computer.

A square of functions commutes when both routes give the same output for
every input. The experiment (1) tests three squares on the integers -50..50
and reports the first input where the routes disagree; (2) hunts for
counterexamples to "f(a + b) = f(a) + f(b)"; (3) checks all 3125 functions
from {0, ..., 4} to itself and finds exactly 5 that preserve addition with
remainders, each "multiply by m"; (4) checks every way of filling a pair of
squares with functions on {0, 1}: pasting always works, the converse does
not. Parts 3 and 4 are exhaustive; parts 1 and 2 are evidence or refutation.
"""

from fractions import Fraction
from itertools import product

def around_zero(n):
    """The integers -n..n, ordered 0, -1, 1, -2, 2, ... so that searches
    report the smallest counterexample first."""
    return sorted(range(-n, n + 1), key=lambda x: (abs(x), x))

def first_disagreement(route1, route2, inputs):
    """The first input where the two routes differ, or None if they agree."""
    for x in inputs:
        if route1(x) != route2(x):
            return x
    return None

def add_counterexample(f, values, add=lambda a, b: a + b):
    """A pair (a, b) with f(a + b) != f(a) + f(b), or None. `add` is the
    addition used after applying f (for remainders it wraps around)."""
    for a in values:
        for b in values:
            if f(a + b) != add(f(a), f(b)):
                return (a, b)
    return None

def additive_maps_mod(n):
    """All functions f on {0..n-1} with f((a+b) % n) == (f(a)+f(b)) % n."""
    found = []
    for outputs in product(range(n), repeat=n):
        if all(outputs[(a + b) % n] == (outputs[a] + outputs[b]) % n
               for a in range(n) for b in range(n)):
            found.append(outputs)
    return found

def square_commutes(top, right, left, bottom, inputs):
    """right(top(x)) == bottom(left(x)) for every x; maps are tuples."""
    return all(right[top[x]] == bottom[left[x]] for x in inputs)

def pasting_counts():
    """Fill the two squares (7 maps on {0, 1}) in every way. Return
    (both squares commute, ... and the rectangle commutes too,
    rectangle commutes but the left square does not)."""
    maps = list(product((0, 1), repeat=2))
    both = both_and_outer = outer_not_left = 0
    for f, g, f2, g2, a, b, c in product(maps, repeat=7):
        left = square_commutes(f, b, a, f2, (0, 1))
        right = square_commutes(g, c, b, g2, (0, 1))
        gf = tuple(g[f[x]] for x in (0, 1))
        g2f2 = tuple(g2[f2[x]] for x in (0, 1))
        outer = square_commutes(gf, c, a, g2f2, (0, 1))
        if left and right:
            both += 1
            both_and_outer += outer
        if outer and not left:
            outer_not_left += 1
    return both, both_and_outer, outer_not_left

def main():
    xs = around_zero(50)
    print("1. Two routes around a square, inputs -50..50")
    tests = [
        ("double, +2  vs  +1, double", lambda x: 2 * x + 2, lambda x: 2 * (x + 1)),
        ("+1, double  vs  double, +1", lambda x: 2 * (x + 1), lambda x: 2 * x + 1),
        ("square      vs  double    ", lambda x: x * x, lambda x: 2 * x),
    ]
    for name, r1, r2 in tests:
        bad = first_disagreement(r1, r2, xs)
        agree = sum(r1(x) == r2(x) for x in xs)
        verdict = "agree on all 101" if bad is None else f"differ at {bad}"
        print(f"   {name}: {verdict} (agree on {agree})")
    print()
    print("2. Does f(a + b) = f(a) + f(b)? Search a, b in -20..20")
    vals = around_zero(20)
    rules = [("100x", lambda x: 100 * x), ("x + 1", lambda x: x + 1),
             ("x * x", lambda x: x * x), ("-3x", lambda x: -3 * x),
             ("C to F", lambda x: Fraction(9, 5) * x + 32)]
    for name, f in rules:
        cx = add_counterexample(f, vals)
        print(f"   {name:<7}", "no counterexample" if cx is None
              else f"fails at a, b = {cx[0]}, {cx[1]}")
    print()
    maps = additive_maps_mod(5)
    print("3. All 5^5 = 3125 functions on {0..4}, adding with remainders mod 5")
    print(f"   preserving addition: {len(maps)}")
    for m in maps:
        print(f"   {m}  = multiply by {m[1]}:",
              all(m[x] == m[1] * x % 5 for x in range(5)))
    print()
    both, outer, converse = pasting_counts()
    print("4. Pasting: all 4^7 = 16384 ways to fill two squares on {0, 1}")
    print(f"   both squares commute: {both}; rectangle commutes too: {outer}")
    print(f"   rectangle commutes but the left square does not: {converse}")
    print()
    print("Epistemic status: parts 3 and 4 are exhaustive, so they prove their")
    print("claims for these small sets; parts 1 and 2 refute with one")
    print("counterexample but only test the others. The lesson proves that")
    print("pasting always works and that additive maps are multiplications.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Parts 1 and 2 are refutations or evidence: a disagreement found at one input settles “does not commute” for good, but “no counterexample among −20-20 to 2020” is only a hint. Parts 3 and 4 are exhaustive. Part 3 is Theorem 4 in miniature: of all 31253125 functions on {0,1,2,3,4}\{0, 1, 2, 3, 4\}, exactly 55 preserve addition (with remainders on division by 55), and each one is “multiply by mm”. Part 4 confirms pasting for every one of the 16641664 fillings where both squares commute, and finds thousands of fillings where the rectangle commutes although the left square does not.

Explore

Explore: when do two routes agree?

Graph each route as a function of the input xx. The square commutes exactly when the two graphs are the same line. Here the routes are “add aa, then multiply by mm” and “multiply by mm, then add aa”:

Two routes, two graphs

Move m and a. When do the lines coincide?

  • add a, then multiply by m
  • multiply by m, then add a
  • add a, then multiply by m: y = 4
  • multiply by m, then add a: y = 3

Things to try: find all settings of mm and aa where the lines coincide. (You should find a=0a = 0 with any mm, and m=1m = 1 with any aa — can you explain why from the formulas mx+mamx + ma and mx+amx + a?) When they don't coincide, the lines are parallel or cross at one point — and crossing at one point means the routes agree for one input only, which is not enough.

The machines below run two functions in both orders, which is exactly the square with f,gf, g across the top and right and g,fg, f down the left and bottom. Look for pairs of machines whose square commutes.

Composition machines

Feed a number through two machines. Does the order matter?

g ∘ ff first, then g

3

Add 1

x ↦ x + 1

→ 4

Double

x ↦ 2x

→ 8

f ∘ gg first, then f

3

Double

x ↦ 2x

→ 6

Add 1

x ↦ x + 1

→ 7

Different results: 8 versus 7. The order of composition matters.

Exercises

Exercises

1. Diagrams where paths agree

Warm-upHuman

A square on the integers has “add 33” across the top and “multiply by 22” down the right; down the left it has “multiply by 22” and across the bottom “add 66”. Does it commute?

Choose one

2. Diagrams where paths agree

Warm-upHuman

Weekdays are numbered 00 (Monday) to 66 (Sunday). Today is weekday 44 (Friday). Using the square “add 100100 days, then take the weekday = take the weekday, then add 22 and take the remainder on division by 77”, which weekday number will it be in 100100 days?

3. Diagrams where paths agree

CoreHuman

Which of these functions from Z\Z to Z\Z preserve addition, f(a+b)=f(a)+f(b)f(a + b) = f(a) + f(b)? Choose all that apply.

Choose all that apply

4. Diagrams where paths agree

CoreHuman

Kwame tests a square whose two routes are x↦(x+1)2x \mapsto (x + 1)^2 and x↦x2+1x \mapsto x^2 + 1. At x=0x = 0 both give 11, so he says the square commutes. Is he right?

Choose one

5. Diagrams where paths agree

CoreHuman

A rug measures 22 m by 33 m. What is its area in square centimetres?

6. Diagrams where paths agree

CoreHuman

A square has “add a delivery fee of 300300 shillings” across the top and “divide by 125125” (shillings to dollars) down both sides. Which arrow across the bottom makes the square commute?

Choose one

7. Diagrams where paths agree

StretchHuman

Two squares are placed side by side, sharing a middle arrow. You are told that the outer rectangle commutes. What can you conclude?

Choose one

8. Diagrams where paths agree

StretchHuman

A function f:Z→Zf : \Z \to \Z preserves addition, and f(3)=12f(3) = 12. What is f(5)f(5)?

9. Diagrams where paths agree

CoreFormal

Which Lean statement says that converting metres to centimetres, x↦100xx \mapsto 100x, preserves addition?

Choose one

10. Diagrams where paths agree

StretchComputational

Casting out nines checks a multiplication with remainders on division by 99. Write digit_sum(n) (the sum of the decimal digits of a whole number n) and nines_check(a, b, claimed), which returns True when digit_sum(a) * digit_sum(b) and digit_sum(claimed) leave the same remainder on division by 99, and False otherwise. Can the check ever pass for a wrong answer?

Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Common misconceptionsH

Common misconceptions

Misconception

“The routes agree for one input, so the diagram commutes.” The routes x↦(x+1)2x \mapsto (x + 1)^2 and x↦x2+1x \mapsto x^2 + 1 agree at x=0x = 0, but at x=1x = 1 they give 44 and 22. A diagram commutes only if the routes agree for every input, which needs an argument (or, on a finite set, a check of every case).

Misconception

“If all the arrows can be drawn, the diagram commutes.” Drawing the arrows only says that the routes exist. Whether they agree is a separate question: the square with “add 11, then double” and “double, then add 11” is perfectly drawable and never commutes.

Misconception

“A commutative diagram means the functions commute with each other.” The word is borrowed from “commutative” as in ab=baab = ba, but a commuting square says that two routes agree, g(f(a))=k(h(a))g(f(a)) = k(h(a)), and its four functions can all be different. Only the special square with f,gf, g on one route and g,fg, f on the other says that ff and gg can be swapped.

Misconception

“A unit conversion preserves everything.” Converting metres to centimetres preserves addition but not multiplication: 1 m21\ \mathrm{m}^2 is 10 000 cm210\,000\ \mathrm{cm}^2. And Celsius to Fahrenheit does not even preserve addition, because of the +32+32.

ViewpointsH

Other ways of seeing

Algebra— Maps that respect structure

Functions that preserve an operation are called homomorphisms (“same shape”), and they are how algebraists compare one number system with another (see structure-preserving maps). Some of them change the operation: 2a+b=2a⋅2b2^{a + b} = 2^a \cdot 2^b turns addition into multiplication, and logarithms go back, log⁡(ab)=log⁡a+log⁡b\log(ab) = \log a + \log b. John Napier's tables of logarithms (1614) and the slide rules invented in the 1620s used this square for three centuries to turn hard multiplications into easy additions. Theorem 4 is a first classification theorem: the homomorphisms from (Z,+)(\Z, +) to itself are exactly the multiplications.

Number theory— Casting out nines

A number and the sum of its digits leave the same remainder on division by 99 (because 10,100,1000,…10, 100, 1000, \dots all leave remainder 11). And “take the remainder on division by 99” preserves multiplication, if we multiply remainders and reduce again. So the square “multiply, then reduce” = “reduce both, then multiply and reduce” gives a quick check of arithmetic. For 47×23=108147 \times 23 = 1081: the digit sums give 4+7=11→24 + 7 = 11 \to 2 and 2+3=52 + 3 = 5, and 2×5=10→12 \times 5 = 10 \to 1; also 1+0+8+1=10→11 + 0 + 8 + 1 = 10 \to 1. They match. A claimed answer of 10711071 (digit sum 9→09 \to 0) would be caught. But the check cannot catch every error — 18011801 passes too. The method was known to medieval arithmeticians writing in Arabic and is explained in Fibonacci's Liber Abaci (1202); see also clock arithmetic and check digits.

Physics— Units and scales

Physical laws must not depend on the units we measure in, which is a commuting-square requirement: compute in metres and convert, or convert and compute in feet — the answers must match. Conversions between length units are multiplications, so they preserve addition of lengths. Temperature scales are different: Celsius and Fahrenheit have different zero points, so the conversion C↦1.8 C+32C \mapsto 1.8\,C + 32 preserves neither addition nor doubling. That is why “twice as hot” makes no sense in °C or °F, and why physicists use the kelvin scale, whose zero is absolute zero, when they need to multiply or divide temperatures.

Geometry— Maps of maps

A map of a city at scale 1:50 0001 : 50\,000 shrinks every distance by the same factor, so it preserves adding distances along a route: walk 22 cm and then 33 cm on the map, and you have walked 5×50 0005 \times 50\,000 cm =2.5= 2.5 km in the city. Scaling preserves angles as well, so triangles on the map are similar to triangles in the city (see rigid motions, congruence and similarity). But it does not preserve areas: a park of 11 cm² on the map is 0.250.25 km² in real life, because both of its dimensions are scaled.

Category-theoretic connectionH

The language of category theory

Commutative diagrams are the everyday language of category theory, where they state equations between composites of arrows (see categories). A famous example is the naturality square. Suppose a translation η\eta turns objects of one kind into objects of another, and ff is a change on the first side with a matching change f′f' on the other side. Then η\eta is “natural” if translating and changing can be done in either order:

XX
X′X'
YY
Y′Y'
ηX\eta_X
ff
f′f'
ηY\eta_Y
A naturality square: translate then change, or change then translate.

Our VAT square is an example in spirit: converting currency is natural with respect to adding a percentage, but not with respect to adding a fixed fee unless the fee is converted too. And the pasting theorem is used constantly: big diagrams are proved to commute by breaking them into small squares and triangles, each of which commutes.

Wonder Trails

Wonder Trail

History & global context

History and global context

  • The idea that a calculation can be checked by doing it “downstairs”, with remainders, is old. Casting out nines was used by medieval arithmeticians writing in Arabic and explained by Leonardo of Pisa (Fibonacci) in Liber Abaci (1202).
  • John Napier published his tables of logarithms in 1614, and the slide rule followed in the 1620s, with William Oughtred among its inventors. Both rest on a square that turns multiplication into addition.
  • Diagrams of arrows that commute became a standard tool in algebraic topology in the 1940s and 1950s. Samuel Eilenberg and Saunders Mac Lane introduced categories in 1945, and Eilenberg and Norman Steenrod's book Foundations of Algebraic Topology (1952) used commutative diagrams throughout, helping to make them part of every mathematician's toolkit.
Further reading

Further reading

  • F. William Lawvere and Stephen H. Schanuel, Conceptual Mathematics: A First Introduction to Categories (2nd edition, 2009) — diagrams of sets and maps from the first chapter, for beginners.
  • Eugenia Cheng, How to Bake Pi: An Edible Exploration of the Mathematics of Mathematics (2015) — category theory for everyone.
  • Eugenia Cheng, The Joy of Abstraction: An Exploration of Math, Category Theory, and Life (2022) — a longer, gentle introduction with many diagrams.
  • David I. Spivak, Category Theory for the Sciences (2014) — diagrams as a modelling language.