Skip to content

Commit f46ca23

Browse files
committed
Prove insertionsort stability
1 parent 56c98a5 commit f46ca23

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

Cslib/AlgorithmsTheory/Algorithms/ListInsertionSort.lean

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ the `SortOpsInsertHead` model. This insertionSort evaluates identically to the u
2929
- `insertionSort_sorted` : `insertionSort` outputs a sorted list.
3030
- `insertionSort_complexity` : `insertionSort` takes at most n * (n + 1) comparisons and
3131
(n + 1) * (n + 2) list head-insertions.
32+
- `insertionSort_stable` : `insertionSort` is a stable sorting algorithm.
3233
-/
3334

3435
namespace Cslib
@@ -88,6 +89,67 @@ theorem insertionSort_complexity (l : List α) (le : α → α → Bool) :
8889
grind [insertOrd_complexity_upper_bound, List.length_insertionSort, SortOpsCost.le_def,
8990
insertionSort_time_compares, insertionSort_time_inserts]
9091

92+
section Stability
93+
94+
private lemma filter_orderedInsert_of_neg {r : α → α → Prop} [DecidableRel r]
95+
(a : α) (l : List α) (p : α → Bool) (ha : p a = false) :
96+
(l.orderedInsert r a).filter p = l.filter p := by
97+
induction l with
98+
| nil => rw [List.orderedInsert_nil]; simp [ha]
99+
| cons b l ih =>
100+
rw [List.orderedInsert_cons]
101+
split
102+
· simp [List.filter, ha]
103+
· simp only [List.filter]; split <;> simp [ih]
104+
105+
private lemma filter_orderedInsert_of_pos {r : α → α → Prop} [DecidableRel r]
106+
(a : α) (l : List α) (p : α → Bool)
107+
(ha : p a = true)
108+
(hcompat : ∀ b, p b = true → r a b)
109+
(hsorted : l.Pairwise r) :
110+
(l.orderedInsert r a).filter p = a :: l.filter p := by
111+
induction l with
112+
| nil => rw [List.orderedInsert_nil]; simp [ha]
113+
| cons b l ih =>
114+
rw [List.orderedInsert_cons]
115+
rw [List.pairwise_cons] at hsorted
116+
split
117+
· simp [List.filter, ha]
118+
· rename_i hnr
119+
have hnpb : p b = false := by
120+
by_contra h; push_neg at h
121+
cases hpb : p b with
122+
| false => simp [hpb] at h
123+
| true => exact hnr (hcompat b hpb)
124+
simp only [List.filter, hnpb]
125+
exact ih hsorted.2
126+
127+
theorem insertionSort_stable
128+
(xs : List α) (le : α → α → Bool)
129+
[Std.Total (fun x y => le x y = true)]
130+
[IsTrans α (fun x y => le x y = true)] :
131+
let ys := (insertionSort xs).eval (sortModel le)
132+
∀ k : α, ys.filter (fun x => le x k && le k x) = xs.filter (fun x => le x k && le k x) := by
133+
simp only [insertionSort_eval]
134+
intro k
135+
induction xs with
136+
| nil => simp
137+
| cons a rest ih =>
138+
rw [List.insertionSort_cons]
139+
have hsorted : (rest.insertionSort (fun x y => le x y = true)).Pairwise
140+
(fun x y => le x y = true) :=
141+
List.pairwise_insertionSort _ rest
142+
rcases hab : (le a k && le k a) with _ | _
143+
· rw [filter_orderedInsert_of_neg a _ (fun x => le x k && le k x) hab]
144+
simp [hab, ih]
145+
· rw [filter_orderedInsert_of_pos a _ (fun x => le x k && le k x) hab _ hsorted]
146+
· simp [hab, ih]
147+
· intro b hb
148+
simp only [Bool.and_eq_true] at hab hb
149+
exact IsTrans.trans (r := fun x y => le x y = true) a k b hab.1 hb.2
150+
151+
end Stability
152+
91153
end Algorithms
92154

93155
end Cslib

0 commit comments

Comments
 (0)