Skip to content

Commit ddec2bc

Browse files
committed
feat: interactions between List.map and sorting lists (#15952)
If the function preserves the relation on the list, then the sorting algorithms are unaffected.
1 parent fe13253 commit ddec2bc

File tree

2 files changed

+98
-4
lines changed

2 files changed

+98
-4
lines changed

Mathlib/Data/List/Sort.lean

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Then we define two sorting algorithms:
2020

2121
open List.Perm
2222

23-
universe u
23+
universe u v
2424

2525
namespace List
2626

@@ -31,7 +31,7 @@ namespace List
3131

3232
section Sorted
3333

34-
variable {α : Type u} {r : α → α → Prop} {a : α} {l : List α}
34+
variable {α : Type u} {β : Type v} {r : α → αProp} {s : β → βProp} {a : α} {l : List α}
3535

3636
/-- `Sorted r l` is the same as `List.Pairwise r l`, preferred in the case that `r`
3737
is a `<` or `≤`-like relation (transitive and antisymmetric or asymmetric) -/
@@ -162,9 +162,11 @@ end Monotone
162162

163163
section sort
164164

165-
variable {α : Type u} (r : α → α → Prop) [DecidableRel r]
165+
variable {α : Type u} {β : Type v} (r : α → α → Prop) (s : β → β → Prop)
166+
variable [DecidableRel r] [DecidableRel s]
166167

167168
local infixl:50 " ≼ " => r
169+
local infixl:50 " ≼ " => s
168170

169171
/-! ### Insertion sort -/
170172

@@ -220,6 +222,18 @@ theorem mem_orderedInsert {a b : α} {l : List α} :
220222
· simp [orderedInsert]
221223
· rw [mem_cons, mem_cons, mem_orderedInsert, or_left_comm]
222224

225+
theorem map_orderedInsert (f : α → β) (l : List α) (x : α)
226+
(hl₁ : ∀ a ∈ l, a ≼ x ↔ f a ≼ f x) (hl₂ : ∀ a ∈ l, x ≼ a ↔ f x ≼ f a) :
227+
(l.orderedInsert r x).map f = (l.map f).orderedInsert s (f x) := by
228+
induction l with
229+
| nil => simp
230+
| cons x xs ih =>
231+
rw [List.forall_mem_cons] at hl₁ hl₂
232+
simp only [List.map, List.orderedInsert, ← hl₁.1, ← hl₂.1]
233+
split_ifs
234+
· rw [List.map, List.map]
235+
· rw [List.map, ih (fun _ ha => hl₁.2 _ ha) (fun _ ha => hl₂.2 _ ha)]
236+
223237
section Correctness
224238

225239
open Perm
@@ -241,6 +255,25 @@ theorem perm_insertionSort : ∀ l : List α, insertionSort r l ~ l
241255
| b :: l => by
242256
simpa [insertionSort] using (perm_orderedInsert _ _ _).trans ((perm_insertionSort l).cons b)
243257

258+
@[simp]
259+
theorem mem_insertionSort {l : List α} {x : α} : x ∈ l.insertionSort r ↔ x ∈ l :=
260+
(perm_insertionSort r l).mem_iff
261+
262+
@[simp]
263+
theorem length_insertionSort (l : List α) : (insertionSort r l).length = l.length :=
264+
(perm_insertionSort r _).length_eq
265+
266+
theorem map_insertionSort (f : α → β) (l : List α) (hl : ∀ a ∈ l, ∀ b ∈ l, a ≼ b ↔ f a ≼ f b) :
267+
(l.insertionSort r).map f = (l.map f).insertionSort s := by
268+
induction l with
269+
| nil => simp
270+
| cons x xs ih =>
271+
simp_rw [List.forall_mem_cons, forall_and] at hl
272+
simp_rw [List.map, List.insertionSort]
273+
rw [List.map_orderedInsert _ s, ih hl.2.2]
274+
· simpa only [mem_insertionSort] using hl.2.1
275+
· simpa only [mem_insertionSort] using hl.1.2
276+
244277
variable {r}
245278

246279
/-- If `l` is already `List.Sorted` with respect to `r`, then `insertionSort` does not change
@@ -347,6 +380,17 @@ def split : List α → List α × List α
347380
theorem split_cons_of_eq (a : α) {l l₁ l₂ : List α} (h : split l = (l₁, l₂)) :
348381
split (a :: l) = (a :: l₂, l₁) := by rw [split, h]
349382

383+
@[simp]
384+
theorem map_split (f : α → β) :
385+
∀ l : List α, (map f l).split = (l.split.1.map f, l.split.2.map f)
386+
| [] => rfl
387+
| a :: l => by simp [map_split]
388+
389+
@[simp]
390+
theorem mem_split_iff {x : α} : ∀ {l : List α}, x ∈ l.split.1 ∨ x ∈ l.split.2 ↔ x ∈ l
391+
| [] => by simp
392+
| a :: l => by simp_rw [split, mem_cons, or_assoc, or_comm, mem_split_iff]
393+
350394
theorem length_split_le :
351395
∀ {l l₁ l₂ : List α}, split l = (l₁, l₂) → length l₁ ≤ length l ∧ length l₂ ≤ length l
352396
| [], _, _, rfl => ⟨Nat.le_refl 0, Nat.le_refl 0
@@ -407,6 +451,10 @@ theorem perm_mergeSort : ∀ l : List α, mergeSort r l ~ l
407451
((perm_mergeSort l₁).append (perm_mergeSort l₂)).trans (perm_split e).symm
408452
termination_by l => length l
409453

454+
@[simp]
455+
theorem mem_mergeSort {l : List α} {x : α} : x ∈ l.mergeSort r ↔ x ∈ l :=
456+
(perm_mergeSort r l).mem_iff
457+
410458
@[simp]
411459
theorem length_mergeSort (l : List α) : (mergeSort r l).length = l.length :=
412460
(perm_mergeSort r _).length_eq
@@ -472,6 +520,45 @@ theorem mergeSort_nil : [].mergeSort r = [] := by rw [List.mergeSort]
472520
@[simp]
473521
theorem mergeSort_singleton (a : α) : [a].mergeSort r = [a] := by rw [List.mergeSort]
474522

523+
theorem map_merge (f : α → β) (r : α → α → Bool) (s : β → β → Bool) (l l' : List α)
524+
(hl : ∀ a ∈ l, ∀ b ∈ l', r a b = s (f a) (f b)) :
525+
(l.merge r l').map f = (l.map f).merge s (l'.map f) := by
526+
match l, l' with
527+
| [], x' => simp
528+
| x, [] => simp
529+
| x :: xs, x' :: xs' =>
530+
simp_rw [List.forall_mem_cons, forall_and] at hl
531+
simp_rw [List.map, List.cons_merge_cons]
532+
rw [← hl.1.1]
533+
split
534+
· rw [List.map, map_merge _ r s, List.map]
535+
simp_rw [List.forall_mem_cons, forall_and]
536+
exact ⟨hl.2.1, hl.2.2
537+
· rw [List.map, map_merge _ r s, List.map]
538+
simp_rw [List.forall_mem_cons]
539+
exact ⟨hl.1.2, hl.2.2
540+
541+
theorem map_mergeSort (f : α → β) (l : List α) (hl : ∀ a ∈ l, ∀ b ∈ l, a ≼ b ↔ f a ≼ f b) :
542+
(l.mergeSort r).map f = (l.map f).mergeSort s :=
543+
match l with
544+
| [] => by simp
545+
| [x] => by simp
546+
| a :: b :: l => by
547+
simp_rw [← mem_split_iff (l := a :: b :: l), or_imp, forall_and] at hl
548+
set l₁ := (split (a :: b :: l)).1
549+
set l₂ := (split (a :: b :: l)).2
550+
have e : split (a :: b :: l) = (l₁, l₂) := rfl
551+
have fe : split (f a :: f b :: l.map f) = (l₁.map f, l₂.map f) := by
552+
rw [← map, ← map, map_split, e]
553+
have := length_split_fst_le l
554+
have := length_split_snd_le l
555+
simp_rw [List.map]
556+
rw [List.mergeSort_cons_cons _ e, List.mergeSort_cons_cons _ fe,
557+
map_merge _ (r · ·) (s · ·), map_mergeSort _ l₁ hl.1.1, map_mergeSort _ l₂ hl.2.2]
558+
simp_rw [mem_mergeSort, decide_eq_decide]
559+
exact hl.1.2
560+
termination_by length l
561+
475562
end MergeSort
476563

477564
end sort

Mathlib/Data/Multiset/Sort.lean

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ namespace Multiset
1515

1616
open List
1717

18-
variable {α : Type*}
18+
variableβ : Type*}
1919

2020
section sort
2121

2222
variable (r : α → α → Prop) [DecidableRel r] [IsTrans α r] [IsAntisymm α r] [IsTotal α r]
23+
variable (r' : β → β → Prop) [DecidableRel r'] [IsTrans β r'] [IsAntisymm β r'] [IsTotal β r']
2324

2425
/-- `sort s` constructs a sorted list from the multiset `s`.
2526
(Uses merge sort algorithm.) -/
@@ -55,6 +56,12 @@ theorem sort_zero : sort r 0 = [] :=
5556
theorem sort_singleton (a : α) : sort r {a} = [a] :=
5657
List.mergeSort_singleton r a
5758

59+
theorem map_sort (f : α → β) (s : Multiset α)
60+
(hs : ∀ a ∈ s, ∀ b ∈ s, r a b ↔ r' (f a) (f b)) :
61+
(s.sort r).map f = (s.map f).sort r' := by
62+
revert s
63+
exact Quot.ind fun _ => List.map_mergeSort _ _ _ _
64+
5865
end sort
5966

6067
-- TODO: use a sort order if available, gh-18166

0 commit comments

Comments
 (0)