1-- Counting functions: a set of size m has n ^ m maps into a set of size n,2-- by splitting a function on insert(a, A) into its restriction to A and its3-- value at a; words of length m over an alphabet are functions on the4-- numeral m5-- 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.Functions11import Binomial1213theorem functionSpace.finite (A B : Set)14requires finiteA : Finite(A)15requires finiteB : Finite(B)16shows Finite(functionSpace(A, B))17proof18have product := Finite.product with finiteA, finiteB19have powers := Finite.powerset with product20exact Finite.subset with powers, (functionSpace.subset_powerset at A, B)2122theorem functionSpace.empty_domain_count (B : Set)23shows cardinality(functionSpace(∅, B)) =124proof25rw functionSpace.empty_domain26exact cardinality.singleton at∅2728theorem functionSpace.empty_codomain_count (A : Set)29requires nonempty : Nonempty(A)30shows cardinality(functionSpace(A, ∅)) =031proof32have empty := functionSpace.empty_codomain with nonempty33rw empty34exact cardinality.empty3536theorem insert.subset_self (A a : Set)37shows A ⊆ insert(a, A)38proof39intros x hx40exact insert.contains with hx4142-- A function on insert(a, A) is its restriction to A together with its43-- value at a.44defgraph functionSplit (A B a : Set) (f ∈ functionSpace(insert(a, A), B)) : functionSpace(A, B) × B :=45 (restrict(f, A), f(a))46proof47have function := functionSpace.mem_iff.forward with member48have subset := insert.subset_self at A, a49have restricted := restrict.domain_function with function, subset50have value := FunctionBetween.apply_closed with51 function, (insert.self at a, A)52apply product.pair53 . exact functionSpace.mem_iff.backward with restricted54 . exact value5556theorem functionSplit.injective (A B a : Set)57shows58 InjectiveBetween(functionSplit(A, B, a), functionSpace(insert(a, A), B), functionSpace(A, B) × B)59proof60have function := functionSplit.function at A, B, a61have subset := insert.subset_self at A, a62apply Injective.of_pointwise with function63intros f hf g hg same64have valueF := functionSplit.value at A, B, a, f with hf65have valueG := functionSplit.value at A, B, a, g with hg66rw [valueF, valueG] at same67have parts := orderedPair.injective with same68have fFunction := functionSpace.mem_iff.forward with hf69have gFunction := functionSpace.mem_iff.forward with hg70apply FunctionBetween.ext with fFunction, gFunction71intros x hx72havesplit:= insert.membership.forward with hx73casessplitwith isA | inA74 . rw isA75exact parts.right76 . have restrictF := restrict.domain_apply with fFunction, subset, inA77have restrictG := restrict.domain_apply with gFunction, subset, inA78rw [← restrictF, ← restrictG, parts.left]79rfl8081theorem functionSplit.adjoin_member (A B a g b : Set)82requires fresh : ¬a ∈ A83requires hg : g ∈ functionSpace(A, B)84requires hb : b ∈ B85shows adjoinMap(g, a, b) ∈ functionSpace(insert(a, A), B)86proof87have gFunction := functionSpace.mem_iff.forward with hg88have extended := adjoinMap.function at g, A, B, a, b with gFunction, fresh89have absorb := insert.eq_of_member with hb90rw absorb at extended91exact functionSpace.mem_iff.backward with extended9293theorem functionSplit.adjoin_value (A B a g b : Set)94requires fresh : ¬a ∈ A95requires hg : g ∈ functionSpace(A, B)96requires hb : b ∈ B97shows functionSplit(A, B, a)(adjoinMap(g, a, b)) = (g, b)98proof99have subset := insert.subset_self at A, a100have gFunction := functionSpace.mem_iff.forward with hg101have inSpace := functionSplit.adjoin_member with fresh, hg, hb102have extended := functionSpace.mem_iff.forward with inSpace103have value := functionSplit.value at A, B, a, adjoinMap(g, a, b) with inSpace104have valueA : adjoinMap(g, a, b)(a) = b105exact FunctionBetween.apply_value with extended, (insert.self at a, A), (adjoinMap.relates_new at g, a, b)106have restricted : restrict(adjoinMap(g, a, b), A) = g107have restrictFunction := restrict.domain_function with extended, subset108apply FunctionBetween.ext with restrictFunction, gFunction109intros x hx110have step := restrict.domain_apply with extended, subset, hx111rw step112have related := adjoinMap.relates_old at g, a, b, x, g(x) with (FunctionBetween.relates_apply with gFunction, hx)113exact FunctionBetween.apply_value with extended, (subset with x, hx), related114rw [value, restricted, valueA]115rfl116117theorem functionSplit.surjective (A B a : Set)118requires fresh : ¬a ∈ A119shows120 SurjectiveBetween(functionSplit(A, B, a), functionSpace(insert(a, A), B), functionSpace(A, B) × B)121proof122have function := functionSplit.function at A, B, a123unfold SurjectiveBetween124refine⟨function, ?_⟩125intros p hp126obtain⟨bound, g, hg, b, hb, shape⟩:= product.membership.forward with hp127have inSpace := functionSplit.adjoin_member with fresh, hg, hb128have target := functionSplit.adjoin_value with fresh, hg, hb129refine⟨adjoinMap(g, a, b), inSpace, ?_⟩130rw [shape, ← target]131exact FunctionBetween.relates_apply with function, inSpace132133theorem functionSplit.bijective (A B a : Set)134requires fresh : ¬a ∈ A135shows136 BijectiveBetween(functionSplit(A, B, a), functionSpace(insert(a, A), B), functionSpace(A, B) × B)137proof138have injective := functionSplit.injective at A, B, a139have surjective := functionSplit.surjective at A, B, a with fresh140exact⟨injective, surjective⟩141142theorem functionSpace.insert_equipotent (A B a : Set)143requires fresh : ¬a ∈ A144shows functionSpace(insert(a, A), B) ≃ functionSpace(A, B) × B145proof146witness functionSplit(A, B, a)147exact functionSplit.bijective with fresh148149-- The number of functions from an m-element set to an n-element set.150theorem functionSpace.cardinality (m : Nat)151shows∀ A, ∀ B, ∀ n, Nat(n) → HasCardinality(A, m) → HasCardinality(B, n) →152 HasCardinality(functionSpace(A, B), n ^ m)153proof154induction m155| zero =>156intros A B n nNat countedA countedB157have empty := HasCardinality.empty_of_zero at A with countedA158rw [empty, functionSpace.empty_domain, pow.zero]159constructor160 . exact Naturals.constructor.succ at0with Naturals.constructor.zero161 . exact Equipotent.singleton_one at∅162| k +1using ih =>163intros A B n nNat countedA countedB164have hk : k +1= succ(k) := add.right_one with*165rw hk at countedA166obtain⟨a, member⟩:= HasCardinality.exists_member with countedA167have rest := HasCardinality.remove at A, a, k with countedA, member168have fresh : ¬a ∈ A ∖ {a} bysimp [difference.membership, singleton.membership]169have restored := insert.restore with member170have restCount := ih with A ∖ {a}, B, n, nNat, rest, countedB171have product := HasCardinality.product with restCount, countedB172havesplit:= functionSpace.insert_equipotent at A ∖ {a}, B, a with fresh173rw restored atsplit174have powNat := pow.closed at n, k175have shape : n ^ (k +1) = mul(n ^ k, n)176rw [hk, pow.succ]177ring178rw shape179constructor180 . exact HasCardinality.natural with product181 . exact Equipotent.transitive withsplit, (HasCardinality.equipotent with product)182183theorem functionSpace.count (A B : Set)184requires finiteA : Finite(A)185requires finiteB : Finite(B)186shows cardinality(functionSpace(A, B)) = cardinality(B) ^ cardinality(A)187proof188have countedA := cardinality.correct with finiteA189have countedB := cardinality.correct with finiteB190have natA := cardinality.nat with finiteA191have natB := cardinality.nat with finiteB192have all := functionSpace.cardinality at cardinality(A)193have counted := all with A, B, cardinality(B), natB, countedA, countedB194exact cardinality.eq_of_has with counted195196theorem functionSpace.self_count (A : Set)197requires finite : Finite(A)198shows cardinality(functionSpace(A, A)) = cardinality(A) ^ cardinality(A)199proof200exact functionSpace.count with finite, finite201202theorem pow.one_base (m : Nat)203shows1 ^ m =1204proof205induction m206| zero =>exact pow.zero at1207| k +1using ih =>208have hk : k +1= succ(k) := add.right_one with*209rw [hk, pow.succ, ih]210compute211212theorem functionSpace.singleton_codomain_count (A y : Set)213requires finite : Finite(A)214shows cardinality(functionSpace(A, {y})) =1215proof216have count := functionSpace.count with finite, (Finite.singleton at y)217rw [count, cardinality.singleton]218have natA := cardinality.nat with finite219exact pow.one_base at cardinality(A)220221-- Functions into a two-element set are as many as subsets.222theorem functionSpace.two_count (A : Set)223requires finite : Finite(A)224shows cardinality(functionSpace(A, 2)) =2 ^ cardinality(A)225proof226have two : Nat(2) bytypecheck227have count := functionSpace.count with finite, (Finite.natural at2)228rw [count, cardinality.natural]229rfl230231theorem functionSpace.two_equipotent_powerset (A : Set)232requires finite : Finite(A)233shows functionSpace(A, 2) ≃𝒫(A)234proof235have two : Nat(2) bytypecheck236have finiteSpace := functionSpace.finite with finite, (Finite.natural at2)237have finitePower := Finite.powerset with finite238have same : cardinality(functionSpace(A, 2)) = cardinality(𝒫(A))239haveleft:= functionSpace.two_count with finite240haveright:= powerset.count with finite241rw [left, right]242rfl243exact cardinality.equipotent_of_eq with finiteSpace, finitePower, same244245-- Words of length m over an alphabet are functions on the numeral m.246def words (A : Set, m : Nat) : Set:= functionSpace(m, A)247248theorem words.membership (w A : Set, m : Nat)249shows w ∈ words(A, m) ↔ w : m → A250proof251simp [words, functionSpace.mem_iff]252253theorem words.finite (A : Set, m : Nat)254requires finite : Finite(A)255shows Finite(words(A, m))256proof257unfold words258exact functionSpace.finite with (Finite.natural at m), finite259260theorem words.zero (A : Set)261shows words(A, 0) = {∅}262proof263unfold words264have shape := functionSpace.empty_domain at A265rw nat.zero266exact shape267268theorem words.count (A : Set, m : Nat)269requires finite : Finite(A)270shows cardinality(words(A, m)) = cardinality(A) ^ m271proof272unfold words273have count := functionSpace.count with (Finite.natural at m), finite274rw [count, cardinality.natural]275rfl276277theorem words.binary_count (m : Nat)278shows cardinality(words(2, m)) =2 ^ m279proof280have two : Nat(2) bytypecheck281have count := words.count at2, m with (Finite.natural at2)282rw [count, cardinality.natural]283rfl284285theorem words.letter (w A x : Set, m : Nat)286requires word : w ∈ words(A, m)287requires position : x ∈ m288shows w(x) ∈ A289proof290have function := words.membership.forward with word291exact FunctionBetween.apply_closed with function, position292