Skip to content

Commit 9131b85

Browse files
committed
feat: List.merge and lemmas
1 parent 7969a87 commit 9131b85

File tree

3 files changed

+122
-1
lines changed

3 files changed

+122
-1
lines changed

Std/Data/List/Basic.lean

+11-1
Original file line numberDiff line numberDiff line change
@@ -1655,4 +1655,14 @@ See `isSubperm_iff` for a characterization in terms of `List.Subperm`.
16551655
-/
16561656
def isSubperm [BEq α] (l₁ l₂ : List α) : Bool := ∀ x ∈ l₁, count x l₁ ≤ count x l₂
16571657

1658-
end List
1658+
/--
1659+
`O(|l| + |r|)`. Merge two lists using `s` as a switch.
1660+
-/
1661+
def merge (s : α → α → Bool) (l r : List α) : List α :=
1662+
loop l r []
1663+
where
1664+
/-- Inner loop for `List.merge`. Tail recursive. -/
1665+
loop : List α → List α → List α → List α
1666+
| [], r, t => reverseAux t r
1667+
| l, [], t => reverseAux t l
1668+
| a::l, b::r, t => bif s a b then loop l (b::r) (a::t) else loop (a::l) r (b::t)

Std/Data/List/Lemmas.lean

+91
Original file line numberDiff line numberDiff line change
@@ -2398,3 +2398,94 @@ theorem indexOf_mem_indexesOf [BEq α] [LawfulBEq α] {xs : List α} (m : x ∈
23982398
case tail m =>
23992399
specialize ih m
24002400
simpa
2401+
2402+
theorem merge_loop_nil_left (s : α → α → Bool) (r t) :
2403+
merge.loop s [] r t = reverseAux t r := by
2404+
rw [merge.loop]
2405+
2406+
theorem merge_loop_nil_right (s : α → α → Bool) (l t) :
2407+
merge.loop s l [] t = reverseAux t l := by
2408+
cases l <;> rw [merge.loop]; intro; contradiction
2409+
2410+
theorem merge_loop (s : α → α → Bool) (l r t) :
2411+
merge.loop s l r t = reverseAux t (merge s l r) := by
2412+
rw [merge]; generalize hn : l.length + r.length = n
2413+
induction n using Nat.recAux generalizing l r t with
2414+
| zero =>
2415+
rw [eq_nil_of_length_eq_zero (Nat.eq_zero_of_add_eq_zero_left hn)]
2416+
rw [eq_nil_of_length_eq_zero (Nat.eq_zero_of_add_eq_zero_right hn)]
2417+
rfl
2418+
| succ n ih =>
2419+
match l, r with
2420+
| [], r => simp only [merge_loop_nil_left]; rfl
2421+
| l, [] => simp only [merge_loop_nil_right]; rfl
2422+
| a::l, b::r =>
2423+
simp only [merge.loop, cond]
2424+
split
2425+
· have hn : l.length + (b :: r).length = n := by
2426+
apply Nat.add_right_cancel (m:=1)
2427+
rw [←hn]; simp only [length_cons, Nat.add_succ, Nat.succ_add]
2428+
rw [ih _ _ (a::t) hn, ih _ _ [] hn, ih _ _ [a] hn]; rfl
2429+
· have hn : (a::l).length + r.length = n := by
2430+
apply Nat.add_right_cancel (m:=1)
2431+
rw [←hn]; simp only [length_cons, Nat.add_succ, Nat.succ_add]
2432+
rw [ih _ _ (b::t) hn, ih _ _ [] hn, ih _ _ [b] hn]; rfl
2433+
2434+
@[simp] theorem merge_nil (s : α → α → Bool) (l) : merge s l [] = l := merge_loop_nil_right ..
2435+
2436+
@[simp] theorem nil_merge (s : α → α → Bool) (r) : merge s [] r = r := merge_loop_nil_left ..
2437+
2438+
theorem cons_merge_cons (s : α → α → Bool) (a b l r) :
2439+
merge s (a::l) (b::r) = if s a b then a :: merge s l (b::r) else b :: merge s (a::l) r := by
2440+
simp only [merge, merge.loop, cond]; split <;> (next hs => rw [hs, merge_loop]; rfl)
2441+
2442+
@[simp] theorem cons_merge_cons_pos (s : α → α → Bool) (l r) (h : s a b) :
2443+
merge s (a::l) (b::r) = a :: merge s l (b::r) := by
2444+
rw [cons_merge_cons, if_pos h]
2445+
2446+
@[simp] theorem cons_merge_cons_neg (s : α → α → Bool) (l r) (h : ¬ s a b) :
2447+
merge s (a::l) (b::r) = b :: merge s (a::l) r := by
2448+
rw [cons_merge_cons, if_neg h]
2449+
2450+
@[simp] theorem length_merge (s : α → α → Bool) (l r) :
2451+
(merge s l r).length = l.length + r.length := by
2452+
match l, r with
2453+
| [], r => simp
2454+
| l, [] => simp
2455+
| a::l, b::r =>
2456+
rw [cons_merge_cons]
2457+
split
2458+
· simp_arith [length_merge s l (b::r)]
2459+
· simp_arith [length_merge s (a::l) r]
2460+
2461+
theorem mem_merge_left (s : α → α → Bool) (h : x ∈ l) : x ∈ merge s l r := by
2462+
match l, r with
2463+
| l, [] => simp [h]
2464+
| a::l, b::r =>
2465+
match mem_cons.1 h with
2466+
| .inl rfl =>
2467+
rw [cons_merge_cons]
2468+
split
2469+
· exact mem_cons_self ..
2470+
· apply mem_cons_of_mem; exact mem_merge_left s h
2471+
| .inr h' =>
2472+
rw [cons_merge_cons]
2473+
split
2474+
· apply mem_cons_of_mem; exact mem_merge_left s h'
2475+
· apply mem_cons_of_mem; exact mem_merge_left s h
2476+
2477+
theorem mem_merge_right (s : α → α → Bool) (h : x ∈ r) : x ∈ merge s l r := by
2478+
match l, r with
2479+
| [], r => simp [h]
2480+
| a::l, b::r =>
2481+
match mem_cons.1 h with
2482+
| .inl rfl =>
2483+
rw [cons_merge_cons]
2484+
split
2485+
· apply mem_cons_of_mem; exact mem_merge_right s h
2486+
· exact mem_cons_self ..
2487+
| .inr h' =>
2488+
rw [cons_merge_cons]
2489+
split
2490+
· apply mem_cons_of_mem; exact mem_merge_right s h
2491+
· apply mem_cons_of_mem; exact mem_merge_right s h'

Std/Data/List/Perm.lean

+20
Original file line numberDiff line numberDiff line change
@@ -710,3 +710,23 @@ theorem Perm.eraseP (f : α → Bool) {l₁ l₂ : List α}
710710
| trans p₁ _ IH₁ IH₂ =>
711711
refine (IH₁ H).trans (IH₂ ((p₁.pairwise_iff ?_).1 H))
712712
exact fun h h₁ h₂ => h h₂ h₁
713+
714+
theorem perm_merge (s : α → α → Bool) (l r) : merge s l r ~ l ++ r := by
715+
match l, r with
716+
| [], r => simp
717+
| l, [] => simp
718+
| a::l, b::r =>
719+
rw [cons_merge_cons]
720+
split
721+
· apply Perm.trans ((perm_cons a).mpr (perm_merge s l (b::r)))
722+
simp [cons_append]
723+
· apply Perm.trans ((perm_cons b).mpr (perm_merge s (a::l) r))
724+
simp [cons_append]
725+
apply Perm.trans (Perm.swap ..)
726+
apply Perm.cons
727+
apply perm_cons_append_cons
728+
exact Perm.rfl
729+
730+
theorem Perm.merge (s₁ s₂ : α → α → Bool) (hl : l₁ ~ l₂) (hr : r₁ ~ r₂) :
731+
merge s₁ l₁ r₁ ~ merge s₂ l₂ r₂ :=
732+
Perm.trans (perm_merge ..) <| Perm.trans (Perm.append hl hr) <| Perm.symm (perm_merge ..)

0 commit comments

Comments
 (0)