Pigeonhole.lean
Proves the pigeonhole principle from scratch: you cannot injectively map n+1 items into n slots, so at least two must collide.
compress
A helper that removes one element from Fin (n+1), compressing the remaining elements into Fin n. Elements below the removed value keep their index; elements above shift down by 1.
private def compress {n : Nat} (v x : Fin (n + 1)) (h : x ≠ v) : Fin n :=
if hlt : x.val < v.val then
⟨x.val, by omega⟩
else
⟨x.val - 1, by ...⟩ Fin.no_injection
There is no injective function from Fin (n+1) to Fin n. Proved by induction on n with element removal at each step.
theorem Fin.no_injection (n : Nat)
: ∀ g : Fin (n + 1) → Fin n, ¬ Function.Injective g Base case: Fin 1 → Fin 0 is impossible since Fin 0 is empty. Inductive step: given g : Fin (k+2) → Fin (k+1), remove the image of the last element from the codomain. The compressed function g' : Fin (k+1) → Fin k inherits injectivity, contradicting the induction hypothesis.
pigeonhole
Among N+1 values in Fin N, at least two must collide. The collision gives specific indices i < j where f i = f j.
theorem pigeonhole {N : Nat} (f : Fin (N + 1) → Fin N)
: &exists; i j : Fin (N + 1), i < j ∧ f i = f j Uses Fin.no_injection by contradiction: if no collision existed, f would be injective, which is impossible.
pigeonhole_nat
A convenience wrapper for Nat-indexed sequences: among values f(0), ..., f(N), at least two in Fin N must collide.
Connections
- Stochasticity.lean — uses pigeonhole to get state collisions in bounded transducers
- Removal.lean — A3 and Co1 removal tests assume the collision that pigeonhole provides
- Axioms.lean — capacity_bound gives the finite state space that pigeonhole needs