Split from #4583 `exists_of_set` appears in Batteries as `exists_of_set'`. The `exists_of_set` version is unused in batteries and mathlib at least and I would argue that the primed version (i.e., the one added in this PR) is always better anyway. `isEmpty_iff` appears in mathlib as `isEmpty_iff_eq_nil`.
396 lines
16 KiB
Text
396 lines
16 KiB
Text
/-
|
||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
|
||
-/
|
||
prelude
|
||
import Init.Data.List.Lemmas
|
||
import Init.Data.Nat.Lemmas
|
||
|
||
/-!
|
||
# Further lemmas about `List.take`, `List.drop`, `List.zip` and `List.zipWith`.
|
||
|
||
These are in a separate file from most of the list lemmas
|
||
as they required importing more lemmas about natural numbers, and use `omega`.
|
||
-/
|
||
|
||
namespace List
|
||
|
||
open Nat
|
||
|
||
/-! ### take -/
|
||
|
||
@[simp] theorem length_take : ∀ (i : Nat) (l : List α), length (take i l) = min i (length l)
|
||
| 0, l => by simp [Nat.zero_min]
|
||
| succ n, [] => by simp [Nat.min_zero]
|
||
| succ n, _ :: l => by simp [Nat.succ_min_succ, length_take]
|
||
|
||
theorem length_take_le (n) (l : List α) : length (take n l) ≤ n := by simp [Nat.min_le_left]
|
||
|
||
theorem length_take_le' (n) (l : List α) : length (take n l) ≤ l.length :=
|
||
by simp [Nat.min_le_right]
|
||
|
||
theorem length_take_of_le (h : n ≤ length l) : length (take n l) = n := by simp [Nat.min_eq_left h]
|
||
|
||
theorem take_take : ∀ (n m) (l : List α), take n (take m l) = take (min n m) l
|
||
| n, 0, l => by rw [Nat.min_zero, take_zero, take_nil]
|
||
| 0, m, l => by rw [Nat.zero_min, take_zero, take_zero]
|
||
| succ n, succ m, nil => by simp only [take_nil]
|
||
| succ n, succ m, a :: l => by
|
||
simp only [take, succ_min_succ, take_take n m l]
|
||
|
||
@[simp] theorem take_replicate (a : α) : ∀ n m : Nat, take n (replicate m a) = replicate (min n m) a
|
||
| n, 0 => by simp [Nat.min_zero]
|
||
| 0, m => by simp [Nat.zero_min]
|
||
| succ n, succ m => by simp [replicate_succ, succ_min_succ, take_replicate]
|
||
|
||
@[simp] theorem drop_replicate (a : α) : ∀ n m : Nat, drop n (replicate m a) = replicate (m - n) a
|
||
| n, 0 => by simp
|
||
| 0, m => by simp
|
||
| succ n, succ m => by simp [replicate_succ, succ_sub_succ, drop_replicate]
|
||
|
||
/-- Taking the first `n` elements in `l₁ ++ l₂` is the same as appending the first `n` elements
|
||
of `l₁` to the first `n - l₁.length` elements of `l₂`. -/
|
||
theorem take_append_eq_append_take {l₁ l₂ : List α} {n : Nat} :
|
||
take n (l₁ ++ l₂) = take n l₁ ++ take (n - l₁.length) l₂ := by
|
||
induction l₁ generalizing n
|
||
· simp
|
||
· cases n
|
||
· simp [*]
|
||
· simp only [cons_append, take_cons_succ, length_cons, succ_eq_add_one, cons.injEq,
|
||
append_cancel_left_eq, true_and, *]
|
||
congr 1
|
||
omega
|
||
|
||
theorem take_append_of_le_length {l₁ l₂ : List α} {n : Nat} (h : n ≤ l₁.length) :
|
||
(l₁ ++ l₂).take n = l₁.take n := by
|
||
simp [take_append_eq_append_take, Nat.sub_eq_zero_of_le h]
|
||
|
||
/-- Taking the first `l₁.length + i` elements in `l₁ ++ l₂` is the same as appending the first
|
||
`i` elements of `l₂` to `l₁`. -/
|
||
theorem take_append {l₁ l₂ : List α} (i : Nat) :
|
||
take (l₁.length + i) (l₁ ++ l₂) = l₁ ++ take i l₂ := by
|
||
rw [take_append_eq_append_take, take_all_of_le (Nat.le_add_right _ _), Nat.add_sub_cancel_left]
|
||
|
||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||
length `> i`. Version designed to rewrite from the big list to the small list. -/
|
||
theorem getElem_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
|
||
L[i] = (L.take j)[i]'(length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩) :=
|
||
getElem_of_eq (take_append_drop j L).symm _ ▸ getElem_append ..
|
||
|
||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||
length `> i`. Version designed to rewrite from the small list to the big list. -/
|
||
theorem getElem_take' (L : List α) {j i : Nat} {h : i < (L.take j).length} :
|
||
(L.take j)[i] =
|
||
L[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
|
||
rw [length_take, Nat.lt_min] at h; rw [getElem_take L _ h.1]
|
||
|
||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||
length `> i`. Version designed to rewrite from the big list to the small list. -/
|
||
@[deprecated getElem_take (since := "2024-06-12")]
|
||
theorem get_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
|
||
get L ⟨i, hi⟩ = get (L.take j) ⟨i, length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩⟩ := by
|
||
simp [getElem_take _ hi hj]
|
||
|
||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||
length `> i`. Version designed to rewrite from the small list to the big list. -/
|
||
@[deprecated getElem_take (since := "2024-06-12")]
|
||
theorem get_take' (L : List α) {j i} :
|
||
get (L.take j) i =
|
||
get L ⟨i.1, Nat.lt_of_lt_of_le i.2 (length_take_le' _ _)⟩ := by
|
||
simp [getElem_take']
|
||
|
||
theorem getElem?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) :
|
||
(l.take n)[m]? = none :=
|
||
getElem?_eq_none <| Nat.le_trans (length_take_le _ _) h
|
||
|
||
@[deprecated getElem?_take_eq_none (since := "2024-06-12")]
|
||
theorem get?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) :
|
||
(l.take n).get? m = none := by
|
||
simp [getElem?_take_eq_none h]
|
||
|
||
theorem getElem?_take_eq_if {l : List α} {n m : Nat} :
|
||
(l.take n)[m]? = if m < n then l[m]? else none := by
|
||
split
|
||
· next h => exact getElem?_take h
|
||
· next h => exact getElem?_take_eq_none (Nat.le_of_not_lt h)
|
||
|
||
@[deprecated getElem?_take_eq_if (since := "2024-06-12")]
|
||
theorem get?_take_eq_if {l : List α} {n m : Nat} :
|
||
(l.take n).get? m = if m < n then l.get? m else none := by
|
||
simp [getElem?_take_eq_if]
|
||
|
||
@[simp]
|
||
theorem take_eq_take :
|
||
∀ {l : List α} {m n : Nat}, l.take m = l.take n ↔ min m l.length = min n l.length
|
||
| [], m, n => by simp [Nat.min_zero]
|
||
| _ :: xs, 0, 0 => by simp
|
||
| x :: xs, m + 1, 0 => by simp [Nat.zero_min, succ_min_succ]
|
||
| x :: xs, 0, n + 1 => by simp [Nat.zero_min, succ_min_succ]
|
||
| x :: xs, m + 1, n + 1 => by simp [succ_min_succ, take_eq_take]; omega
|
||
|
||
theorem take_add (l : List α) (m n : Nat) : l.take (m + n) = l.take m ++ (l.drop m).take n := by
|
||
suffices take (m + n) (take m l ++ drop m l) = take m l ++ take n (drop m l) by
|
||
rw [take_append_drop] at this
|
||
assumption
|
||
rw [take_append_eq_append_take, take_all_of_le, append_right_inj]
|
||
· simp only [take_eq_take, length_take, length_drop]
|
||
omega
|
||
apply Nat.le_trans (m := m)
|
||
· apply length_take_le
|
||
· apply Nat.le_add_right
|
||
|
||
theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
|
||
(l.take n).dropLast = l.take n.pred := by
|
||
simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, take_take, pred_le, Nat.min_eq_left]
|
||
|
||
theorem map_eq_append_split {f : α → β} {l : List α} {s₁ s₂ : List β}
|
||
(h : map f l = s₁ ++ s₂) : ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = s₁ ∧ map f l₂ = s₂ := by
|
||
have := h
|
||
rw [← take_append_drop (length s₁) l] at this ⊢
|
||
rw [map_append] at this
|
||
refine ⟨_, _, rfl, append_inj this ?_⟩
|
||
rw [length_map, length_take, Nat.min_eq_left]
|
||
rw [← length_map l f, h, length_append]
|
||
apply Nat.le_add_right
|
||
|
||
/-! ### drop -/
|
||
|
||
theorem drop_length_cons {l : List α} (h : l ≠ []) (a : α) :
|
||
(a :: l).drop l.length = [l.getLast h] := by
|
||
induction l generalizing a with
|
||
| nil =>
|
||
cases h rfl
|
||
| cons y l ih =>
|
||
simp only [drop, length]
|
||
by_cases h₁ : l = []
|
||
· simp [h₁]
|
||
rw [getLast_cons' _ h₁]
|
||
exact ih h₁ y
|
||
|
||
/-- Dropping the elements up to `n` in `l₁ ++ l₂` is the same as dropping the elements up to `n`
|
||
in `l₁`, dropping the elements up to `n - l₁.length` in `l₂`, and appending them. -/
|
||
theorem drop_append_eq_append_drop {l₁ l₂ : List α} {n : Nat} :
|
||
drop n (l₁ ++ l₂) = drop n l₁ ++ drop (n - l₁.length) l₂ := by
|
||
induction l₁ generalizing n
|
||
· simp
|
||
· cases n
|
||
· simp [*]
|
||
· simp only [cons_append, drop_succ_cons, length_cons, succ_eq_add_one, append_cancel_left_eq, *]
|
||
congr 1
|
||
omega
|
||
|
||
theorem drop_append_of_le_length {l₁ l₂ : List α} {n : Nat} (h : n ≤ l₁.length) :
|
||
(l₁ ++ l₂).drop n = l₁.drop n ++ l₂ := by
|
||
simp [drop_append_eq_append_drop, Nat.sub_eq_zero_of_le h]
|
||
|
||
|
||
/-- Dropping the elements up to `l₁.length + i` in `l₁ + l₂` is the same as dropping the elements
|
||
up to `i` in `l₂`. -/
|
||
@[simp]
|
||
theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l₁ ++ l₂) = drop i l₂ := by
|
||
rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;>
|
||
simp [Nat.add_sub_cancel_left, Nat.le_add_right]
|
||
|
||
theorem lt_length_drop (L : List α) {i j : Nat} (h : i + j < L.length) : j < (L.drop i).length := by
|
||
have A : i < L.length := Nat.lt_of_le_of_lt (Nat.le.intro rfl) h
|
||
rw [(take_append_drop i L).symm] at h
|
||
simpa only [Nat.le_of_lt A, Nat.min_eq_left, Nat.add_lt_add_iff_left, length_take,
|
||
length_append] using h
|
||
|
||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
|
||
theorem getElem_drop (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||
L[i + j] = (L.drop i)[j]'(lt_length_drop L h) := by
|
||
have : i ≤ L.length := Nat.le_trans (Nat.le_add_right _ _) (Nat.le_of_lt h)
|
||
rw [getElem_of_eq (take_append_drop i L).symm h, getElem_append_right'] <;>
|
||
simp [Nat.min_eq_left this, Nat.add_sub_cancel_left, Nat.le_add_right]
|
||
|
||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
|
||
@[deprecated getElem_drop (since := "2024-06-12")]
|
||
theorem get_drop (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||
get L ⟨i + j, h⟩ = get (L.drop i) ⟨j, lt_length_drop L h⟩ := by
|
||
simp [getElem_drop]
|
||
|
||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
|
||
theorem getElem_drop' (L : List α) {i : Nat} {j : Nat} {h : j < (L.drop i).length} :
|
||
(L.drop i)[j] = L[i + j]'(by
|
||
rw [Nat.add_comm]
|
||
exact Nat.add_lt_of_lt_sub (length_drop i L ▸ h)) := by
|
||
rw [getElem_drop]
|
||
|
||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
|
||
@[deprecated getElem_drop' (since := "2024-06-12")]
|
||
theorem get_drop' (L : List α) {i j} :
|
||
get (L.drop i) j = get L ⟨i + j, by
|
||
rw [Nat.add_comm]
|
||
exact Nat.add_lt_of_lt_sub (length_drop i L ▸ j.2)⟩ := by
|
||
simp [getElem_drop']
|
||
|
||
@[simp]
|
||
theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? := by
|
||
ext
|
||
simp only [getElem?_eq_some, getElem_drop', Option.mem_def]
|
||
constructor <;> intro ⟨h, ha⟩
|
||
· exact ⟨_, ha⟩
|
||
· refine ⟨?_, ha⟩
|
||
rw [length_drop]
|
||
rw [Nat.add_comm] at h
|
||
apply Nat.lt_sub_of_add_lt h
|
||
|
||
@[deprecated getElem?_drop (since := "2024-06-12")]
|
||
theorem get?_drop (L : List α) (i j : Nat) : get? (L.drop i) j = get? L (i + j) := by
|
||
simp
|
||
|
||
theorem set_eq_take_append_cons_drop {l : List α} {n : Nat} {a : α} :
|
||
l.set n a = if n < l.length then l.take n ++ a :: l.drop (n + 1) else l := by
|
||
split <;> rename_i h
|
||
· ext1 m
|
||
by_cases h' : m < n
|
||
· rw [getElem?_append (by simp [length_take]; omega), getElem?_set_ne (by omega),
|
||
getElem?_take h']
|
||
· by_cases h'' : m = n
|
||
· subst h''
|
||
rw [getElem?_set_eq (by simp; omega), getElem?_append_right, length_take,
|
||
Nat.min_eq_left (by omega), Nat.sub_self, getElem?_cons_zero]
|
||
rw [length_take]
|
||
exact Nat.min_le_left m l.length
|
||
· have h''' : n < m := by omega
|
||
rw [getElem?_set_ne (by omega), getElem?_append_right, length_take,
|
||
Nat.min_eq_left (by omega)]
|
||
· obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_lt h'''
|
||
have p : n + k + 1 - n = k + 1 := by omega
|
||
rw [p]
|
||
rw [getElem?_cons_succ, getElem?_drop]
|
||
congr 1
|
||
omega
|
||
· rw [length_take]
|
||
exact Nat.le_trans (Nat.min_le_left _ _) (by omega)
|
||
· rw [set_eq_of_length_le]
|
||
omega
|
||
|
||
theorem exists_of_set {n : Nat} {a' : α} {l : List α} (h : n < l.length) :
|
||
∃ l₁ l₂, l = l₁ ++ l[n] :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by
|
||
refine ⟨l.take n, l.drop (n + 1), ⟨by simp, ⟨length_take_of_le (Nat.le_of_lt h), ?_⟩⟩⟩
|
||
simp [set_eq_take_append_cons_drop, h]
|
||
|
||
theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α)
|
||
(hnm : n < m) : drop m (l.set n a) = l.drop m :=
|
||
ext_getElem? fun k => by simpa only [getElem?_drop] using getElem?_set_ne (by omega)
|
||
|
||
theorem drop_take : ∀ (m n : Nat) (l : List α), drop n (take m l) = take (m - n) (drop n l)
|
||
| 0, _, _ => by simp
|
||
| _, 0, _ => by simp
|
||
| _, _, [] => by simp
|
||
| m+1, n+1, h :: t => by
|
||
simp [take_succ_cons, drop_succ_cons, drop_take m n t]
|
||
congr 1
|
||
omega
|
||
|
||
theorem take_reverse {α} {xs : List α} (n : Nat) (h : n ≤ xs.length) :
|
||
xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
|
||
induction xs generalizing n <;>
|
||
simp only [reverse_cons, drop, reverse_nil, Nat.zero_sub, length, take_nil]
|
||
next xs_hd xs_tl xs_ih =>
|
||
cases Nat.lt_or_eq_of_le h with
|
||
| inl h' =>
|
||
have h' := Nat.le_of_succ_le_succ h'
|
||
rw [take_append_of_le_length, xs_ih _ h']
|
||
rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
|
||
· rwa [succ_eq_add_one, Nat.sub_add_comm]
|
||
· rwa [length_reverse]
|
||
| inr h' =>
|
||
subst h'
|
||
rw [length, Nat.sub_self, drop]
|
||
suffices xs_tl.length + 1 = (xs_tl.reverse ++ [xs_hd]).length by
|
||
rw [this, take_length, reverse_cons]
|
||
rw [length_append, length_reverse]
|
||
rfl
|
||
|
||
@[deprecated (since := "2024-06-15")] abbrev reverse_take := @take_reverse
|
||
|
||
/-! ### rotateLeft -/
|
||
|
||
@[simp] theorem rotateLeft_replicate (n) (a : α) : rotateLeft (replicate m a) n = replicate m a := by
|
||
cases n with
|
||
| zero => simp
|
||
| succ n =>
|
||
suffices 1 < m → m - (n + 1) % m + min ((n + 1) % m) m = m by
|
||
simpa [rotateLeft]
|
||
intro h
|
||
rw [Nat.min_eq_left (Nat.le_of_lt (Nat.mod_lt _ (by omega)))]
|
||
have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
|
||
omega
|
||
|
||
/-! ### rotateRight -/
|
||
|
||
@[simp] theorem rotateRight_replicate (n) (a : α) : rotateRight (replicate m a) n = replicate m a := by
|
||
cases n with
|
||
| zero => simp
|
||
| succ n =>
|
||
suffices 1 < m → m - (m - (n + 1) % m) + min (m - (n + 1) % m) m = m by
|
||
simpa [rotateRight]
|
||
intro h
|
||
have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
|
||
rw [Nat.min_eq_left (by omega)]
|
||
omega
|
||
|
||
/-! ### zipWith -/
|
||
|
||
@[simp] theorem length_zipWith (f : α → β → γ) (l₁ l₂) :
|
||
length (zipWith f l₁ l₂) = min (length l₁) (length l₂) := by
|
||
induction l₁ generalizing l₂ <;> cases l₂ <;>
|
||
simp_all [succ_min_succ, Nat.zero_min, Nat.min_zero]
|
||
|
||
theorem zipWith_eq_zipWith_take_min : ∀ (l₁ : List α) (l₂ : List β),
|
||
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
|
||
| [], _ => by simp
|
||
| _, [] => by simp
|
||
| a :: l₁, b :: l₂ => by simp [succ_min_succ, zipWith_eq_zipWith_take_min l₁ l₂]
|
||
|
||
@[simp] theorem zipWith_replicate {a : α} {b : β} {m n : Nat} :
|
||
zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
|
||
rw [zipWith_eq_zipWith_take_min]
|
||
simp
|
||
|
||
/-! ### zip -/
|
||
|
||
@[simp] theorem length_zip (l₁ : List α) (l₂ : List β) :
|
||
length (zip l₁ l₂) = min (length l₁) (length l₂) := by
|
||
simp [zip]
|
||
|
||
theorem zip_eq_zip_take_min : ∀ (l₁ : List α) (l₂ : List β),
|
||
zip l₁ l₂ = zip (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
|
||
| [], _ => by simp
|
||
| _, [] => by simp
|
||
| a :: l₁, b :: l₂ => by simp [succ_min_succ, zip_eq_zip_take_min l₁ l₂]
|
||
|
||
@[simp] theorem zip_replicate {a : α} {b : β} {m n : Nat} :
|
||
zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
|
||
rw [zip_eq_zip_take_min]
|
||
simp
|
||
|
||
/-! ### minimum? -/
|
||
|
||
-- A specialization of `minimum?_eq_some_iff` to Nat.
|
||
theorem minimum?_eq_some_iff' {xs : List Nat} :
|
||
xs.minimum? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, a ≤ b) :=
|
||
minimum?_eq_some_iff
|
||
(le_refl := Nat.le_refl)
|
||
(min_eq_or := fun _ _ => by omega)
|
||
(le_min_iff := fun _ _ _ => by omega)
|
||
|
||
/-! ### maximum? -/
|
||
|
||
-- A specialization of `maximum?_eq_some_iff` to Nat.
|
||
theorem maximum?_eq_some_iff' {xs : List Nat} :
|
||
xs.maximum? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, b ≤ a) :=
|
||
maximum?_eq_some_iff
|
||
(le_refl := Nat.le_refl)
|
||
(max_eq_or := fun _ _ => by omega)
|
||
(max_le_iff := fun _ _ _ => by omega)
|
||
|
||
end List
|