-
Notifications
You must be signed in to change notification settings - Fork 142
feat(algorithms): add stable insertion sort #576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Robertboy18
wants to merge
2
commits into
leanprover:main
Choose a base branch
from
Robertboy18:algorithms-insertion-sort-timem
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| /- | ||
| Copyright (c) 2026 Robert Joseph George. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Robert Joseph George | ||
| -/ | ||
|
|
||
| module | ||
|
|
||
| public import Cslib.Algorithms.Lean.Sorting | ||
| public import Cslib.Algorithms.Lean.TimeM | ||
| public import Mathlib.Data.List.Sort | ||
| public import Mathlib.Data.Nat.Basic | ||
|
|
||
| /-! | ||
| # Stable insertion sort on lists | ||
|
|
||
| `insertionSort` returns a `TimeM ℕ (List α)`: the return value is the sorted list, and the time | ||
| component counts comparisons. | ||
|
|
||
| Equal values are inserted before equal values already in the sorted tail. Since the sort processes | ||
| the input from right to left, this preserves the original order of equal values. | ||
|
|
||
| The cost model charges exactly one tick for each comparison made while searching for the insertion | ||
| point. | ||
| -/ | ||
|
|
||
| @[expose] public section | ||
|
|
||
| set_option autoImplicit false | ||
|
|
||
| namespace Cslib.Algorithms.Lean.TimeM | ||
|
|
||
| variable {α : Type*} [LinearOrder α] | ||
|
|
||
| /-- | ||
| Inserts one value into a sorted list, counting comparisons as time cost. The test is `x ≤ y`, so | ||
| the new value is placed before equal values in the already-sorted tail. | ||
| -/ | ||
| def insert (x : α) : List α → TimeM ℕ (List α) | ||
| | [] => return [x] | ||
| | y :: ys => do | ||
| ✓ let inFront := x ≤ y | ||
| if inFront then | ||
| return x :: y :: ys | ||
| else | ||
| let rest ← insert x ys | ||
| return y :: rest | ||
|
|
||
| /-- Sorts a list using stable insertion sort, counting comparisons as time cost. -/ | ||
| def insertionSort : List α → TimeM ℕ (List α) | ||
| | [] => return [] | ||
| | x :: xs => do | ||
| let sortedTail ← insertionSort xs | ||
| insert x sortedTail | ||
|
|
||
| section Correctness | ||
|
|
||
| /-- Timed `insert` computes mathlib's ordered insertion. -/ | ||
| @[simp, grind =] | ||
| theorem ret_insert (x : α) (xs : List α) : | ||
| ⟪insert x xs⟫ = xs.orderedInsert (· ≤ ·) x := by | ||
| induction xs with | ||
| | nil => simp [insert] | ||
| | cons y ys ih => | ||
| by_cases h : x ≤ y <;> simp [insert, h, ih] | ||
|
|
||
| /-- Timed insertion sort computes mathlib's insertion sort. -/ | ||
| @[simp, grind =] | ||
| theorem ret_insertionSort (xs : List α) : | ||
| ⟪insertionSort xs⟫ = xs.insertionSort (· ≤ ·) := by | ||
| induction xs with | ||
| | nil => simp [insertionSort] | ||
| | cons x xs ih => simp [insertionSort, ih] | ||
|
|
||
| /-- Inserting one value keeps exactly the original values. -/ | ||
| private theorem insert_perm (x : α) (xs : List α) : (⟪insert x xs⟫).Perm (x :: xs) := by | ||
| simpa using List.perm_orderedInsert (· ≤ ·) x xs | ||
|
|
||
| /-- Insertion sort returns a permutation of its input. -/ | ||
| theorem insertionSort_perm (xs : List α) : (⟪insertionSort xs⟫).Perm xs := by | ||
| simpa using List.perm_insertionSort (· ≤ ·) xs | ||
|
|
||
| /-- Inserting one value is stable with respect to filtering by any fixed value. -/ | ||
| private theorem insert_stable (x : α) (xs : List α) : StableByValue (x :: xs) ⟪insert x xs⟫ := by | ||
| induction xs with | ||
| | nil => simp [StableByValue, insert] | ||
| | cons y ys ih => | ||
| intro z | ||
| by_cases h : x ≤ y | ||
| · simp [insert, h] | ||
| · have ihz := ih z | ||
| by_cases hyz : y = z | ||
| · by_cases hxz : x = z | ||
| · subst x | ||
| subst y | ||
| exact (h le_rfl).elim | ||
| · have hxlez : ¬x ≤ z := by simpa [hyz] using h | ||
| simpa [insert, hxlez, hxz, hyz] using ihz | ||
| · by_cases hxz : x = z | ||
| · subst x | ||
| have hzley : ¬z ≤ y := by simpa using h | ||
| simpa [insert, hzley, hyz] using ihz | ||
| · simpa [insert, h, hyz, hxz] using ihz | ||
|
|
||
| /-- | ||
| Insertion sort is stable. The induction uses stability of the recursive tail and then stability of | ||
| one insertion step. | ||
| -/ | ||
| theorem insertionSort_stable (xs : List α) : StableByValue xs ⟪insertionSort xs⟫ := by | ||
| induction xs with | ||
| | nil => simp [StableByValue, insertionSort] | ||
| | cons x xs ih => | ||
| intro z | ||
| simp only [insertionSort, ret_bind] | ||
| rw [insert_stable x ⟪insertionSort xs⟫ z] | ||
| simp only [List.filter_cons] | ||
| rw [ih z] | ||
|
|
||
| /-- Insertion sort returns a sorted list. -/ | ||
| theorem insertionSort_sorted (xs : List α) : List.Pairwise (· ≤ ·) ⟪insertionSort xs⟫ := by | ||
| simpa using List.pairwise_insertionSort (· ≤ ·) xs | ||
|
|
||
| /-- Insertion sort is functionally correct. -/ | ||
| theorem insertionSort_correct (xs : List α) : List.Pairwise (· ≤ ·) ⟪insertionSort xs⟫ ∧ | ||
| (⟪insertionSort xs⟫).Perm xs ∧ StableByValue xs ⟪insertionSort xs⟫ := by | ||
| exact ⟨insertionSort_sorted xs, insertionSort_perm xs, insertionSort_stable xs⟩ | ||
|
|
||
| end Correctness | ||
|
|
||
| section TimeComplexity | ||
|
|
||
| /-- Inserting into a list performs at most one comparison per possible insertion point. -/ | ||
| private theorem insert_time_le (x : α) (xs : List α) : (insert x xs).time ≤ xs.length + 1 := by | ||
| induction xs with | ||
| | nil => simp [insert] | ||
| | cons y ys ih => | ||
| by_cases h : x ≤ y | ||
| · simp [insert, h] | ||
| · simp [insert, h] | ||
| omega | ||
|
|
||
| /-- Insertion sort preserves length. -/ | ||
| private theorem insertionSort_length (xs : List α) : ⟪insertionSort xs⟫.length = xs.length := by | ||
| simp | ||
|
|
||
| /-- Time complexity of insertion sort. -/ | ||
| theorem insertionSort_time (xs : List α) : | ||
| let n := xs.length | ||
| (insertionSort xs).time ≤ n * n := by | ||
| induction xs with | ||
| | nil => simp [insertionSort] | ||
| | cons x xs ih => | ||
| simp only [List.length_cons] | ||
| simp only [insertionSort, time_bind] | ||
| have hinsert := insert_time_le x ⟪insertionSort xs⟫ | ||
| rw [insertionSort_length xs] at hinsert | ||
| have hsquare : xs.length * xs.length + (xs.length + 1) ≤ | ||
| (xs.length + 1) * (xs.length + 1) := by | ||
| exact Nat.le_trans | ||
| (Nat.add_le_add_right | ||
| (Nat.mul_le_mul_right xs.length (Nat.le_succ xs.length)) (xs.length + 1)) | ||
| (by rw [Nat.mul_succ]) | ||
| exact (Nat.add_le_add ih hinsert).trans hsquare | ||
|
|
||
| end TimeComplexity | ||
|
|
||
| end Cslib.Algorithms.Lean.TimeM | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| /- | ||
| Copyright (c) 2026 Robert Joseph George. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Robert Joseph George | ||
| -/ | ||
|
|
||
| module | ||
|
|
||
| public import Cslib.Init | ||
|
|
||
| /-! | ||
| # Sorting utilities | ||
| For stable list sorts, filtering the input and output by any value gives a compact way to state that | ||
| the output keeps the same per-value subsequence as the input. For plain values this is equivalent to | ||
| preserving the number of copies of each value; for richer element types it can express a stronger | ||
| order-preservation property. | ||
| -/ | ||
|
|
||
| @[expose] public section | ||
|
|
||
| set_option autoImplicit false | ||
|
|
||
| namespace Cslib.Algorithms.Lean | ||
|
|
||
| /-- `ys` preserves the order of equal values from `xs`. -/ | ||
| abbrev StableByValue {α : Type*} [DecidableEq α] (xs ys : List α) : Prop := | ||
| ∀ value, ys.filter (fun x => decide (x = value)) = xs.filter (fun x => decide (x = value)) | ||
|
|
||
| end Cslib.Algorithms.Lean |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.