1-- Occurrences of an element in a list: the count, its interaction with2-- concatenation, reversal, filtering, and constant lists, and positivity3-- as membership in the support4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.List.Count10import Filter1112def listCount {A : Set} (x : Set) (xs : List(A)) →Set13| x, List.nil =>014| x, List.cons(a, tail) => add(indicator({x}, a), listCount(x, tail))15descends xs1617theorem listCount.nil (A x : Set)18shows listCount{A}(x, []) =019proof20simp [listCount]2122theorem listCount.cons (A x a : Set) (xs : List(A))23requires element : a ∈ A24shows listCount{A}(x, a :: xs) = indicator({x}, a) + listCount{A}(x, xs)25proof26simp [listCount]2728theorem listCount.natural (A x : Set) (xs : List(A))29showsNat(listCount{A}(x, xs))30proof31induction xs32| List.nil =>33rw listCount.nil34typecheck35| List.cons(a, tail) using ih =>36have element : a ∈ A byassumption37have mark := indicator.natural at {x}, a38rw listCount.cons39typecheck4041theorem listCount.cons_self (A x : Set) (xs : List(A))42requires element : x ∈ A43shows listCount{A}(x, x :: xs) =1+ listCount{A}(x, xs)44proof45have mark := indicator.singleton_self at x46rw [listCount.cons, mark]47rfl4849theorem listCount.cons_other (A x a : Set) (xs : List(A))50requires element : a ∈ A51requires different : x ≠ a52shows listCount{A}(x, a :: xs) = listCount{A}(x, xs)53proof54have mark := indicator.singleton_other with different55have natural := listCount.natural at A, x, xs with*56rw [listCount.cons, mark, add.left_unit]57rfl5859theorem listCount.singleton_self (A x : Set)60requires element : x ∈ A61shows listCount{A}(x, x :: []) =162proof63have mark := indicator.singleton_self at x64simp [listCount, mark, add]6566theorem listCount.singleton_other (A x a : Set)67requires element : a ∈ A68requires different : x ≠ a69shows listCount{A}(x, a :: []) =070proof71have mark := indicator.singleton_other with different72simp [listCount, mark, add]7374theorem listCount.append (A x : Set) (xs ys : List(A))75shows listCount{A}(x, append(ys, xs)) = listCount{A}(x, xs) + listCount{A}(x, ys)76proof77induction xs78| List.nil =>79have natural := listCount.natural at A, x, ys with*80rw [append.nil, listCount.nil, add.left_unit]81rfl82| List.cons(a, tail) using ih =>83have element : a ∈ A byassumption84have appended := append.closed at A, tail, ys with*85have mark := indicator.natural at {x}, a86have tailNat := listCount.natural at A, x, tail with*87have ysNat := listCount.natural at A, x, ys with*88rw [append.cons, listCount.cons, ih, listCount.cons, add.associative]89rfl9091theorem listCount.reverse (A x : Set) (xs : List(A))92shows listCount{A}(x, reverse(xs)) = listCount{A}(x, xs)93proof94induction xs95| List.nil =>96rw reverse.nil97rfl98| List.cons(a, tail) using ih =>99have element : a ∈ A byassumption100have single : List(A, a :: []) bytypecheck101have reversed : List(A, reverse(tail)) bytypecheck102have mark := indicator.natural at {x}, a103have tailNat := listCount.natural at A, x, tail with*104have nilList : List(A, []) bytypecheck105rw [reverse.cons, listCount.append, ih, listCount.cons, listCount.cons, listCount.nil]106rw [add.right_unit, add.commutative]107rfl108109theorem listCount.le_length (A x : Set) (xs : List(A))110shows listCount{A}(x, xs) ≤ length{A}(xs)111proof112induction xs113| List.nil =>114rw [listCount.nil, length.nil]115arith116| List.cons(a, tail) using ih =>117have element : a ∈ A byassumption118have tailNat := listCount.natural at A, x, tail with*119rw [listCount.cons, length.cons]120have alternatives : x = a ∨ x ≠ a bytauto121cases alternatives with same | different122 . have mark : indicator({x}, a) =1123rw same124exact indicator.singleton_self at a125rw mark126arith127 . have mark := indicator.singleton_other with different128rw [mark, add.left_unit]129arith130131theorem listCount.positive_of_mem (A x : Set) (xs : List(A))132requires member : x ∈ listSupport{A}(xs)133shows0 < listCount{A}(x, xs)134proof135induction xs136| List.nil =>137intro member138rw listSupport.nil at member139exfalso140exactset.empty with member141| List.cons(a, tail) using ih =>142intro member143have element : a ∈ A byassumption144have tailNat := listCount.natural at A, x, tail with*145havesplit:= listSupport.mem_cons_iff.forward with element, member146rw listCount.cons147casessplitwith head | rest148 . have mark : indicator({x}, a) =1149rw head150exact indicator.singleton_self at a151rw mark152arith153 . have inner := ih with rest154have mark := indicator.natural at {x}, a155arith156157theorem listCount.mem_of_positive (A x : Set) (xs : List(A))158requires positive : 0 < listCount{A}(x, xs)159shows x ∈ listSupport{A}(xs)160proof161induction xs162| List.nil =>163intro positive164rw listCount.nil at positive165exfalso166exact Less.irreflexive with Naturals.constructor.zero, positive167| List.cons(a, tail) using ih =>168intro positive169have element : a ∈ A byassumption170have tailNat := listCount.natural at A, x, tail with*171have alternatives : x = a ∨ x ≠ a bytauto172cases alternatives with same | different173 . rw same174exact listSupport.mem_cons_self with element175 . rw listCount.cons_other at positive176have inner := ih with positive177exact listSupport.mem_cons_of_mem with element, inner178179theorem listCount.positive_iff (A x : Set) (xs : List(A))180shows0 < listCount{A}(x, xs) ↔ x ∈ listSupport{A}(xs)181proof182constructor183 . intro positive184exact listCount.mem_of_positive with positive185 . intro member186exact listCount.positive_of_mem with member187188theorem listCount.zero_of_absent (A x : Set) (xs : List(A))189requires absent : ¬(x ∈ listSupport{A}(xs))190shows listCount{A}(x, xs) =0191proof192have natural := listCount.natural at A, x, xs with*193have shape := natural.zero_or_successor at listCount{A}(x, xs) with natural194cases shape with zero | successor195 . exact zero196 . obtain⟨k, kNat, equal⟩:= successor197have positive : 0 < listCount{A}(x, xs)198rw equal199arith200have member := listCount.mem_of_positive with positive201exfalso202exact absent with member203204theorem listCount.absent_of_zero (A x : Set) (xs : List(A))205requires zero : listCount{A}(x, xs) =0206shows¬(x ∈ listSupport{A}(xs))207proof208intro member209have positive := listCount.positive_of_mem with member210rw zero at positive211exact Less.irreflexive with Naturals.constructor.zero, positive212213theorem listCount.zero_iff (A x : Set) (xs : List(A))214shows listCount{A}(x, xs) =0↔¬(x ∈ listSupport{A}(xs))215proof216constructor217 . intro zero218exact listCount.absent_of_zero with zero219 . intro absent220exact listCount.zero_of_absent with absent221222theorem listCount.outside_carrier (A x : Set) (xs : List(A))223requires outside : ¬(x ∈ A)224shows listCount{A}(x, xs) =0225proof226have absent : ¬(x ∈ listSupport{A}(xs))227intro member228have subset := listSupport.subset at A, xs with*229have inA := subset with x, member230exact outside with inA231exact listCount.zero_of_absent with absent232233theorem listCount.replicate_self (A x : Set) (n : Nat)234requires element : x ∈ A235shows listCount{A}(x, listReplicate(n, x)) = n236proof237induction n238| zero =>239rw [listReplicate.zero, listCount.nil]240rfl241| succ(k) using ih =>242have list := listReplicate.closed at A, x, k with element243rw [listReplicate.succ, listCount.cons_self, ih, add.commutative, add.right_one]244rfl245246theorem listCount.replicate_other (A x y : Set) (n : Nat)247requires element : x ∈ A248requires different : y ≠ x249shows listCount{A}(y, listReplicate(n, x)) =0250proof251have absent : ¬(y ∈ listSupport{A}(listReplicate(n, x)))252intro member253have equal := listReplicate.mem_support with element, member254exact different with equal255exact listCount.zero_of_absent with absent256257theorem listCount.filter_member (A S x : Set) (xs : List(A))258requires member : x ∈ S259shows listCount{A}(x, listFilter{A}(S, xs)) = listCount{A}(x, xs)260proof261induction xs262| List.nil =>263rw listFilter.nil264rfl265| List.cons(a, tail) using ih =>266have element : a ∈ A byassumption267have filtered := listFilter.closed at A, S, tail with*268have alternatives : a ∈ S ∨¬(a ∈ S) bytauto269cases alternatives with inS | absent270 . rw [listFilter.cons_member, listCount.cons, listCount.cons, ih]271rfl272 . have different : x ≠ a273intro same274rw same at member275exact absent with member276rw [listFilter.cons_other, listCount.cons_other, ih]277rfl278279theorem listCount.filter_other (A S x : Set) (xs : List(A))280requires absent : ¬(x ∈ S)281shows listCount{A}(x, listFilter{A}(S, xs)) =0282proof283have filtered := listFilter.closed at A, S, xs with*284have outside : ¬(x ∈ listSupport{A}(listFilter{A}(S, xs)))285intro member286have both := listFilter.mem_support with member287exact absent with both.right288exact listCount.zero_of_absent with outside289290-- The count is the length of the entries equal to x.291theorem listCount.filter_length (A x : Set) (xs : List(A))292shows listCount{A}(x, xs) = length{A}(listFilter{A}({x}, xs))293proof294induction xs295| List.nil =>296rw [listCount.nil, listFilter.nil, length.nil]297rfl298| List.cons(a, tail) using ih =>299have element : a ∈ A byassumption300have filtered := listFilter.closed at A, {x}, tail with*301have alternatives : x = a ∨ x ≠ a bytauto302cases alternatives with same | different303 . have elementX : x ∈ A304rw same305exact element306have inSingle : x ∈ {x} := singleton.self at x307rw [← same, listCount.cons_self, listFilter.cons_member, length.cons, ih]308rw [add.commutative, add.right_one]309rfl310 . have notSingle : ¬(a ∈ {x})311intro inSingle312have equal := singleton.membership.forward with inSingle313 symm at equal314exact different with equal315rw [listCount.cons_other, listFilter.cons_other, ih]316rfl317318theorem listCount.take_add_drop (A x : Set) (xs : List(A)) (n : Nat)319shows listCount{A}(x, listTake{A}(n, xs)) + listCount{A}(x, listDrop{A}(n, xs)) =320 listCount{A}(x, xs)321proof322havesplit:= listTake.append_drop at A, xs, n with*323have taken := listTake.closed at A, xs, n with*324have dropped := listDrop.closed at A, xs, n with*325have counts := listCount.append at A, x, listTake{A}(n, xs), listDrop{A}(n, xs) with*326rwsplitat counts327 symm328exact counts329330theorem listCount.cons_le (A x a : Set) (xs : List(A))331requires element : a ∈ A332shows listCount{A}(x, xs) ≤ listCount{A}(x, a :: xs)333proof334have mark := indicator.natural at {x}, a335have tailNat := listCount.natural at A, x, xs with*336rw listCount.cons337arith338339theorem listCount.eq_length (A x : Set) (xs : List(A))340requires element : x ∈ A341requires full : listCount{A}(x, xs) = length{A}(xs)342shows xs = listReplicate(length{A}(xs), x)343proof344have filtered := listFilter.closed at A, {x}, xs with*345rw listCount.filter_length at full346have same := listFilter.length_eq_of_all with full347have covered := listFilter.support_in at A, {x}, xs with*348rw same at covered349exact List.constant_of_support with element, covered350351theorem listCount.le_of_support_subset (A x : Set) (xs : List(A))352requires element : x ∈ A353requires covered : listSupport{A}(xs) ⊆ {x}354shows listCount{A}(x, xs) = length{A}(xs)355proof356have constant := List.constant_of_support with element, covered357have count := listCount.replicate_self at A, x, length{A}(xs) with element358rw← constant at count359exact count360