1-- Counting is independent of a finite enumeration.2-- 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.Enumeration8import Set.Indicator9import ListSupport1011predicate DistinctValues (f n : Set) :=12∀ i ∈ n, ∀ j ∈ n, f[i] = f[j] → i = j1314predicate Occurs (f n x : Set) :=∃ i ∈ n, f[i] = x1516theorem membership.into_successor (x : Set, n : Nat)17requires before : x ∈ n18shows x ∈ succ(n)19proof20simp2122theorem DistinctValues.prefix (f : Set, n : Nat)23requires distinct : DistinctValues(f, succ(n))24shows DistinctValues(f, n)25proof26intros i hi j hj same27have iNext := membership.into_successor with hi28have jNext := membership.into_successor with hj29exact distinct with i, iNext, j, jNext, same3031theorem DistinctValues.last_fresh (f : Set, n : Nat)32requires distinct : DistinctValues(f, succ(n))33shows∀ i ∈ n, f[i] ≠ f[n]34proof35intros i hi same36have iNext := membership.into_successor with hi37have nNext := membership.self_successor at n38have equal := distinct with i, iNext, n, nNext, same39rw equal at hi40exact membership.irreflexive with hi4142theorem countMembers.absent (A f : Set, n : Nat)43shows (∀ i ∈ n, ¬(f[i] ∈ A)) → countMembers(A, f, n) =044proof45induction n46| zero =>47intro absent48rw countMembers49rfl50| succ(k) using ih =>51intro absent52haveprefix : ∀ i ∈ k, ¬(f[i] ∈ A) bysimp53have last := absent with k, membership.self_successor at k withassumption54have previous := ih withprefix55have value := indicator.absent with last56rw [countMembers, previous, value]57simp [add]5859theorem countMembers.singleton_one (f x : Set, n : Nat)60shows DistinctValues(f, n) → Occurs(f, n, x) → countMembers({x}, f, n) =161proof62induction n63| zero =>64intros distinct occurs65rcases occurs with⟨i, impossible, same⟩66exfalso67simp [nat.zero, set.empty]68| succ(k) using ih =>69intros distinct occurs70have alternatives : f[k] = x ∨ f[k] ≠ x bytauto71cases alternatives with last | other72 . have fresh := DistinctValues.last_fresh at f, k withassumption, distinct73have absent : ∀ i ∈ k, ¬(f[i] ∈ {x}) bysimp74have previous := countMembers.absent withassumption, absent75have member := singleton.membership.backward with last76have value := indicator.member with member77rw [countMembers, previous, value]78simp [add]79 . obtain⟨position, before, equal⟩:= Occurs.forward at f, succ(k), x with occurs80have shape := membership.successor_forward{n := k} with before81have earlier : position ∈ k bysimp82haveprefix:= DistinctValues.prefix withassumption, distinct83have occurrence : Occurs(f, k, x)84unfold Occurs85refine⟨position, earlier, equal⟩86have previous := ih withprefix, occurrence87have absent : ¬(f[k] ∈ {x}) bysimp88have value := indicator.absent with absent89rw [countMembers, previous, value]90simp [add.right_unit]9192-- The weighted equality matrix is symmetric. Its row sum selects a single93-- occurrence, so its two iterated sums count the same subset in either order.9495def matchWeight (A x y : Set) : Set:= mul(indicator(A, x), indicator({x}, y))9697theorem matchWeight.symmetric (A x y : Set)98shows matchWeight(A, x, y) = matchWeight(A, y, x)99proof100have alternatives : x = y ∨ x ≠ y bytauto101cases alternatives with same | different102 . rw same103rfl104 . have xy : ¬(y ∈ {x}) bysimp105have yx : ¬(x ∈ {y}) bysimp106have leftZero := indicator.absent with xy107have rightZero := indicator.absent with yx108simp [matchWeight, leftZero, rightZero, mul.right_zero]109110def matchRow (A f x : Set, n : Nat) →Set111| A, f, x, zero =>0112| A, f, x, succ(k) => add(matchRow(A, f, x, k), matchWeight(A, x, f[k]))113114def matchTotal (A f g : Set, n m : Nat) →Set115| A, f, g, n, zero =>0116| A, f, g, n, succ(k) => add(matchTotal(A, f, g, n, k), matchRow(A, f, g[k], n))117descends m118119theorem matchWeight.natural (A x y : Set)120showsNat(matchWeight(A, x, y))121proof122unfold matchWeight123typecheck124125theorem matchRow.natural (A f x : Set, n : Nat)126showsNat(matchRow(A, f, x, n))127proof128induction n129| zero =>130rw matchRow131typecheck132| succ(k) using ih =>133rw matchRow134typecheck135136theorem matchTotal.natural (A f g : Set, n m : Nat)137showsNat(matchTotal(A, f, g, n, m))138proof139induction m140| zero =>141rw matchTotal142typecheck143| succ(k) using ih =>144rw matchTotal145have value := matchRow.natural at A, f, g[k], n withassumption146typecheck147148theorem matchRow.factor (A f x : Set, n : Nat)149shows matchRow(A, f, x, n) = mul(indicator(A, x), countMembers({x}, f, n))150proof151induction n152| zero =>153rw [matchRow, countMembers]154simp [mul.right_zero]155| succ(k) using ih =>156rw [matchRow, countMembers, ih]157unfold matchWeight158have b := countMembers.natural at {x}, f, k withassumption159ring160161theorem matchTotal.empty_left (A f g : Set, m : Nat)162shows matchTotal(A, f, g, 0, m) =0163proof164induction m165| zero =>166rw matchTotal167rfl168| succ(k) using ih =>169rw [matchTotal, matchRow, ih]170simp [add]171172theorem matchTotal.extend_left (A f g : Set, n m : Nat)173shows matchTotal(A, f, g, succ(n), m) =174 add(matchTotal(A, f, g, n, m), matchRow(A, g, f[n], m))175proof176induction m177| zero =>178simp [matchTotal, matchRow, add]179| succ(k) using ih =>180rw [matchTotal, matchTotal, matchRow, matchRow, ih]181have symmetric := matchWeight.symmetric at A, g[k], f[n]182rw symmetric183have a := matchTotal.natural at A, f, g, n, k with*184have b := matchRow.natural at A, g, f[n], k withassumption185have c := matchRow.natural at A, f, g[k], n withassumption186have d := matchWeight.natural at A, f[n], g[k]187exact add.four_shuffle with a, b, c, d188189theorem matchTotal.transpose (A f g : Set, m n : Nat)190shows matchTotal(A, f, g, n, m) = matchTotal(A, g, f, m, n)191proof192induction n193| zero =>194rw [matchTotal.empty_left, matchTotal]195rfl196| succ(k) using ih =>197rw [matchTotal.extend_left, matchTotal, ih]198rfl199200theorem matchTotal.count (A f g : Set, n m : Nat)201requires distinct : DistinctValues(f, n)202shows (∀ j ∈ m, Occurs(f, n, g[j])) →203 matchTotal(A, f, g, n, m) = countMembers(A, g, m)204proof205induction m206| zero =>207intro covered208simp [matchTotal, countMembers]209| succ(k) using ih =>210intro covered211haveprefix : ∀ j ∈ k, Occurs(f, n, g[j]) bysimp212have last := covered with k, membership.self_successor at k withassumption213have singletonCount := countMembers.singleton_one withassumption, distinct, last214have factored := matchRow.factor at A, f, g[k], n withassumption215rw singletonCount at factored216have previous := ih withprefix217rw [matchTotal, countMembers, previous, factored]218simp [mul.right_unit]219220theorem countMembers.same_entries (A f g : Set, n m : Nat)221requires distinctF : DistinctValues(f, n)222requires distinctG : DistinctValues(g, m)223requires coveredF : ∀ i ∈ n, Occurs(g, m, f[i])224requires coveredG : ∀ j ∈ m, Occurs(f, n, g[j])225shows countMembers(A, f, n) = countMembers(A, g, m)226proof227haveleft:= Enumeration.matchTotal.count at A, g, f, m, n with*228haveright:= Enumeration.matchTotal.count at A, f, g, n, m with*229have transpose := Enumeration.matchTotal.transpose at A, f, g, m, n with*230rw [←left, ←right]231 symm232exact transpose233234theorem Injective.distinct_values (f X V : Set)235requires injective : InjectiveBetween(f, X, V)236shows DistinctValues(f, X)237proof238rcases injective with⟨fn, unique⟩239intros i hi j hj equal240have value := FunctionBetween.apply_closed with fn, hi241haveleft:= FunctionBetween.relates_apply with fn, hi242haveright:= FunctionBetween.relates_apply with fn, hj243rw← equal atright244exact unique with i, hi, j, hj, f[i], value, left, right245246theorem Surjective.occurs (f X V x : Set)247requires surjective : SurjectiveBetween(f, X, V)248requires member : x ∈ V249shows Occurs(f, X, x)250proof251rcases surjective with⟨fn, onto⟩252obtain⟨i, hi, related⟩:= onto with x, member253have equal := FunctionBetween.apply_value with fn, hi, related254unfold Occurs255refine⟨i, hi, equal⟩256257theorem countMembers.reindex (A V f g : Set, n m : Nat)258requires enumerationF : BijectiveBetween(f, n, V)259requires enumerationG : BijectiveBetween(g, m, V)260shows countMembers(A, f, n) = countMembers(A, g, m)261proof262have injF := Bijective.injective with enumerationF263have injG := Bijective.injective with enumerationG264have surjF := Bijective.surjective with enumerationF265have surjG := Bijective.surjective with enumerationG266have fnF := Injective.function with injF267have fnG := Injective.function with injG268have distinctF := Injective.distinct_values with injF269have distinctG := Injective.distinct_values with injG270have coveredF : ∀ i ∈ n, Occurs(g, m, f[i])271intros i hi272have value := FunctionBetween.apply_closed with fnF, hi273exact Surjective.occurs with surjG, value274have coveredG : ∀ j ∈ m, Occurs(f, n, g[j])275intros j hj276have value := FunctionBetween.apply_closed with fnG, hj277exact Surjective.occurs with surjF, value278exact countMembers.same_entries with distinctF, distinctG, coveredF, coveredG279280theorem countMembers.all (A f : Set, n : Nat)281shows (∀ i ∈ n, f[i] ∈ A) → countMembers(A, f, n) = n282proof283induction n284| zero =>285intro covered286rw countMembers287rfl288| succ(k) using ih =>289intro covered290haveprefix : ∀ i ∈ k, f[i] ∈ A bysimp291have last := covered with k, membership.self_successor at k withassumption292have value := indicator.member with last293have previous := ih withprefix294rw [countMembers, previous, value]295exact add.right_one withassumption296297theorem Bijective.natural_domain_unique (V f g : Set, n m : Nat)298requires enumerationF : BijectiveBetween(f, n, V)299requires enumerationG : BijectiveBetween(g, m, V)300shows n = m301proof302have injF := Bijective.injective with enumerationF303have injG := Bijective.injective with enumerationG304have fnF := Injective.function with injF305have fnG := Injective.function with injG306have coveredF : ∀ i ∈ n, f[i] ∈ V307intros i hi308exact FunctionBetween.apply_closed with fnF, hi309have coveredG : ∀ j ∈ m, g[j] ∈ V310intros j hj311exact FunctionBetween.apply_closed with fnG, hj312have countF := countMembers.all with coveredF313have countG := countMembers.all with coveredG314have equal := countMembers.reindex at V, V, f, g, n, m with*315 rwa [countF, countG] at equal316317theorem HasCardinality.unique (V n m : Set)318requires first : HasCardinality(V, n)319requires second : HasCardinality(V, m)320shows n = m321proof322rcases first with⟨naturalN, f, forwardF⟩323rcases second with⟨naturalM, g, forwardG⟩324have inverseF := converse.bijective with forwardF325have inverseG := converse.bijective with forwardG326exact Bijective.natural_domain_unique with naturalN, naturalM, inverseF, inverseG327328theorem Bijective.values (f X V : Set)329requires enumeration : BijectiveBetween(f, X, V)330shows∀ i ∈ X, f[i] ∈ V331proof332have injective := Bijective.injective with enumeration333have fn := Injective.function with injective334intros i hi335exact FunctionBetween.apply_closed with fn, hi336337-- Finite cardinality has a canonical value because its witness is unique.338-- The correctness law requires finiteness.339defunique cardinality (A : Set) (n ∈ ℕ) := HasCardinality(A, n)340requires finite : Finite(A)341proof342rcases finite with⟨n, natural, equivalent⟩343witness n344constructor345 . exact nat.omega.forward at n with natural346 . unfold HasCardinality347refine⟨natural, equivalent⟩348349uniqueness350intros n nMember first m mMember second351exact HasCardinality.unique with first, second352353theorem cardinality.correct (A : Set)354requires finite : Finite(A)355shows HasCardinality(A, cardinality(A))356proof357simp [cardinality.selected]358359theorem cardinality.eq_of_has (A n : Set)360requires given : HasCardinality(A, n)361shows cardinality(A) = n362proof363have finite := Finite.from_cardinality with given364have correct := cardinality.correct with finite365exact HasCardinality.unique with correct, given366367theorem cardinality.natural (n : Nat)368shows cardinality(n) = n369proof370have own : HasCardinality(n, n)371unfold HasCardinality372refine⟨assumption, Equipotent.reflexive at n⟩373exact cardinality.eq_of_has with own374375theorem cardinality.singleton (x : Set)376shows cardinality({x}) =1377proof378have one : HasCardinality({x}, 1)379constructor380 . exact Naturals.constructor.succ at0with Naturals.constructor.zero381 . exact Equipotent.singleton_one at x382exact cardinality.eq_of_has with one383384theorem cardinality.empty385shows cardinality(∅) =0386proof387exact cardinality.eq_of_has with HasCardinality.empty_set388