1-- Sorted lists of natural numbers: the head bounds the tail, sortedness2-- survives prefixes, suffixes, filters, and ordered concatenation,3-- insertion sort produces a sorted permutation, and a sorted arrangement4-- of given entries is unique5-- 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.List.Sorted11import Prefix1213-- Entries are nondecreasing along positions.14predicate ListSorted (xs : Set) :=15∀ i, ∀ j, Nat(i) →Nat(j) → i < j → j < length{ℕ}(xs) → listCoefficient{ℕ}(0, xs, i) ≤ listCoefficient{ℕ}(0, xs, j)1617theorem ListSorted.nil18shows ListSorted([])19proof20unfold ListSorted21intros i j iNat jNat below bound22rw length.nil at bound23exfalso24arith2526theorem ListSorted.singleton (x : Nat)27shows ListSorted(x :: [])28proof29unfold ListSorted30intros i j iNat jNat below bound31have xIn : x ∈ ℕ := nat.omega.forward with*32rw length.singleton at bound33exfalso34arith3536theorem ListSorted.head_le (a : Nat) (xs : List(ℕ))37requires sorted : ListSorted(a :: xs)38shows∀ y ∈ listSupport{ℕ}(xs), a ≤ y39proof40intros y hy41have aIn : a ∈ ℕ := nat.omega.forward with*42obtain⟨k, kNat, bound, value⟩:= listSupport.mem_iff_index.forward at ℕ, 0, y, xs with hy43have kSucc : Nat(succ(k)) bytypecheck44have positive : 0 < succ(k) byarith45have inside : succ(k) < length{ℕ}(a :: xs)46rw length.cons47arith48unfold ListSorted at sorted49have step := sorted with0, succ(k), Naturals.constructor.zero, kSucc, positive, inside50rw [listCoefficient.zero, listCoefficient.succ, value] at step51exact step5253theorem ListSorted.tail (a : Nat) (xs : List(ℕ))54requires sorted : ListSorted(a :: xs)55shows ListSorted(xs)56proof57unfold ListSorted58intros i j iNat jNat below bound59have aIn : a ∈ ℕ := nat.omega.forward with*60have iSucc : Nat(succ(i)) bytypecheck61have jSucc : Nat(succ(j)) bytypecheck62have belowSucc : succ(i) < succ(j) byarith63have inside : succ(j) < length{ℕ}(a :: xs)64rw length.cons65arith66unfold ListSorted at sorted67have step := sorted with succ(i), succ(j), iSucc, jSucc, belowSucc, inside68rw [listCoefficient.succ, listCoefficient.succ] at step69exact step7071theorem ListSorted.cons (a : Nat) (xs : List(ℕ))72requires head : ∀ y ∈ listSupport{ℕ}(xs), a ≤ y73requires sorted : ListSorted(xs)74shows ListSorted(a :: xs)75proof76unfold ListSorted77intros i j iNat jNat below bound78have aIn : a ∈ ℕ := nat.omega.forward with*79rw length.cons at bound80have shapeJ := natural.zero_or_successor at j with jNat81cases shapeJ with zeroJ | successorJ82 . rw zeroJ at below83exfalso84arith85 . obtain⟨q, qNat, equalJ⟩:= successorJ86rw equalJ at bound87have insideQ : q < length{ℕ}(xs) byarith88have memberQ := listCoefficient.mem_support at ℕ, 0, xs, q with insideQ89have shapeI := natural.zero_or_successor at i with iNat90cases shapeI with zeroI | successorI91 . rw [zeroI, equalJ, listCoefficient.zero, listCoefficient.succ]92exact head with listCoefficient{ℕ}(0, xs, q), memberQ93 . obtain⟨p, pNat, equalI⟩:= successorI94rw [equalI, equalJ] at below95have belowPQ : p < q byarith96unfold ListSorted at sorted97have step := sorted with p, q, pNat, qNat, belowPQ, insideQ98rw [equalI, equalJ, listCoefficient.succ, listCoefficient.succ]99exact step100101theorem ListSorted.cons_iff (a : Nat) (xs : List(ℕ))102shows ListSorted(a :: xs) ↔ ((∀ y ∈ listSupport{ℕ}(xs), a ≤ y) ∧ ListSorted(xs))103proof104constructor105 . intro sorted106have head := ListSorted.head_le with sorted107have tail := ListSorted.tail with sorted108exact⟨head, tail⟩109 . intro both110obtain⟨head, tail⟩:= both111exact ListSorted.cons with head, tail112113theorem ListSorted.cons_cons_le (a b : Nat) (xs : List(ℕ))114requires sorted : ListSorted(a :: b :: xs)115shows a ≤ b116proof117have bIn : b ∈ ℕ := nat.omega.forward with*118have head := ListSorted.head_le with sorted119have member := listSupport.mem_cons_self at ℕ, b, xs with bIn120exact head with b, member121122theorem ListSorted.min_head (a : Nat) (xs : List(ℕ))123requires sorted : ListSorted(a :: xs)124shows∀ y ∈ listSupport{ℕ}(a :: xs), a ≤ y125proof126intros y hy127have aIn : a ∈ ℕ := nat.omega.forward with*128have head := ListSorted.head_le with sorted129havesplit:= listSupport.mem_cons_iff.forward with aIn, hy130casessplitwith same | rest131 . rw same132exact LessEqual.reflexive at a133 . exact head with y, rest134135theorem ListSorted.replicate (x : Nat) (n : Nat)136shows ListSorted(listReplicate(n, x))137proof138induction n139| zero =>140rw listReplicate.zero141exact ListSorted.nil142| succ(k) using ih =>143have xIn : x ∈ ℕ := nat.omega.forward with*144have list := listReplicate.closed at ℕ, x, k with xIn145have head : ∀ y ∈ listSupport{ℕ}(listReplicate(k, x)), x ≤ y146intros y hy147have equal := listReplicate.mem_support with xIn, hy148rw equal149exact LessEqual.reflexive at x150rw listReplicate.succ151exact ListSorted.cons with head, ih152153theorem ListSorted.take (xs : List(ℕ)) (n : Nat)154requires sorted : ListSorted(xs)155shows ListSorted(listTake{ℕ}(n, xs))156proof157induction xs generalizing n158| List.nil =>159intros n nNat sorted160rw listTake.nil161exact ListSorted.nil162| List.cons(a, tail) using ih =>163intros n nNat sorted164have aIn : a ∈ ℕ byassumption165have aNat := nat.omega.backward with aIn166have shape := natural.zero_or_successor at n with nNat167cases shape with zero | successor168 . have whole : List(ℕ, a :: tail) bytypecheck169rw [zero, listTake.zero]170exact ListSorted.nil171 . obtain⟨k, kNat, equal⟩:= successor172have headAll := ListSorted.head_le with sorted173have tailSorted := ListSorted.tail with sorted174have inner := ih with k, kNat, tailSorted175have taken := listTake.closed at ℕ, tail, k with*176have subset := listTake.support_subset at ℕ, tail, k with*177have head : ∀ y ∈ listSupport{ℕ}(listTake{ℕ}(k, tail)), a ≤ y178intros y hy179have member := subset with y, hy180exact headAll with y, member181rw [equal, listTake.succ_cons]182exact ListSorted.cons with head, inner183184theorem ListSorted.drop (xs : List(ℕ)) (n : Nat)185requires sorted : ListSorted(xs)186shows ListSorted(listDrop{ℕ}(n, xs))187proof188induction xs generalizing n189| List.nil =>190intros n nNat sorted191rw listDrop.nil192exact ListSorted.nil193| List.cons(a, tail) using ih =>194intros n nNat sorted195have aIn : a ∈ ℕ byassumption196have aNat := nat.omega.backward with aIn197have shape := natural.zero_or_successor at n with nNat198cases shape with zero | successor199 . have whole : List(ℕ, a :: tail) bytypecheck200rw [zero, listDrop.zero]201exact sorted202 . obtain⟨k, kNat, equal⟩:= successor203have tailSorted := ListSorted.tail with sorted204rw [equal, listDrop.succ_cons]205exact ih with k, kNat, tailSorted206207theorem ListSorted.filter (S : Set) (xs : List(ℕ))208requires sorted : ListSorted(xs)209shows ListSorted(listFilter{ℕ}(S, xs))210proof211induction xs212| List.nil =>213intro sorted214rw listFilter.nil215exact ListSorted.nil216| List.cons(a, tail) using ih =>217intro sorted218have aIn : a ∈ ℕ byassumption219have aNat := nat.omega.backward with aIn220have headAll := ListSorted.head_le with sorted221have tailSorted := ListSorted.tail with sorted222have inner := ih with tailSorted223have filtered := listFilter.closed at ℕ, S, tail with*224have alternatives : a ∈ S ∨¬(a ∈ S) bytauto225cases alternatives with member | absent226 . have subset := listFilter.support_subset at ℕ, S, tail with*227have head : ∀ y ∈ listSupport{ℕ}(listFilter{ℕ}(S, tail)), a ≤ y228intros y hy229have inTail := subset with y, hy230exact headAll with y, inTail231rw listFilter.cons_member232exact ListSorted.cons with head, inner233 . rw listFilter.cons_other234exact inner235236theorem ListSorted.append (xs ys : List(ℕ))237requires first : ListSorted(xs)238requires second : ListSorted(ys)239requires between : ∀ x ∈ listSupport{ℕ}(xs), ∀ y ∈ listSupport{ℕ}(ys), x ≤ y240shows ListSorted(append(ys, xs))241proof242induction xs243| List.nil =>244intros first between245have ysList : List(ℕ, ys) bytypecheck246rw append.nil247exact second248| List.cons(a, tail) using ih =>249intros first between250have aIn : a ∈ ℕ byassumption251have aNat := nat.omega.backward with aIn252have headAll := ListSorted.head_le with first253have tailSorted := ListSorted.tail with first254have headIn := listSupport.mem_cons_self at ℕ, a, tail with aIn255have restBetween : ∀ x ∈ listSupport{ℕ}(tail), ∀ y ∈ listSupport{ℕ}(ys), x ≤ y256intros x hx y hy257have outer := listSupport.mem_cons_of_mem with aIn, hx258exact between with x, outer, y, hy259have inner := ih with tailSorted, restBetween260have appended := append.closed at ℕ, tail, ys with*261have head : ∀ y ∈ listSupport{ℕ}(append(ys, tail)), a ≤ y262intros y hy263havesplit:= listSupport.mem_append_iff.forward at ℕ, y, tail, ys with hy264casessplitwith inTail | inYs265 . exact headAll with y, inTail266 . exact between with a, headIn, y, inYs267rw append.cons268exact ListSorted.cons with head, inner269270-- A sorted arrangement of given entries is unique.271theorem ListSorted.permutation_unique (xs ys : List(ℕ))272requires first : ListSorted(xs)273requires second : ListSorted(ys)274requires permutation : ListPermutation(ℕ, xs, ys)275shows xs = ys276proof277induction xs generalizing ys278| List.nil =>279intros ys ysList first second permutation280have back := ListPermutation.symmetric with permutation281have empty := ListPermutation.nil with back282rw empty283rfl284| List.cons(a, tail) using ih =>285intros ys ysList first second permutation286have aIn : a ∈ ℕ byassumption287have aNat := nat.omega.backward with aIn288have shape := List.cases with ysList289cases shape with nil | cons290 . rw nil at permutation291have empty := ListPermutation.nil with permutation292have distinct := List.cons_ne_nil at ℕ, a, tail with aIn293exfalso294exact distinct with empty295 . obtain⟨b, bIn, rest, restList, equal⟩:= cons296have bNat := nat.omega.backward with bIn297rw equal at permutation298rw equal at second299have headIn := listSupport.mem_cons_self at ℕ, a, tail with aIn300have aInYs := ListPermutation.mem_support with permutation, headIn301have back := ListPermutation.symmetric with permutation302have headInYs := listSupport.mem_cons_self at ℕ, b, rest with bIn303have bInXs := ListPermutation.mem_support with back, headInYs304have minA := ListSorted.min_head with first305have minB := ListSorted.min_head with second306have aLeB := minA with b, bInXs307have bLeA := minB with a, aInYs308have same := LessEqual.antisymmetric with aLeB, bLeA309rw← same at permutation310have tails := ListPermutation.cons_cancel with aIn, permutation311have tailSorted := ListSorted.tail with first312rw← same at second313have restSorted := ListSorted.tail with second314have inner := ih with rest, restList, tailSorted, restSorted, tails315rw [equal, ← same, inner]316rfl317318-- Insertion into a sorted list, and insertion sort.319theorem memberTest.successor_le (x y : Nat)320requires le : x ≤ y321shows memberTest(succ(y), x) = Bool.true322proof323have below : x < succ(y) byarith324have member := membership.of_Less at x, succ(y) with*, below325exact memberTest.true with member326327theorem memberTest.successor_gt (x y : Nat)328requires gt : y < x329shows memberTest(succ(y), x) = Bool.false330proof331have absent : ¬(x ∈ succ(y))332intro member333have below := Less.of_membership at x, succ(y) with*, member334have le := Less.successor_upper with below335have strict : x < x byarith336exact Less.irreflexive with*, strict337exact memberTest.false with absent338339def listInsert (x : Nat, xs : List(ℕ)) →Set340| x, [] => x :: []341| x, y :: rest =>342 boolChoice(memberTest(succ(y), x), x :: y :: rest, y :: listInsert(x, rest))343344theorem listInsert.nil (x : Nat)345shows listInsert(x, []) = x :: []346proof347simp [listInsert]348349theorem listInsert.cons_le (x y : Nat) (rest : List(ℕ))350requires le : x ≤ y351shows listInsert(x, y :: rest) = x :: y :: rest352proof353have test := memberTest.successor_le with le354simp [listInsert, test, boolChoice]355356theorem listInsert.cons_gt (x y : Nat) (rest : List(ℕ))357requires gt : y < x358shows listInsert(x, y :: rest) = y :: listInsert(x, rest)359proof360have test := memberTest.successor_gt with gt361simp [listInsert, test, boolChoice]362363theorem listInsert.closed (x : Nat) (xs : List(ℕ))364shows List(ℕ, listInsert(x, xs))365proof366induction xs367| List.nil =>368have xIn : x ∈ ℕ := nat.omega.forward with*369rw listInsert.nil370typecheck371| List.cons(y, rest) using ih =>372have xIn : x ∈ ℕ := nat.omega.forward with*373have yIn : y ∈ ℕ byassumption374have yNat := nat.omega.backward with yIn375have alternatives : x ≤ y ∨¬(x ≤ y) bytauto376cases alternatives with le | notLe377 . rw listInsert.cons_le378typecheck379 . have gt := Less.of_not_LessEqual at x, y with notLe380rw listInsert.cons_gt381typecheck382383theorem listInsert.permutation (x : Nat) (xs : List(ℕ))384shows ListPermutation(ℕ, listInsert(x, xs), x :: xs)385proof386induction xs387| List.nil =>388have xIn : x ∈ ℕ := nat.omega.forward with*389rw listInsert.nil390exact ListPermutation.reflexive at ℕ, x :: [] with*391| List.cons(y, rest) using ih =>392have xIn : x ∈ ℕ := nat.omega.forward with*393have yIn : y ∈ ℕ byassumption394have yNat := nat.omega.backward with yIn395have inserted := listInsert.closed at x, rest with*396have whole : List(ℕ, y :: rest) bytypecheck397have alternatives : x ≤ y ∨¬(x ≤ y) bytauto398cases alternatives with le | notLe399 . rw listInsert.cons_le400exact ListPermutation.reflexive at ℕ, x :: y :: rest with*401 . have gt := Less.of_not_LessEqual at x, y with notLe402rw listInsert.cons_gt403have step := ListPermutation.cons at ℕ, y, listInsert(x, rest), x :: rest with yIn, ih404have swap := ListPermutation.swap at ℕ, y, x, rest with yIn, xIn405exact ListPermutation.transitive with step, swap406407theorem listInsert.length (x : Nat) (xs : List(ℕ))408shows length{ℕ}(listInsert(x, xs)) = succ(length{ℕ}(xs))409proof410have xIn : x ∈ ℕ := nat.omega.forward with*411have inserted := listInsert.closed at x, xs with*412have whole : List(ℕ, x :: xs) bytypecheck413have permutation := listInsert.permutation at x, xs with*414have lengths := ListPermutation.length with permutation415rw [lengths, length.cons]416rfl417418theorem listInsert.count (x z : Nat) (xs : List(ℕ))419shows listCount{ℕ}(z, listInsert(x, xs)) = listCount{ℕ}(z, x :: xs)420proof421have xIn : x ∈ ℕ := nat.omega.forward with*422have inserted := listInsert.closed at x, xs with*423have whole : List(ℕ, x :: xs) bytypecheck424have permutation := listInsert.permutation at x, xs with*425exact ListPermutation.count with permutation426427theorem listInsert.support (x : Nat) (xs : List(ℕ))428shows listSupport{ℕ}(listInsert(x, xs)) = insert(x, listSupport{ℕ}(xs))429proof430have xIn : x ∈ ℕ := nat.omega.forward with*431have inserted := listInsert.closed at x, xs with*432have whole : List(ℕ, x :: xs) bytypecheck433have permutation := listInsert.permutation at x, xs with*434have support := ListPermutation.support with permutation435rw [support, listSupport.cons]436rfl437438theorem listInsert.sorted (x : Nat) (xs : List(ℕ))439requires sorted : ListSorted(xs)440shows ListSorted(listInsert(x, xs))441proof442induction xs443| List.nil =>444intro sorted445rw listInsert.nil446exact ListSorted.singleton at x with*447| List.cons(y, rest) using ih =>448intro sorted449have xIn : x ∈ ℕ := nat.omega.forward with*450have yIn : y ∈ ℕ byassumption451have yNat := nat.omega.backward with yIn452have inserted := listInsert.closed at x, rest with*453have whole : List(ℕ, y :: rest) bytypecheck454have headAll := ListSorted.head_le with sorted455have restSorted := ListSorted.tail with sorted456have alternatives : x ≤ y ∨¬(x ≤ y) bytauto457cases alternatives with le | notLe458 . rw listInsert.cons_le459have head : ∀ z ∈ listSupport{ℕ}(y :: rest), x ≤ z460intros z hz461havesplit:= listSupport.mem_cons_iff.forward with yIn, hz462casessplitwith same | inRest463 . rw same464exact le465 . have subset := listSupport.subset at ℕ, rest with*466have zIn := subset with z, inRest467have zNat := nat.omega.backward with zIn468have yz := headAll with z, inRest469exact LessEqual.transitive with le, yz470exact ListSorted.cons with head, sorted471 . have gt := Less.of_not_LessEqual at x, y with notLe472have inner := ih with restSorted473rw listInsert.cons_gt474have head : ∀ z ∈ listSupport{ℕ}(listInsert(x, rest)), y ≤ z475intros z hz476rw listInsert.support at hz477havesplit:= insert.membership.forward with hz478casessplitwith same | inRest479 . rw same480exact Less.implies_LessEqual with gt481 . exact headAll with z, inRest482exact ListSorted.cons with head, inner483484def listInsertionSort (xs : List(ℕ)) →Set485| [] => []486| x :: rest => listInsert(x, listInsertionSort(rest))487488theorem listInsertionSort.nil489shows listInsertionSort([]) = []490proof491simp [listInsertionSort]492493theorem listInsertionSort.cons (x : Nat) (rest : List(ℕ))494shows listInsertionSort(x :: rest) = listInsert(x, listInsertionSort(rest))495proof496simp [listInsertionSort]497498theorem listInsertionSort.closed (xs : List(ℕ))499shows List(ℕ, listInsertionSort(xs))500proof501induction xs502| List.nil =>503rw listInsertionSort.nil504typecheck505| List.cons(x, rest) using ih =>506have xIn : x ∈ ℕ byassumption507have xNat := nat.omega.backward with xIn508rw listInsertionSort.cons509exact listInsert.closed at x, listInsertionSort(rest) with*510511theorem listInsertionSort.permutation (xs : List(ℕ))512shows ListPermutation(ℕ, listInsertionSort(xs), xs)513proof514induction xs515| List.nil =>516rw listInsertionSort.nil517exact ListPermutation.reflexive at ℕ, [] with*518| List.cons(x, rest) using ih =>519have xIn : x ∈ ℕ byassumption520have xNat := nat.omega.backward with xIn521have sortedRest := listInsertionSort.closed at rest with*522have inserted := listInsert.closed at x, listInsertionSort(rest) with*523have consSorted : List(ℕ, x :: listInsertionSort(rest)) bytypecheck524rw listInsertionSort.cons525have step := listInsert.permutation at x, listInsertionSort(rest) with*526have consStep := ListPermutation.cons at ℕ, x, listInsertionSort(rest), rest with xIn, ih527exact ListPermutation.transitive with step, consStep528529theorem listInsertionSort.sorted (xs : List(ℕ))530shows ListSorted(listInsertionSort(xs))531proof532induction xs533| List.nil =>534rw listInsertionSort.nil535exact ListSorted.nil536| List.cons(x, rest) using ih =>537have xIn : x ∈ ℕ byassumption538have xNat := nat.omega.backward with xIn539have sortedRest := listInsertionSort.closed at rest with*540rw listInsertionSort.cons541exact listInsert.sorted with ih542543theorem listInsertionSort.length (xs : List(ℕ))544shows length{ℕ}(listInsertionSort(xs)) = length{ℕ}(xs)545proof546have sorted := listInsertionSort.closed at xs with*547have permutation := listInsertionSort.permutation at xs with*548exact ListPermutation.length with permutation549550theorem listInsertionSort.support (xs : List(ℕ))551shows listSupport{ℕ}(listInsertionSort(xs)) = listSupport{ℕ}(xs)552proof553have sorted := listInsertionSort.closed at xs with*554have permutation := listInsertionSort.permutation at xs with*555exact ListPermutation.support with permutation556557theorem listInsertionSort.count (x : Set) (xs : List(ℕ))558shows listCount{ℕ}(x, listInsertionSort(xs)) = listCount{ℕ}(x, xs)559proof560have sorted := listInsertionSort.closed at xs with*561have permutation := listInsertionSort.permutation at xs with*562exact ListPermutation.count with permutation563564theorem listInsertionSort.of_sorted (xs : List(ℕ))565requires sorted : ListSorted(xs)566shows listInsertionSort(xs) = xs567proof568have list := listInsertionSort.closed at xs with*569have resultSorted := listInsertionSort.sorted at xs with*570have permutation := listInsertionSort.permutation at xs with*571exact ListSorted.permutation_unique with resultSorted, sorted, permutation572573theorem listInsertionSort.idempotent (xs : List(ℕ))574shows listInsertionSort(listInsertionSort(xs)) = listInsertionSort(xs)575proof576have list := listInsertionSort.closed at xs with*577have resultSorted := listInsertionSort.sorted at xs with*578exact listInsertionSort.of_sorted with resultSorted579580theorem listInsertionSort.of_permutation (xs ys : List(ℕ))581requires permutation : ListPermutation(ℕ, xs, ys)582shows listInsertionSort(xs) = listInsertionSort(ys)583proof584have leftList := listInsertionSort.closed at xs with*585have rightList := listInsertionSort.closed at ys with*586have leftSorted := listInsertionSort.sorted at xs with*587have rightSorted := listInsertionSort.sorted at ys with*588haveleft:= listInsertionSort.permutation at xs with*589haveright:= listInsertionSort.permutation at ys with*590have rightBack := ListPermutation.symmetric withright591have middle := ListPermutation.transitive withleft, permutation592have whole := ListPermutation.transitive with middle, rightBack593exact ListSorted.permutation_unique with leftSorted, rightSorted, whole594