1-- The pigeonhole principle for finite sets: an injection never shrinks a set,2-- a surjection never grows one, a function from a larger set into a smaller3-- one collides somewhere, and between finite sets of the same size injective,4-- surjective, and bijective coincide5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Combinatorics.Pigeonhole11import InclusionExclusion1213theorem Injective.apply_ne (f A B x y : Set)14requires injective : InjectiveBetween(f, A, B)15requires hx : x ∈ A16requires hy : y ∈ A17requires different : x ≠ y18shows f(x) ≠ f(y)19proof20intro same21apply different22exact Injective.apply_cancel with injective, hx, hy, same2324theorem Surjective.image_full (f A B : Set)25requires surjective : SurjectiveBetween(f, A, B)26shows functionImage(f, A, B) = B27proof28have function := Surjective.function with surjective29apply Subset.antisymmetric with (functionImage.subset at f, A, B)30intros y hy31obtain⟨x, hx, related⟩:= surjective.right with y, hy32have value := FunctionBetween.apply_value with function, hx, related33apply functionImage.membership.backward34refine⟨hy, x, hx, ?_⟩35 symm36exact value3738theorem Surjective.of_image_full (f A B : Set)39requires function : f : A → B40requires full : functionImage(f, A, B) = B41shows SurjectiveBetween(f, A, B)42proof43unfold SurjectiveBetween44refine⟨function, ?_⟩45intros y hy46rw← full at hy47obtain⟨inB, x, hx, shape⟩:= functionImage.membership.forward with hy48refine⟨x, hx, ?_⟩49rw shape50exact FunctionBetween.relates_apply with function, hx5152theorem Injective.image_count (f A B : Set)53requires injective : InjectiveBetween(f, A, B)54requires finite : Finite(A)55shows cardinality(functionImage(f, A, B)) = cardinality(A)56proof57exact cardinality.injective_image with injective, (Subset.reflexive at A), finite5859theorem Injective.finite_domain (f A B : Set)60requires injective : InjectiveBetween(f, A, B)61requires finite : Finite(B)62shows Finite(A)63proof64have dominated := Dominated.of_injective with injective65exact Finite.of_dominated with finite, dominated6667-- An injection never shrinks a finite set.68theorem Injective.cardinality_le (f A B : Set)69requires injective : InjectiveBetween(f, A, B)70requires finite : Finite(B)71shows cardinality(A) ≤ cardinality(B)72proof73have finiteA := Injective.finite_domain with injective, finite74have image := Injective.image_count with injective, finiteA75have bound := cardinality.monotone with76 finite, (functionImage.subset at f, A, B)77rw image at bound78exact bound7980theorem Dominated.cardinality_le (A B : Set)81requires dominated : A ≼ B82requires finite : Finite(B)83shows cardinality(A) ≤ cardinality(B)84proof85obtain⟨f, injective⟩:= dominated86exact Injective.cardinality_le with injective, finite8788theorem Surjective.finite_codomain (f A B : Set)89requires surjective : SurjectiveBetween(f, A, B)90requires finite : Finite(A)91shows Finite(B)92proof93have function := Surjective.function with surjective94have full := Surjective.image_full with surjective95have finiteImage := Finite.function_image with96 function, finite, (Subset.reflexive at A)97rw full at finiteImage98exact finiteImage99100-- A surjection never grows a finite set.101theorem Surjective.cardinality_ge (f A B : Set)102requires surjective : SurjectiveBetween(f, A, B)103requires finite : Finite(A)104shows cardinality(B) ≤ cardinality(A)105proof106have function := Surjective.function with surjective107have full := Surjective.image_full with surjective108have bound := cardinality.image_le with109 function, (Subset.reflexive at A), finite110rw full at bound111exact bound112113-- The pigeonhole principle: more pigeons than holes forces a shared hole.114theorem pigeonhole.not_injective (f A B : Set)115requires function : f : A → B116requires finite : Finite(B)117requires more : cardinality(B) < cardinality(A)118shows¬InjectiveBetween(f, A, B)119proof120intro injective121have bound := Injective.cardinality_le with injective, finite122have natA := cardinality.nat with (Injective.finite_domain with123 injective, finite)124have natB := cardinality.nat with finite125have strict := Less.transitive_LessEqual with more, bound126exact Less.irreflexive at cardinality(B) with strict127128theorem pigeonhole.collision (f A B : Set)129requires function : f : A → B130requires finite : Finite(B)131requires more : cardinality(B) < cardinality(A)132shows∃ x ∈ A, ∃ y ∈ A, x ≠ y ∧ f(x) = f(y)133proof134by_contra none135have cancel : ∀ x ∈ A, ∀ y ∈ A, f(x) = f(y) → x = y136intros x hx y hy same137by_contra different138apply none139exact⟨x, hx, y, hy, different, same⟩140have injective := Injective.of_pointwise with function, cancel141exact pigeonhole.not_injective with function, finite, more, injective142143theorem pigeonhole.successor (f : Set) (n : Nat)144shows¬InjectiveBetween(f, n +1, n)145proof146intro injective147have bound := Injective.cardinality_le with injective, (Finite.natural at n)148have one : n +1= succ(n) := add.right_one with*149have sizeSucc := cardinality.natural at succ(n)150have size := cardinality.natural at n151rw one at bound152rw [sizeSucc, size] at bound153arith154155theorem pigeonhole.not_dominated (n : Nat)156shows¬(n +1 ≼ n)157proof158intro dominated159obtain⟨f, injective⟩:= dominated160exact pigeonhole.successor at f, n with injective161162theorem pigeonhole.not_equipotent (n : Nat)163shows¬(n +1≃ n)164proof165intro equipotent166have dominated := Dominated.of_equipotent with equipotent167exact pigeonhole.not_dominated at n with dominated168169-- Two naturals are equipotent exactly when they are equal.170theorem natural.equipotent_iff (m n : Nat)171shows m ≃ n ↔ m = n172proof173constructor174 . intro equipotent175have counted : HasCardinality(m, n) :=⟨assumption, equipotent⟩176have size := cardinality.eq_of_has with counted177have own := cardinality.natural at m178rw own at size179exact size180 . intro equal181rw equal182exact Equipotent.reflexive at n183184theorem natural.subset_of_le (m d : Nat)185shows m ⊆ m + d186proof187induction d188| zero =>189have shape : m +0= m byring190rw shape191exact Subset.reflexive at m192| k +1using ih =>193have shape : m + (k +1) = succ(m + k) byring194rw shape195intros x hx196have inside := ih with x, hx197have sumNat : Nat(m + k) bytypecheck198exact membership.into_successor at x, m + k with inside199200theorem natural.subset_of_LessEqual (m n : Nat)201requires le : m ≤ n202shows m ⊆ n203proof204obtain⟨d, dNat, shape⟩:= le205rw← shape206exact natural.subset_of_le at m, d207208theorem Dominated.of_cardinality_le (A B : Set)209requires finiteA : Finite(A)210requires finiteB : Finite(B)211requires le : cardinality(A) ≤ cardinality(B)212shows A ≼ B213proof214have natA := cardinality.nat with finiteA215have natB := cardinality.nat with finiteB216have countedA := HasCardinality.equipotent with (cardinality.correct with217 finiteA)218have countedB := HasCardinality.equipotent with (cardinality.correct with219 finiteB)220have subset := natural.subset_of_LessEqual with le221have first := Dominated.of_equipotent with countedA222have second := Dominated.of_subset with subset223have third := Dominated.of_equipotent with (Equipotent.symmetric with224 countedB)225exact Dominated.transitive with first, (Dominated.transitive with second, third)226227theorem Dominated.iff_cardinality_le (A B : Set)228requires finiteA : Finite(A)229requires finiteB : Finite(B)230shows A ≼ B ↔ cardinality(A) ≤ cardinality(B)231proof232constructor233 . intro dominated234exact Dominated.cardinality_le with dominated, finiteB235 . intro le236exact Dominated.of_cardinality_le with finiteA, finiteB, le237238-- Between finite sets of the same size, a surjection is injective.239theorem Finite.injective_of_surjective (f A B : Set)240requires surjective : SurjectiveBetween(f, A, B)241requires finite : Finite(A)242requires same : cardinality(A) = cardinality(B)243shows InjectiveBetween(f, A, B)244proof245have function := Surjective.function with surjective246have full := Surjective.image_full with surjective247have whole := Subset.reflexive at A248apply Injective.of_pointwise with function249intros x hx y hy equal250have imageCount : cardinality(functionImage(f, A, B)) = cardinality(A)251rw [full, same]252rfl253exact cardinality.injective_of_image with function, whole, finite, imageCount, hx, hy, equal254255-- Between finite sets of the same size, an injection is surjective.256theorem Finite.surjective_of_injective (f A B : Set)257requires injective : InjectiveBetween(f, A, B)258requires finite : Finite(B)259requires same : cardinality(A) = cardinality(B)260shows SurjectiveBetween(f, A, B)261proof262have function := Injective.function with injective263have finiteA := Injective.finite_domain with injective, finite264have image := Injective.image_count with injective, finiteA265rw same at image266have full := cardinality.eq_subset with267 finite, (functionImage.subset at f, A, B), image268exact Surjective.of_image_full with function, full269270theorem Finite.bijective_of_injective (f A B : Set)271requires injective : InjectiveBetween(f, A, B)272requires finite : Finite(B)273requires same : cardinality(A) = cardinality(B)274shows BijectiveBetween(f, A, B)275proof276have surjective := Finite.surjective_of_injective with injective, finite, same277exact⟨injective, surjective⟩278279theorem Finite.bijective_of_surjective (f A B : Set)280requires surjective : SurjectiveBetween(f, A, B)281requires finite : Finite(A)282requires same : cardinality(A) = cardinality(B)283shows BijectiveBetween(f, A, B)284proof285have injective := Finite.injective_of_surjective with surjective, finite, same286exact⟨injective, surjective⟩287288theorem Finite.injective_iff_surjective (f A B : Set)289requires function : f : A → B290requires finiteA : Finite(A)291requires finiteB : Finite(B)292requires same : cardinality(A) = cardinality(B)293shows InjectiveBetween(f, A, B) ↔ SurjectiveBetween(f, A, B)294proof295constructor296 . intro injective297exact Finite.surjective_of_injective with injective, finiteB, same298 . intro surjective299exact Finite.injective_of_surjective with surjective, finiteA, same300301theorem Finite.injective_iff_bijective (f A B : Set)302requires finiteB : Finite(B)303requires same : cardinality(A) = cardinality(B)304shows InjectiveBetween(f, A, B) ↔ BijectiveBetween(f, A, B)305proof306constructor307 . intro injective308exact Finite.bijective_of_injective with injective, finiteB, same309 . intro bijective310exact Bijective.injective with bijective311312theorem Finite.surjective_iff_bijective (f A B : Set)313requires finiteA : Finite(A)314requires same : cardinality(A) = cardinality(B)315shows SurjectiveBetween(f, A, B) ↔ BijectiveBetween(f, A, B)316proof317constructor318 . intro surjective319exact Finite.bijective_of_surjective with surjective, finiteA, same320 . intro bijective321exact Bijective.surjective with bijective322323-- Self-maps of a finite set.324theorem Finite.self_injective_bijective (f A : Set)325requires injective : InjectiveBetween(f, A, A)326requires finite : Finite(A)327shows BijectiveBetween(f, A, A)328proof329have same : cardinality(A) = cardinality(A) byrfl330exact Finite.bijective_of_injective with injective, finite, same331332theorem Finite.self_surjective_bijective (f A : Set)333requires surjective : SurjectiveBetween(f, A, A)334requires finite : Finite(A)335shows BijectiveBetween(f, A, A)336proof337have same : cardinality(A) = cardinality(A) byrfl338exact Finite.bijective_of_surjective with surjective, finite, same339340-- A collision shrinks the image.341theorem pigeonhole.image_strict (f A B x y : Set)342requires function : f : A → B343requires finite : Finite(A)344requires hx : x ∈ A345requires hy : y ∈ A346requires different : x ≠ y347requires same : f(x) = f(y)348shows cardinality(functionImage(f, A, B)) < cardinality(A)349proof350have whole := Subset.reflexive at A351have bound := cardinality.image_le with function, whole, finite352have natImage := cardinality.nat with (Finite.function_image with353 function, finite, whole)354have natA := cardinality.nat with finite355have notFull : cardinality(functionImage(f, A, B)) ≠ cardinality(A)356intro full357apply different358exact cardinality.injective_of_image with function, whole, finite, full, hx, hy, same359have alternatives := Less.trichotomy at cardinality(functionImage(f, A, B)), cardinality(A) with natImage, natA360rcases alternatives with less | equal | greater361 . exact less362 . exfalso363exact notFull with equal364 . exfalso365have strict := Less.transitive_LessEqual with greater, bound366exact Less.irreflexive at cardinality(A) with strict367