1-- Countability and Cantor's diagonal theorem2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.Cardinal.Countable8import Finite910-- A set is countable when it injects into the natural numbers. This includes11-- finite sets and gives the usual "at most countable" convention.12predicate Countable (A : Set) :=∃ f, InjectiveBetween(f, A, ℕ)13predicate Uncountable (A : Set) :=¬Countable(A)1415-- The diagonal subset associated with a proposed enumeration of P(A).16def cantorDiagonal (f A : Set) : Set:=17 { x ∈ A |¬(x ∈ f(x)) }1819theorem cantorDiagonal.subset (f A : Set)20shows cantorDiagonal(f, A) ⊆ A21proof22simp2324theorem cantorDiagonal.in_powerset (f A : Set)25shows cantorDiagonal(f, A) ∈𝒫(A)26proof27simp [Subset, set.powerset, cantorDiagonal.subset]2829-- Cantor's theorem in its graph-theoretic form: no set-valued function from A30-- onto its powerset exists. The proof is the literal diagonal argument.31theorem Cantor.no_surjection_onto_powerset (f A : Set)32shows¬SurjectiveBetween(f, A, 𝒫(A))33proof34intro surjective35rcases surjective with⟨function, onto⟩36have diagonalInPower := cantorDiagonal.in_powerset at f, A37specialize onto with cantorDiagonal(f, A), diagonalInPower38obtain⟨d, dInA, mapsToDiagonal⟩:= onto39have value := FunctionBetween.apply_value with function, dInA, mapsToDiagonal40have diagonalShape := cantorDiagonal.membership at f, A, d41have membershipCases : d ∈ cantorDiagonal(f, A) ∨¬(d ∈ cantorDiagonal(f, A)) bytauto42cases membershipCases with diagonal | notDiagonal43 . have shape := diagonalShape.forward with diagonal44rcases shape with⟨dInAAgain, notInValue⟩45rw value at notInValue46exact notInValue with diagonal47 . apply notDiagonal48apply diagonalShape.backward49constructor50 . exact dInA51 . rw value52exact notDiagonal5354theorem powerset.not_equipotent (A : Set)55shows¬(A ≃𝒫(A))56proof57intro equivalent58obtain⟨f, bijective⟩:= equivalent59have surjective := Bijective.surjective with bijective60exact Cantor.no_surjection_onto_powerset with surjective6162-- The injection form of Cantor's theorem for the naturals. Given a proposed63-- code f : P(N) → N, diagonalize at the code assigned to the diagonal set.64def countableDiagonal (f : Set) : Set:=65 { n ∈ ℕ |∃ X ∈𝒫(ℕ), relates(f, X, n) ∧¬(n ∈ X) }6667theorem countableDiagonal.subset (f : Set)68shows countableDiagonal(f) ⊆ ℕ69proof70simp7172theorem powerset.naturals_not_injects_into_naturals (f : Set)73shows¬InjectiveBetween(f, 𝒫(ℕ), ℕ)74proof75intro injection76rcases injection with⟨function, oneToOne⟩77have diagonalSubset := countableDiagonal.subset at f78have diagonalInPower :=set.powerset.backward at countableDiagonal(f), ℕ with79 diagonalSubset80obtain⟨d, dInN, diagonalMaps⟩:= FunctionBetween.exists_value with function, diagonalInPower81havecases : d ∈ countableDiagonal(f) ∨¬(d ∈ countableDiagonal(f)) bytauto82casescaseswith member | missing83 . have data := countableDiagonal.membership.forward at84 f, d with member85rcases data with⟨valueNatural, X, xInPower, xMaps, valueMissingX⟩86have sameSet := oneToOne with87 X, xInPower, countableDiagonal(f), diagonalInPower,88 d, dInN,89 xMaps, diagonalMaps90apply valueMissingX91 rwa sameSet92 . apply missing93apply countableDiagonal.membership.backward94constructor95 . exact dInN96 . witness countableDiagonal(f)97constructor98 . exact diagonalInPower99 . constructor100 . exact diagonalMaps101 . exact missing102103theorem powerset.naturals_uncountable104shows Uncountable(𝒫(ℕ))105proof106unfold Uncountable107intro countable108obtain⟨f, injection⟩:= countable109exact powerset.naturals_not_injects_into_naturals with injection110