1-- Reading a list by position: the default is invisible inside the list,2-- positions mirror under reversal, the last entry of a snoc, and3-- extensionality by positions in both directions4-- 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.Index10import Sum1112theorem listCoefficient.congr_default (A z w : Set) (xs : List(A)) (n : Nat)13requires bound : n < length{A}(xs)14shows listCoefficient{A}(z, xs, n) = listCoefficient{A}(w, xs, n)15proof16induction xs generalizing n17| List.nil =>18intros n nNat bound19rw length.nil at bound20exfalso21arith22| List.cons(a, tail) using ih =>23intros n nNat bound24have element : a ∈ A byassumption25rw length.cons at bound26have shape := natural.zero_or_successor with*27cases shape with zero | successor28 . rw [zero, listCoefficient.zero, listCoefficient.zero]29rfl30 . obtain⟨k, kNat, equal⟩:= successor31rw equal at bound32have smaller : k < length{A}(tail) byarith33have inner := ih with k, kNat, smaller34rw [equal, listCoefficient.succ, listCoefficient.succ]35exact inner3637theorem listCoefficient.singleton (A z a : Set)38requires element : a ∈ A39shows listCoefficient{A}(z, a :: [], 0) = a40proof41simp [listCoefficient, listHeadOr]4243theorem listCoefficient.lt_length_of_ne_default (A z : Set) (xs : List(A)) (n : Nat)44requires different : listCoefficient{A}(z, xs, n) ≠ z45shows n < length{A}(xs)46proof47have alternatives : n < length{A}(xs) ∨¬(n < length{A}(xs)) bytauto48cases alternatives with inside | outside49 . exact inside50 . have bound := LessEqual.of_not_Less at n, length{A}(xs) with outside51have equal := listCoefficient.outside at A, z, xs, n with bound52exfalso53exact different with equal5455theorem listCoefficient.count_positive (A z : Set) (xs : List(A)) (n : Nat)56requires bound : n < length{A}(xs)57shows0 < listCount{A}(listCoefficient{A}(z, xs, n), xs)58proof59have member := listCoefficient.mem_support at A, z, xs, n with bound60exact listCount.positive_of_mem with member6162theorem listSupport.mem_iff_index (A z y : Set) (xs : List(A))63shows y ∈ listSupport{A}(xs) ↔64∃ n, Nat(n) ∧ n < length{A}(xs) ∧ listCoefficient{A}(z, xs, n) = y65proof66constructor67 . intro member68have cover := listSupport.exists_index at A, z, xs with*69exact cover with y, member70 . introwitness71obtain⟨n, nNat, bound, value⟩:=witness72have member := listCoefficient.mem_support at A, z, xs, n with*73 rwa value at member7475-- The last entry of a list extended by a, and reading the reversal.76theorem listCoefficient.snoc_last (A z a : Set) (xs : List(A))77requires element : a ∈ A78shows listCoefficient{A}(z, append(a :: [], xs), length{A}(xs)) = a79proof80have single : List(A, a :: []) bytypecheck81have step := listCoefficient.append_right at A, z, xs, a :: [], 0with*82rw [add.left_unit, listCoefficient.singleton] at step83exact step8485theorem listCoefficient.snoc_below (A z a : Set) (xs : List(A)) (n : Nat)86requires element : a ∈ A87requires bound : n < length{A}(xs)88shows listCoefficient{A}(z, append(a :: [], xs), n) = listCoefficient{A}(z, xs, n)89proof90have single : List(A, a :: []) bytypecheck91exact listCoefficient.append_left with bound9293theorem listCoefficient.reverse (A z : Set) (xs : List(A)) (n m : Nat)94requiressplit : n + m +1= length{A}(xs)95shows listCoefficient{A}(z, reverse(xs), n) = listCoefficient{A}(z, xs, m)96proof97induction xs generalizing n m98| List.nil =>99intros n m nNat mNat split100rw [length.nil] atsplit101have sum : Nat(n + m) bytypecheck102have distinct := Naturals.disjoint.zero.succ at n + m103rw add.right_one atsplit104exfalso105 symm atsplit106exact distinct withsplit107| List.cons(a, tail) using ih =>108intros n m nNat mNat split109have element : a ∈ A byassumption110have single : List(A, a :: []) bytypecheck111have reversed : List(A, reverse(tail)) bytypecheck112have reversedLength := reverse.length at A, tail with*113rw [length.cons, add.right_one] atsplit114have sum := Naturals.injective.succ withsplit115rw reverse.cons116have shape := natural.zero_or_successor at m with mNat117cases shape with zero | successor118 . rw [zero, add.right_unit] at sum119rw [zero, listCoefficient.zero, sum, ← reversedLength]120exact listCoefficient.snoc_last with element121 . obtain⟨k, kNat, equal⟩:= successor122rw [equal, add.succ_right] at sum123have smaller : n < length{A}(reverse(tail))124rw reversedLength125rw← sum126arith127have inner : n + k +1= length{A}(tail)128rw add.right_one129exact sum130have recursive := ih with n, k, nNat, kNat, inner131rw [equal, listCoefficient.succ, listCoefficient.snoc_below, recursive]132rfl133134theorem listCoefficient.reverse_head (A z : Set) (xs : List(A)) (n : Nat)135requiressplit : n +1= length{A}(xs)136shows listCoefficient{A}(z, reverse(xs), 0) = listCoefficient{A}(z, xs, n)137proof138have shifted : 0+ n +1= length{A}(xs)139rw add.left_unit140exactsplit141exact listCoefficient.reverse with shifted142143theorem listCoefficient.reverse_last (A z : Set) (xs : List(A)) (n : Nat)144requiressplit : n +1= length{A}(xs)145shows listCoefficient{A}(z, reverse(xs), n) = listCoefficient{A}(z, xs, 0)146proof147have shifted : n +0+1= length{A}(xs)148rw add.right_unit149exactsplit150exact listCoefficient.reverse with shifted151152-- Extensionality by positions, in both directions and with every position.153theorem listCoefficient.ext_iff (A z : Set) (xs ys : List(A))154shows xs = ys ↔ (length{A}(xs) = length{A}(ys) ∧ (∀ n, Nat(n) → n < length{A}(xs) →155 listCoefficient{A}(z, xs, n) = listCoefficient{A}(z, ys, n)))156proof157constructor158 . intro equal159constructor160 . rw equal161rfl162 . intros n nNat bound163rw equal164rfl165 . intro both166obtain⟨sameLength, entries⟩:= both167exact listCoefficient.ext with sameLength, entries168169theorem listCoefficient.ext_all (A z : Set) (xs ys : List(A))170requires sameLength : length{A}(xs) = length{A}(ys)171requires entries : ∀ n, Nat(n) → listCoefficient{A}(z, xs, n) = listCoefficient{A}(z, ys, n)172shows xs = ys173proof174have bounded : ∀ n, Nat(n) → n < length{A}(xs) →175 listCoefficient{A}(z, xs, n) = listCoefficient{A}(z, ys, n)176intros n nNat bound177exact entries with n, nNat178exact listCoefficient.ext with sameLength, bounded179180theorem listCoefficient.eq_of_entries (A z : Set) (xs ys : List(A))181requires entries : ∀ n, Nat(n) → listCoefficient{A}(z, xs, n) = listCoefficient{A}(z, ys, n)182requires default : ¬(z ∈ A)183shows xs = ys184proof185have sameLength : length{A}(xs) = length{A}(ys)186have xsNat : Nat(length{A}(xs)) bytypecheck187have ysNat : Nat(length{A}(ys)) bytypecheck188have trichotomy := Less.trichotomy at length{A}(xs), length{A}(ys) with*189rcases trichotomy with less | equal | greater190 . have bound : length{A}(xs) ≤ length{A}(xs) byarith191have outside := listCoefficient.outside at A, z, xs, length{A}(xs) with bound192have inside := listCoefficient.mem_support at A, z, ys, length{A}(xs) with less193have value := entries with length{A}(xs), xsNat194rw [← value, outside] at inside195have subset := listSupport.subset at A, ys with*196have inA := subset with z, inside197exfalso198exact default with inA199 . exact equal200 . have bound : length{A}(ys) ≤ length{A}(ys) byarith201have outside := listCoefficient.outside at A, z, ys, length{A}(ys) with bound202have inside := listCoefficient.mem_support at A, z, xs, length{A}(ys) with greater203have value := entries with length{A}(ys), ysNat204rw [value, outside] at inside205have subset := listSupport.subset at A, xs with*206have inA := subset with z, inside207exfalso208exact default with inA209exact listCoefficient.ext_all with sameLength, entries210211theorem listCoefficient.take_ext (A z : Set) (xs ys : List(A)) (n : Nat)212requires boundXs : n ≤ length{A}(xs)213requires boundYs : n ≤ length{A}(ys)214requires entries : ∀ k, Nat(k) → k < n →215 listCoefficient{A}(z, xs, k) = listCoefficient{A}(z, ys, k)216shows listTake{A}(n, xs) = listTake{A}(n, ys)217proof218have takenXs := listTake.closed at A, xs, n with*219have takenYs := listTake.closed at A, ys, n with*220have lengthXs := listTake.length with boundXs221have lengthYs := listTake.length with boundYs222have sameLength : length{A}(listTake{A}(n, xs)) = length{A}(listTake{A}(n, ys))223rw [lengthXs, lengthYs]224rfl225have positions : ∀ k, Nat(k) → k < length{A}(listTake{A}(n, xs)) →226 listCoefficient{A}(z, listTake{A}(n, xs), k) = listCoefficient{A}(z, listTake{A}(n, ys), k)227intros k kNat bound228rw lengthXs at bound229haveleft:= listTake.coefficient at A, z, xs, n, k with bound230haveright:= listTake.coefficient at A, z, ys, n, k with bound231rw [left, right]232exact entries with k, kNat, bound233exact listCoefficient.ext with sameLength, positions234235theorem listCoefficient.drop_ext (A z : Set) (xs ys : List(A)) (n : Nat)236requires sameLength : length{A}(xs) = length{A}(ys)237requires entries : ∀ k, Nat(k) → n ≤ k →238 listCoefficient{A}(z, xs, k) = listCoefficient{A}(z, ys, k)239shows listDrop{A}(n, xs) = listDrop{A}(n, ys)240proof241have droppedXs := listDrop.closed at A, xs, n with*242have droppedYs := listDrop.closed at A, ys, n with*243have positions : ∀ k, Nat(k) →244 listCoefficient{A}(z, listDrop{A}(n, xs), k) = listCoefficient{A}(z, listDrop{A}(n, ys), k)245intros k kNat246haveleft:= listDrop.coefficient at A, z, xs, n, k with*247haveright:= listDrop.coefficient at A, z, ys, n, k with*248have shifted : Nat(n + k) bytypecheck249have above : n ≤ n + k byarith250rw [left, right]251exact entries with n + k, shifted, above252have lengths : length{A}(listDrop{A}(n, xs)) = length{A}(listDrop{A}(n, ys))253have alternatives : n ≤ length{A}(xs) ∨¬(n ≤ length{A}(xs)) bytauto254cases alternatives with inside | outside255 . have insideYs : n ≤ length{A}(ys) by rwa ← sameLength256haveleft:= listDrop.length with inside257haveright:= listDrop.length with insideYs258rw sameLength atleft259rw←rightatleft260exact add.right_cancel withleft261 . have beyond := Less.of_not_LessEqual at n, length{A}(xs) with outside262have boundXs : length{A}(xs) ≤ n byarith263have boundYs : length{A}(ys) ≤ n by rwa ← sameLength264haveleft:= listDrop.all with boundXs265haveright:= listDrop.all with boundYs266rw [left, right]267rfl268exact listCoefficient.ext_all with lengths, positions269