1100 lines
44 KiB
Text
1100 lines
44 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,
|
||
Kim Morrison
|
||
-/
|
||
prelude
|
||
import Init.Data.List.TakeDrop
|
||
|
||
/-!
|
||
# Lemmas about `List.Subset`, `List.Sublist`, `List.IsPrefix`, `List.IsSuffix`, and `List.IsInfix`.
|
||
-/
|
||
|
||
-- set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||
|
||
namespace List
|
||
|
||
open Nat
|
||
|
||
/-! ### isPrefixOf -/
|
||
section isPrefixOf
|
||
variable [BEq α]
|
||
|
||
@[simp] theorem isPrefixOf_cons₂_self [LawfulBEq α] {a : α} :
|
||
isPrefixOf (a::as) (a::bs) = isPrefixOf as bs := by simp [isPrefixOf_cons₂]
|
||
|
||
@[simp] theorem isPrefixOf_length_pos_nil {l : List α} (h : 0 < l.length) : isPrefixOf l [] = false := by
|
||
cases l <;> simp_all [isPrefixOf]
|
||
|
||
@[simp] theorem isPrefixOf_replicate {a : α} :
|
||
isPrefixOf l (replicate n a) = (decide (l.length ≤ n) && l.all (· == a)) := by
|
||
induction l generalizing n with
|
||
| nil => simp
|
||
| cons _ _ ih =>
|
||
cases n
|
||
· simp
|
||
· simp [replicate_succ, isPrefixOf_cons₂, ih, Nat.succ_le_succ_iff, Bool.and_left_comm]
|
||
|
||
end isPrefixOf
|
||
|
||
/-! ### isSuffixOf -/
|
||
section isSuffixOf
|
||
variable [BEq α]
|
||
|
||
@[simp] theorem isSuffixOf_cons_nil : isSuffixOf (a::as) ([] : List α) = false := by
|
||
simp [isSuffixOf]
|
||
|
||
@[simp] theorem isSuffixOf_replicate {a : α} :
|
||
isSuffixOf l (replicate n a) = (decide (l.length ≤ n) && l.all (· == a)) := by
|
||
simp [isSuffixOf, all_eq]
|
||
|
||
end isSuffixOf
|
||
|
||
/-! ### Subset -/
|
||
|
||
/-! ### List subset -/
|
||
|
||
theorem subset_def {l₁ l₂ : List α} : l₁ ⊆ l₂ ↔ ∀ {a : α}, a ∈ l₁ → a ∈ l₂ := .rfl
|
||
|
||
@[simp] theorem nil_subset (l : List α) : [] ⊆ l := nofun
|
||
|
||
@[simp] theorem Subset.refl (l : List α) : l ⊆ l := fun _ i => i
|
||
|
||
theorem Subset.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ ⊆ l₂) (h₂ : l₂ ⊆ l₃) : l₁ ⊆ l₃ :=
|
||
fun _ i => h₂ (h₁ i)
|
||
|
||
instance : Trans (fun l₁ l₂ => Subset l₂ l₁) (Membership.mem : List α → α → Prop) Membership.mem :=
|
||
⟨fun h₁ h₂ => h₁ h₂⟩
|
||
|
||
instance : Trans (Subset : List α → List α → Prop) Subset Subset :=
|
||
⟨Subset.trans⟩
|
||
|
||
theorem subset_cons_self (a : α) (l : List α) : l ⊆ a :: l := fun _ => Mem.tail _
|
||
|
||
theorem subset_of_cons_subset {a : α} {l₁ l₂ : List α} : a :: l₁ ⊆ l₂ → l₁ ⊆ l₂ :=
|
||
fun s _ i => s (mem_cons_of_mem _ i)
|
||
|
||
@[simp] theorem subset_cons_of_subset (a : α) {l₁ l₂ : List α} : l₁ ⊆ l₂ → l₁ ⊆ a :: l₂ :=
|
||
fun s _ i => .tail _ (s i)
|
||
|
||
theorem cons_subset_cons {l₁ l₂ : List α} (a : α) (s : l₁ ⊆ l₂) : a :: l₁ ⊆ a :: l₂ :=
|
||
fun _ => by simp only [mem_cons]; exact Or.imp_right (@s _)
|
||
|
||
@[simp] theorem cons_subset : a :: l ⊆ m ↔ a ∈ m ∧ l ⊆ m := by
|
||
simp only [subset_def, mem_cons, or_imp, forall_and, forall_eq]
|
||
|
||
@[simp] theorem subset_nil {l : List α} : l ⊆ [] ↔ l = [] :=
|
||
⟨fun h => match l with | [] => rfl | _::_ => (nomatch h (.head ..)), fun | rfl => Subset.refl _⟩
|
||
|
||
theorem eq_nil_of_subset_nil {l : List α} : l ⊆ [] → l = [] := subset_nil.mp
|
||
|
||
theorem map_subset {l₁ l₂ : List α} (f : α → β) (h : l₁ ⊆ l₂) : map f l₁ ⊆ map f l₂ :=
|
||
fun x => by simp only [mem_map]; exact .imp fun a => .imp_left (@h _)
|
||
|
||
theorem filter_subset {l₁ l₂ : List α} (p : α → Bool) (H : l₁ ⊆ l₂) : filter p l₁ ⊆ filter p l₂ :=
|
||
fun x => by simp_all [mem_filter, subset_def.1 H]
|
||
|
||
theorem filterMap_subset {l₁ l₂ : List α} (f : α → Option β) (H : l₁ ⊆ l₂) :
|
||
filterMap f l₁ ⊆ filterMap f l₂ := by
|
||
intro x
|
||
simp only [mem_filterMap]
|
||
rintro ⟨a, h, w⟩
|
||
exact ⟨a, H h, w⟩
|
||
|
||
theorem subset_append_left (l₁ l₂ : List α) : l₁ ⊆ l₁ ++ l₂ := fun _ => mem_append_left _
|
||
|
||
theorem subset_append_right (l₁ l₂ : List α) : l₂ ⊆ l₁ ++ l₂ := fun _ => mem_append_right _
|
||
|
||
@[simp] theorem subset_append_of_subset_left (l₂ : List α) : l ⊆ l₁ → l ⊆ l₁ ++ l₂ :=
|
||
fun s => Subset.trans s <| subset_append_left _ _
|
||
|
||
@[simp] theorem subset_append_of_subset_right (l₁ : List α) : l ⊆ l₂ → l ⊆ l₁ ++ l₂ :=
|
||
fun s => Subset.trans s <| subset_append_right _ _
|
||
|
||
@[simp] theorem append_subset {l₁ l₂ l : List α} :
|
||
l₁ ++ l₂ ⊆ l ↔ l₁ ⊆ l ∧ l₂ ⊆ l := by simp [subset_def, or_imp, forall_and]
|
||
|
||
theorem replicate_subset {n : Nat} {a : α} {l : List α} : replicate n a ⊆ l ↔ n = 0 ∨ a ∈ l := by
|
||
induction n with
|
||
| zero => simp
|
||
| succ n ih => simp +contextual [replicate_succ, ih, cons_subset]
|
||
|
||
theorem subset_replicate {n : Nat} {a : α} {l : List α} (h : n ≠ 0) : l ⊆ replicate n a ↔ ∀ x ∈ l, x = a := by
|
||
induction l with
|
||
| nil => simp
|
||
| cons x xs ih =>
|
||
simp only [cons_subset, mem_replicate, ne_eq, ih, mem_cons, forall_eq_or_imp,
|
||
and_congr_left_iff, and_iff_right_iff_imp]
|
||
solve_by_elim
|
||
|
||
@[simp] theorem reverse_subset {l₁ l₂ : List α} : reverse l₁ ⊆ l₂ ↔ l₁ ⊆ l₂ := by
|
||
simp [subset_def]
|
||
|
||
@[simp] theorem subset_reverse {l₁ l₂ : List α} : l₁ ⊆ reverse l₂ ↔ l₁ ⊆ l₂ := by
|
||
simp [subset_def]
|
||
|
||
/-! ### Sublist and isSublist -/
|
||
|
||
@[simp] theorem nil_sublist : ∀ l : List α, [] <+ l
|
||
| [] => .slnil
|
||
| a :: l => (nil_sublist l).cons a
|
||
|
||
@[simp] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||
| [] => .slnil
|
||
| a :: l => (Sublist.refl l).cons₂ a
|
||
|
||
theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l₂ <+ l₃) : l₁ <+ l₃ := by
|
||
induction h₂ generalizing l₁ with
|
||
| slnil => exact h₁
|
||
| cons _ _ IH => exact (IH h₁).cons _
|
||
| @cons₂ l₂ _ a _ IH =>
|
||
generalize e : a :: l₂ = l₂'
|
||
match e ▸ h₁ with
|
||
| .slnil => apply nil_sublist
|
||
| .cons a' h₁' => cases e; apply (IH h₁').cons
|
||
| .cons₂ a' h₁' => cases e; apply (IH h₁').cons₂
|
||
|
||
instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩
|
||
|
||
attribute [simp] Sublist.cons
|
||
|
||
theorem sublist_cons_self (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _
|
||
|
||
theorem sublist_of_cons_sublist : a :: l₁ <+ l₂ → l₁ <+ l₂ :=
|
||
(sublist_cons_self a l₁).trans
|
||
|
||
@[simp]
|
||
theorem cons_sublist_cons : a :: l₁ <+ a :: l₂ ↔ l₁ <+ l₂ :=
|
||
⟨fun | .cons _ s => sublist_of_cons_sublist s | .cons₂ _ s => s, .cons₂ _⟩
|
||
|
||
theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l₂ ∨ a ∈ l := by
|
||
induction l₁ generalizing l with
|
||
| nil => match h with
|
||
| .cons _ h => exact .inl h
|
||
| .cons₂ _ h => exact .inr (.head ..)
|
||
| cons b l₁ IH =>
|
||
match h with
|
||
| .cons _ h => exact (IH h).imp_left (Sublist.cons _)
|
||
| .cons₂ _ h => exact (IH h).imp (Sublist.cons₂ _) (.tail _)
|
||
|
||
theorem Sublist.subset : l₁ <+ l₂ → l₁ ⊆ l₂
|
||
| .slnil, _, h => h
|
||
| .cons _ s, _, h => .tail _ (s.subset h)
|
||
| .cons₂ .., _, .head .. => .head ..
|
||
| .cons₂ _ s, _, .tail _ h => .tail _ (s.subset h)
|
||
|
||
protected theorem Sublist.mem (hx : a ∈ l₁) (hl : l₁ <+ l₂) : a ∈ l₂ :=
|
||
hl.subset hx
|
||
|
||
theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h ∈ xs :=
|
||
s.mem (List.head_mem h)
|
||
|
||
theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h ∈ xs :=
|
||
s.mem (List.getLast_mem h)
|
||
|
||
instance : Trans (@Sublist α) Subset Subset :=
|
||
⟨fun h₁ h₂ => trans h₁.subset h₂⟩
|
||
|
||
instance : Trans Subset (@Sublist α) Subset :=
|
||
⟨fun h₁ h₂ => trans h₁ h₂.subset⟩
|
||
|
||
instance : Trans (fun l₁ l₂ => Sublist l₂ l₁) (Membership.mem : List α → α → Prop) Membership.mem :=
|
||
⟨fun h₁ h₂ => h₁.subset h₂⟩
|
||
|
||
theorem mem_of_cons_sublist {a : α} {l₁ l₂ : List α} (s : a :: l₁ <+ l₂) : a ∈ l₂ :=
|
||
(cons_subset.1 s.subset).1
|
||
|
||
@[simp] theorem sublist_nil {l : List α} : l <+ [] ↔ l = [] :=
|
||
⟨fun s => subset_nil.1 s.subset, fun H => H ▸ Sublist.refl _⟩
|
||
|
||
theorem eq_nil_of_sublist_nil {l : List α} (s : l <+ []) : l = [] :=
|
||
eq_nil_of_subset_nil <| s.subset
|
||
|
||
theorem Sublist.length_le : l₁ <+ l₂ → length l₁ ≤ length l₂
|
||
| .slnil => Nat.le_refl 0
|
||
| .cons _l s => le_succ_of_le (length_le s)
|
||
| .cons₂ _ s => succ_le_succ (length_le s)
|
||
|
||
theorem Sublist.eq_of_length : l₁ <+ l₂ → length l₁ = length l₂ → l₁ = l₂
|
||
| .slnil, _ => rfl
|
||
| .cons a s, h => nomatch Nat.not_lt.2 s.length_le (h ▸ lt_succ_self _)
|
||
| .cons₂ a s, h => by rw [s.eq_of_length (succ.inj h)]
|
||
|
||
theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l₁) : l₁ = l₂ :=
|
||
s.eq_of_length <| Nat.le_antisymm s.length_le h
|
||
|
||
theorem Sublist.length_eq (s : l₁ <+ l₂) : length l₁ = length l₂ ↔ l₁ = l₂ :=
|
||
⟨s.eq_of_length, congrArg _⟩
|
||
|
||
theorem tail_sublist : ∀ l : List α, tail l <+ l
|
||
| [] => .slnil
|
||
| a::l => sublist_cons_self a l
|
||
|
||
protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tail l₁ <+ tail l₂
|
||
| _, _, slnil => .slnil
|
||
| _, _, Sublist.cons _ h => (tail_sublist _).trans h
|
||
| _, _, Sublist.cons₂ _ h => h
|
||
|
||
theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ :=
|
||
h.tail
|
||
|
||
protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : map f l₁ <+ map f l₂ := by
|
||
induction s with
|
||
| slnil => simp
|
||
| cons a s ih =>
|
||
simpa using cons (f a) ih
|
||
| cons₂ a s ih =>
|
||
simpa using cons₂ (f a) ih
|
||
|
||
protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
|
||
filterMap f l₁ <+ filterMap f l₂ := by
|
||
induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons, cons₂]
|
||
|
||
protected theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by
|
||
rw [← filterMap_eq_filter]; apply s.filterMap
|
||
|
||
theorem head_filter_mem (xs : List α) (p : α → Bool) (h) : (xs.filter p).head h ∈ xs :=
|
||
(filter_sublist xs).head_mem h
|
||
|
||
theorem getLast_filter_mem (xs : List α) (p : α → Bool) (h) : (xs.filter p).getLast h ∈ xs :=
|
||
(filter_sublist xs).getLast_mem h
|
||
|
||
theorem sublist_filterMap_iff {l₁ : List β} {f : α → Option β} :
|
||
l₁ <+ l₂.filterMap f ↔ ∃ l', l' <+ l₂ ∧ l₁ = l'.filterMap f := by
|
||
induction l₂ generalizing l₁ with
|
||
| nil => simp
|
||
| cons a l₂ ih =>
|
||
simp only [filterMap_cons]
|
||
split
|
||
· simp only [ih]
|
||
constructor
|
||
· rintro ⟨l', h, rfl⟩
|
||
exact ⟨l', Sublist.cons a h, rfl⟩
|
||
· rintro ⟨l', h, rfl⟩
|
||
cases h with
|
||
| cons _ h =>
|
||
exact ⟨l', h, rfl⟩
|
||
| cons₂ _ h =>
|
||
rename_i l'
|
||
exact ⟨l', h, by simp_all⟩
|
||
· constructor
|
||
· intro w
|
||
cases w with
|
||
| cons _ h =>
|
||
obtain ⟨l', s, rfl⟩ := ih.1 h
|
||
exact ⟨l', Sublist.cons a s, rfl⟩
|
||
| cons₂ _ h =>
|
||
rename_i l'
|
||
obtain ⟨l', s, rfl⟩ := ih.1 h
|
||
refine ⟨a :: l', Sublist.cons₂ a s, ?_⟩
|
||
rwa [filterMap_cons_some]
|
||
· rintro ⟨l', h, rfl⟩
|
||
replace h := h.filterMap f
|
||
rwa [filterMap_cons_some] at h
|
||
assumption
|
||
|
||
theorem sublist_map_iff {l₁ : List β} {f : α → β} :
|
||
l₁ <+ l₂.map f ↔ ∃ l', l' <+ l₂ ∧ l₁ = l'.map f := by
|
||
simp only [← filterMap_eq_map, sublist_filterMap_iff]
|
||
|
||
theorem sublist_filter_iff {l₁ : List α} {p : α → Bool} :
|
||
l₁ <+ l₂.filter p ↔ ∃ l', l' <+ l₂ ∧ l₁ = l'.filter p := by
|
||
simp only [← filterMap_eq_filter, sublist_filterMap_iff]
|
||
|
||
theorem sublist_append_left : ∀ l₁ l₂ : List α, l₁ <+ l₁ ++ l₂
|
||
| [], _ => nil_sublist _
|
||
| _ :: l₁, l₂ => (sublist_append_left l₁ l₂).cons₂ _
|
||
|
||
theorem sublist_append_right : ∀ l₁ l₂ : List α, l₂ <+ l₁ ++ l₂
|
||
| [], _ => Sublist.refl _
|
||
| _ :: l₁, l₂ => (sublist_append_right l₁ l₂).cons _
|
||
|
||
@[simp] theorem singleton_sublist {a : α} {l} : [a] <+ l ↔ a ∈ l := by
|
||
refine ⟨fun h => h.subset (mem_singleton_self _), fun h => ?_⟩
|
||
obtain ⟨_, _, rfl⟩ := append_of_mem h
|
||
exact ((nil_sublist _).cons₂ _).trans (sublist_append_right ..)
|
||
|
||
@[simp] theorem sublist_append_of_sublist_left (s : l <+ l₁) : l <+ l₁ ++ l₂ :=
|
||
s.trans <| sublist_append_left ..
|
||
|
||
@[simp] theorem sublist_append_of_sublist_right (s : l <+ l₂) : l <+ l₁ ++ l₂ :=
|
||
s.trans <| sublist_append_right ..
|
||
|
||
@[simp] theorem append_sublist_append_left : ∀ l, l ++ l₁ <+ l ++ l₂ ↔ l₁ <+ l₂
|
||
| [] => Iff.rfl
|
||
| _ :: l => cons_sublist_cons.trans (append_sublist_append_left l)
|
||
|
||
theorem Sublist.append_left : l₁ <+ l₂ → ∀ l, l ++ l₁ <+ l ++ l₂ :=
|
||
fun h l => (append_sublist_append_left l).mpr h
|
||
|
||
theorem Sublist.append_right : l₁ <+ l₂ → ∀ l, l₁ ++ l <+ l₂ ++ l
|
||
| .slnil, _ => Sublist.refl _
|
||
| .cons _ h, _ => (h.append_right _).cons _
|
||
| .cons₂ _ h, _ => (h.append_right _).cons₂ _
|
||
|
||
theorem Sublist.append (hl : l₁ <+ l₂) (hr : r₁ <+ r₂) : l₁ ++ r₁ <+ l₂ ++ r₂ :=
|
||
(hl.append_right _).trans ((append_sublist_append_left _).2 hr)
|
||
|
||
theorem sublist_cons_iff {a : α} {l l'} :
|
||
l <+ a :: l' ↔ l <+ l' ∨ ∃ r, l = a :: r ∧ r <+ l' := by
|
||
constructor
|
||
· intro h
|
||
cases h with
|
||
| cons _ h => exact Or.inl h
|
||
| cons₂ _ h => exact Or.inr ⟨_, rfl, h⟩
|
||
· rintro (h | ⟨r, rfl, h⟩)
|
||
· exact h.cons _
|
||
· exact h.cons₂ _
|
||
|
||
theorem cons_sublist_iff {a : α} {l l'} :
|
||
a :: l <+ l' ↔ ∃ r₁ r₂, l' = r₁ ++ r₂ ∧ a ∈ r₁ ∧ l <+ r₂ := by
|
||
induction l' with
|
||
| nil => simp
|
||
| cons a' l' ih =>
|
||
constructor
|
||
· intro w
|
||
cases w with
|
||
| cons _ w =>
|
||
obtain ⟨r₁, r₂, rfl, h₁, h₂⟩ := ih.1 w
|
||
exact ⟨a' :: r₁, r₂, by simp, mem_cons_of_mem a' h₁, h₂⟩
|
||
| cons₂ _ w =>
|
||
exact ⟨[a], l', by simp, mem_singleton_self _, w⟩
|
||
· rintro ⟨r₁, r₂, w, h₁, h₂⟩
|
||
rw [w, ← singleton_append]
|
||
exact Sublist.append (by simpa) h₂
|
||
|
||
theorem sublist_append_iff {l : List α} :
|
||
l <+ r₁ ++ r₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ l₁ <+ r₁ ∧ l₂ <+ r₂ := by
|
||
induction r₁ generalizing l with
|
||
| nil =>
|
||
constructor
|
||
· intro w
|
||
refine ⟨[], l, by simp_all⟩
|
||
· rintro ⟨l₁, l₂, rfl, w₁, w₂⟩
|
||
simp_all
|
||
| cons r r₁ ih =>
|
||
constructor
|
||
· intro w
|
||
simp only [cons_append] at w
|
||
cases w with
|
||
| cons _ w =>
|
||
obtain ⟨l₁, l₂, rfl, w₁, w₂⟩ := ih.1 w
|
||
exact ⟨l₁, l₂, rfl, Sublist.cons r w₁, w₂⟩
|
||
| cons₂ _ w =>
|
||
rename_i l
|
||
obtain ⟨l₁, l₂, rfl, w₁, w₂⟩ := ih.1 w
|
||
refine ⟨r :: l₁, l₂, by simp, cons_sublist_cons.mpr w₁, w₂⟩
|
||
· rintro ⟨l₁, l₂, rfl, w₁, w₂⟩
|
||
cases w₁ with
|
||
| cons _ w₁ =>
|
||
exact Sublist.cons _ (Sublist.append w₁ w₂)
|
||
| cons₂ _ w₁ =>
|
||
rename_i l
|
||
exact Sublist.cons₂ _ (Sublist.append w₁ w₂)
|
||
|
||
theorem append_sublist_iff {l₁ l₂ : List α} :
|
||
l₁ ++ l₂ <+ r ↔ ∃ r₁ r₂, r = r₁ ++ r₂ ∧ l₁ <+ r₁ ∧ l₂ <+ r₂ := by
|
||
induction l₁ generalizing r with
|
||
| nil =>
|
||
constructor
|
||
· intro w
|
||
refine ⟨[], r, by simp_all⟩
|
||
· rintro ⟨r₁, r₂, rfl, -, w₂⟩
|
||
simp only [nil_append]
|
||
exact sublist_append_of_sublist_right w₂
|
||
| cons a l₁ ih =>
|
||
constructor
|
||
· rw [cons_append, cons_sublist_iff]
|
||
rintro ⟨r₁, r₂, rfl, h₁, h₂⟩
|
||
obtain ⟨s₁, s₂, rfl, t₁, t₂⟩ := ih.1 h₂
|
||
refine ⟨r₁ ++ s₁, s₂, by simp, ?_, t₂⟩
|
||
rw [← singleton_append]
|
||
exact Sublist.append (by simpa) t₁
|
||
· rintro ⟨r₁, r₂, rfl, h₁, h₂⟩
|
||
exact Sublist.append h₁ h₂
|
||
|
||
theorem Sublist.of_sublist_append_left (w : ∀ a, a ∈ l → a ∉ l₂) (h : l <+ l₁ ++ l₂) : l <+ l₁ := by
|
||
rw [sublist_append_iff] at h
|
||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||
have : l₂' = [] := by
|
||
rw [eq_nil_iff_forall_not_mem]
|
||
exact fun x m => w x (mem_append_right l₁' m) (h₂.mem m)
|
||
simp_all
|
||
|
||
theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h : l <+ l₁ ++ l₂) : l <+ l₂ := by
|
||
rw [sublist_append_iff] at h
|
||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||
have : l₁' = [] := by
|
||
rw [eq_nil_iff_forall_not_mem]
|
||
exact fun x m => w x (mem_append_left l₂' m) (h₁.mem m)
|
||
simp_all
|
||
|
||
theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l₁ ++ a :: l₂ := by
|
||
rw [sublist_append_iff] at h
|
||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||
exact Sublist.append h₁ (h₂.cons a)
|
||
|
||
theorem Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse
|
||
| .slnil => Sublist.refl _
|
||
| .cons _ h => by rw [reverse_cons]; exact sublist_append_of_sublist_left h.reverse
|
||
| .cons₂ _ h => by rw [reverse_cons, reverse_cons]; exact h.reverse.append_right _
|
||
|
||
@[simp] theorem reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ :=
|
||
⟨fun h => l₁.reverse_reverse ▸ l₂.reverse_reverse ▸ h.reverse, Sublist.reverse⟩
|
||
|
||
theorem sublist_reverse_iff : l₁ <+ l₂.reverse ↔ l₁.reverse <+ l₂ :=
|
||
by rw [← reverse_sublist, reverse_reverse]
|
||
|
||
@[simp] theorem append_sublist_append_right (l) : l₁ ++ l <+ l₂ ++ l ↔ l₁ <+ l₂ :=
|
||
⟨fun h => by
|
||
have := h.reverse
|
||
simp only [reverse_append, append_sublist_append_left, reverse_sublist] at this
|
||
exact this,
|
||
fun h => h.append_right l⟩
|
||
|
||
@[simp] theorem replicate_sublist_replicate {m n} (a : α) :
|
||
replicate m a <+ replicate n a ↔ m ≤ n := by
|
||
refine ⟨fun h => ?_, fun h => ?_⟩
|
||
· have := h.length_le; simp only [length_replicate] at this ⊢; exact this
|
||
· induction h with
|
||
| refl => apply Sublist.refl
|
||
| step => simp [*, replicate, Sublist.cons]
|
||
|
||
theorem sublist_replicate_iff : l <+ replicate m a ↔ ∃ n, n ≤ m ∧ l = replicate n a := by
|
||
induction l generalizing m with
|
||
| nil =>
|
||
simp only [nil_sublist, true_iff]
|
||
exact ⟨0, zero_le m, by simp⟩
|
||
| cons b l ih =>
|
||
constructor
|
||
· intro w
|
||
cases m with
|
||
| zero => simp at w
|
||
| succ m =>
|
||
simp [replicate_succ] at w
|
||
cases w with
|
||
| cons _ w =>
|
||
obtain ⟨n, le, rfl⟩ := ih.1 (sublist_of_cons_sublist w)
|
||
obtain rfl := (mem_replicate.1 (mem_of_cons_sublist w)).2
|
||
exact ⟨n+1, Nat.add_le_add_right le 1, rfl⟩
|
||
| cons₂ _ w =>
|
||
obtain ⟨n, le, rfl⟩ := ih.1 w
|
||
refine ⟨n+1, Nat.add_le_add_right le 1, by simp [replicate_succ]⟩
|
||
· rintro ⟨n, le, w⟩
|
||
rw [w]
|
||
exact (replicate_sublist_replicate a).2 le
|
||
|
||
theorem sublist_flatten_of_mem {L : List (List α)} {l} (h : l ∈ L) : l <+ L.flatten := by
|
||
induction L with
|
||
| nil => cases h
|
||
| cons l' L ih =>
|
||
rcases mem_cons.1 h with (rfl | h)
|
||
· simp [h]
|
||
· simp [ih h, flatten_cons, sublist_append_of_sublist_right]
|
||
|
||
theorem sublist_flatten_iff {L : List (List α)} {l} :
|
||
l <+ L.flatten ↔
|
||
∃ L' : List (List α), l = L'.flatten ∧ ∀ i (_ : i < L'.length), L'[i] <+ L[i]?.getD [] := by
|
||
induction L generalizing l with
|
||
| nil =>
|
||
constructor
|
||
· intro w
|
||
simp only [flatten_nil, sublist_nil] at w
|
||
subst w
|
||
exact ⟨[], by simp, fun i x => by cases x⟩
|
||
· rintro ⟨L', rfl, h⟩
|
||
simp only [flatten_nil, sublist_nil, flatten_eq_nil_iff]
|
||
simp only [getElem?_nil, Option.getD_none, sublist_nil] at h
|
||
exact (forall_getElem (p := (· = []))).1 h
|
||
| cons l' L ih =>
|
||
simp only [flatten_cons, sublist_append_iff, ih]
|
||
constructor
|
||
· rintro ⟨l₁, l₂, rfl, s, L', rfl, h⟩
|
||
refine ⟨l₁ :: L', by simp, ?_⟩
|
||
intro i lt
|
||
cases i <;> simp_all
|
||
· rintro ⟨L', rfl, h⟩
|
||
cases L' with
|
||
| nil =>
|
||
exact ⟨[], [], by simp, by simp, [], by simp, fun i x => by cases x⟩
|
||
| cons l₁ L' =>
|
||
exact ⟨l₁, L'.flatten, by simp, by simpa using h 0 (by simp), L', rfl,
|
||
fun i lt => by simpa using h (i+1) (Nat.add_lt_add_right lt 1)⟩
|
||
|
||
theorem flatten_sublist_iff {L : List (List α)} {l} :
|
||
L.flatten <+ l ↔
|
||
∃ L' : List (List α), l = L'.flatten ∧ ∀ i (_ : i < L.length), L[i] <+ L'[i]?.getD [] := by
|
||
induction L generalizing l with
|
||
| nil =>
|
||
constructor
|
||
· intro _
|
||
exact ⟨[l], by simp, fun i x => by cases x⟩
|
||
· rintro ⟨L', rfl, _⟩
|
||
simp only [flatten_nil, nil_sublist]
|
||
| cons l' L ih =>
|
||
simp only [flatten_cons, append_sublist_iff, ih]
|
||
constructor
|
||
· rintro ⟨l₁, l₂, rfl, s, L', rfl, h⟩
|
||
refine ⟨l₁ :: L', by simp, ?_⟩
|
||
intro i lt
|
||
cases i <;> simp_all
|
||
· rintro ⟨L', rfl, h⟩
|
||
cases L' with
|
||
| nil =>
|
||
exact ⟨[], [], by simp, by simpa using h 0 (by simp), [], by simp,
|
||
fun i x => by simpa using h (i+1) (Nat.add_lt_add_right x 1)⟩
|
||
| cons l₁ L' =>
|
||
exact ⟨l₁, L'.flatten, by simp, by simpa using h 0 (by simp), L', rfl,
|
||
fun i lt => by simpa using h (i+1) (Nat.add_lt_add_right lt 1)⟩
|
||
|
||
@[simp] theorem isSublist_iff_sublist [BEq α] [LawfulBEq α] {l₁ l₂ : List α} :
|
||
l₁.isSublist l₂ ↔ l₁ <+ l₂ := by
|
||
cases l₁ <;> cases l₂ <;> simp [isSublist]
|
||
case cons.cons hd₁ tl₁ hd₂ tl₂ =>
|
||
if h_eq : hd₁ = hd₂ then
|
||
simp [h_eq, cons_sublist_cons, isSublist_iff_sublist]
|
||
else
|
||
simp only [beq_iff_eq, h_eq]
|
||
constructor
|
||
· intro h_sub
|
||
apply Sublist.cons
|
||
exact isSublist_iff_sublist.mp h_sub
|
||
· intro h_sub
|
||
cases h_sub
|
||
case cons h_sub =>
|
||
exact isSublist_iff_sublist.mpr h_sub
|
||
case cons₂ =>
|
||
contradiction
|
||
|
||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
|
||
decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist
|
||
|
||
protected theorem Sublist.drop : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∀ i, l₁.drop i <+ l₂.drop i
|
||
| _, _, h, 0 => h
|
||
| _, _, h, i + 1 => by rw [← drop_tail, ← drop_tail]; exact h.tail.drop i
|
||
|
||
/-! ### IsPrefix / IsSuffix / IsInfix -/
|
||
|
||
@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||
|
||
@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||
|
||
theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := ⟨l₁, l₃, rfl⟩
|
||
|
||
@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||
rw [← List.append_assoc]; apply infix_append
|
||
|
||
theorem IsPrefix.isInfix : l₁ <+: l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ => ⟨[], t, h⟩
|
||
|
||
theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ => ⟨t, [], by rw [h, append_nil]⟩
|
||
|
||
@[simp] theorem nil_prefix {l : List α} : [] <+: l := ⟨l, rfl⟩
|
||
|
||
@[simp] theorem nil_suffix {l : List α} : [] <:+ l := ⟨l, append_nil _⟩
|
||
|
||
@[simp] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
|
||
|
||
theorem prefix_refl (l : List α) : l <+: l := ⟨[], append_nil _⟩
|
||
@[simp] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
|
||
|
||
theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
|
||
@[simp] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
|
||
|
||
theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
|
||
@[simp] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||
|
||
@[simp] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||
|
||
theorem infix_cons : l₁ <:+: l₂ → l₁ <:+: a :: l₂ := fun ⟨l₁', l₂', h⟩ => ⟨a :: l₁', l₂', h ▸ rfl⟩
|
||
|
||
theorem infix_concat : l₁ <:+: l₂ → l₁ <:+: concat l₂ a := fun ⟨l₁', l₂', h⟩ =>
|
||
⟨l₁', concat l₂' a, by simp [← h, concat_eq_append, append_assoc]⟩
|
||
|
||
theorem IsPrefix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <+: l₂ → l₂ <+: l₃ → l₁ <+: l₃
|
||
| _, _, _, ⟨r₁, rfl⟩, ⟨r₂, rfl⟩ => ⟨r₁ ++ r₂, (append_assoc _ _ _).symm⟩
|
||
|
||
theorem IsSuffix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <:+ l₂ → l₂ <:+ l₃ → l₁ <:+ l₃
|
||
| _, _, _, ⟨l₁, rfl⟩, ⟨l₂, rfl⟩ => ⟨l₂ ++ l₁, append_assoc _ _ _⟩
|
||
|
||
theorem IsInfix.trans : ∀ {l₁ l₂ l₃ : List α}, l₁ <:+: l₂ → l₂ <:+: l₃ → l₁ <:+: l₃
|
||
| l, _, _, ⟨l₁, r₁, rfl⟩, ⟨l₂, r₂, rfl⟩ => ⟨l₂ ++ l₁, r₁ ++ r₂, by simp only [append_assoc]⟩
|
||
|
||
protected theorem IsInfix.sublist : l₁ <:+: l₂ → l₁ <+ l₂
|
||
| ⟨_, _, h⟩ => h ▸ (sublist_append_right ..).trans (sublist_append_left ..)
|
||
|
||
protected theorem IsInfix.subset (hl : l₁ <:+: l₂) : l₁ ⊆ l₂ :=
|
||
hl.sublist.subset
|
||
|
||
protected theorem IsPrefix.sublist (h : l₁ <+: l₂) : l₁ <+ l₂ :=
|
||
h.isInfix.sublist
|
||
|
||
protected theorem IsPrefix.subset (hl : l₁ <+: l₂) : l₁ ⊆ l₂ :=
|
||
hl.sublist.subset
|
||
|
||
protected theorem IsSuffix.sublist (h : l₁ <:+ l₂) : l₁ <+ l₂ :=
|
||
h.isInfix.sublist
|
||
|
||
protected theorem IsSuffix.subset (hl : l₁ <:+ l₂) : l₁ ⊆ l₂ :=
|
||
hl.sublist.subset
|
||
|
||
@[simp] theorem infix_nil : l <:+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ infix_rfl)⟩
|
||
|
||
@[simp] theorem prefix_nil : l <+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ prefix_rfl)⟩
|
||
|
||
@[simp] theorem suffix_nil : l <:+ [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ suffix_rfl)⟩
|
||
|
||
theorem eq_nil_of_infix_nil (h : l <:+: []) : l = [] := infix_nil.mp h
|
||
theorem eq_nil_of_prefix_nil (h : l <+: []) : l = [] := prefix_nil.mp h
|
||
theorem eq_nil_of_suffix_nil (h : l <:+ []) : l = [] := suffix_nil.mp h
|
||
|
||
theorem IsPrefix.ne_nil {xs ys : List α} (h : xs <+: ys) (hx : xs ≠ []) : ys ≠ [] := by
|
||
rintro rfl; exact hx <| List.prefix_nil.mp h
|
||
|
||
theorem IsSuffix.ne_nil {xs ys : List α} (h : xs <:+ ys) (hx : xs ≠ []) : ys ≠ [] := by
|
||
rintro rfl; exact hx <| List.suffix_nil.mp h
|
||
|
||
theorem IsInfix.ne_nil {xs ys : List α} (h : xs <:+: ys) (hx : xs ≠ []) : ys ≠ [] := by
|
||
rintro rfl; exact hx <| List.infix_nil.mp h
|
||
|
||
theorem IsInfix.length_le (h : l₁ <:+: l₂) : l₁.length ≤ l₂.length :=
|
||
h.sublist.length_le
|
||
|
||
theorem IsPrefix.length_le (h : l₁ <+: l₂) : l₁.length ≤ l₂.length :=
|
||
h.sublist.length_le
|
||
|
||
theorem IsSuffix.length_le (h : l₁ <:+ l₂) : l₁.length ≤ l₂.length :=
|
||
h.sublist.length_le
|
||
|
||
theorem IsPrefix.getElem {xs ys : List α} (h : xs <+: ys) {i} (hi : i < xs.length) :
|
||
xs[i] = ys[i]'(Nat.le_trans hi h.length_le) := by
|
||
obtain ⟨_, rfl⟩ := h
|
||
exact (List.getElem_append_left hi).symm
|
||
|
||
-- See `Init.Data.List.Nat.Sublist` for `IsSuffix.getElem`.
|
||
|
||
theorem IsPrefix.mem (hx : a ∈ l₁) (hl : l₁ <+: l₂) : a ∈ l₂ :=
|
||
hl.subset hx
|
||
|
||
theorem IsSuffix.mem (hx : a ∈ l₁) (hl : l₁ <:+ l₂) : a ∈ l₂ :=
|
||
hl.subset hx
|
||
|
||
theorem IsInfix.mem (hx : a ∈ l₁) (hl : l₁ <:+: l₂) : a ∈ l₂ :=
|
||
hl.subset hx
|
||
|
||
@[simp] theorem reverse_suffix : reverse l₁ <:+ reverse l₂ ↔ l₁ <+: l₂ :=
|
||
⟨fun ⟨r, e⟩ => ⟨reverse r, by rw [← reverse_reverse l₁, ← reverse_append, e, reverse_reverse]⟩,
|
||
fun ⟨r, e⟩ => ⟨reverse r, by rw [← reverse_append, e]⟩⟩
|
||
|
||
@[simp] theorem reverse_prefix : reverse l₁ <+: reverse l₂ ↔ l₁ <:+ l₂ := by
|
||
rw [← reverse_suffix]; simp only [reverse_reverse]
|
||
|
||
@[simp] theorem reverse_infix : reverse l₁ <:+: reverse l₂ ↔ l₁ <:+: l₂ := by
|
||
refine ⟨fun ⟨s, t, e⟩ => ⟨reverse t, reverse s, ?_⟩, fun ⟨s, t, e⟩ => ⟨reverse t, reverse s, ?_⟩⟩
|
||
· rw [← reverse_reverse l₁, append_assoc, ← reverse_append, ← reverse_append, e,
|
||
reverse_reverse]
|
||
· rw [append_assoc, ← reverse_append, ← reverse_append, e]
|
||
|
||
theorem IsInfix.reverse : l₁ <:+: l₂ → reverse l₁ <:+: reverse l₂ :=
|
||
reverse_infix.2
|
||
|
||
theorem IsSuffix.reverse : l₁ <:+ l₂ → reverse l₁ <+: reverse l₂ :=
|
||
reverse_prefix.2
|
||
|
||
theorem IsPrefix.reverse : l₁ <+: l₂ → reverse l₁ <:+ reverse l₂ :=
|
||
reverse_suffix.2
|
||
|
||
theorem IsPrefix.head {l₁ l₂ : List α} (h : l₁ <+: l₂) (hx : l₁ ≠ []) :
|
||
l₁.head hx = l₂.head (h.ne_nil hx) := by
|
||
cases l₁ <;> cases l₂ <;> simp only [head_cons, ne_eq, not_true_eq_false] at hx ⊢
|
||
all_goals (obtain ⟨_, h⟩ := h; injection h)
|
||
|
||
theorem IsSuffix.getLast {l₁ l₂ : List α} (h : l₁ <:+ l₂) (hx : l₁ ≠ []) :
|
||
l₁.getLast hx = l₂.getLast (h.ne_nil hx) := by
|
||
rw [← head_reverse (by simpa), h.reverse.head,
|
||
head_reverse (by rintro h; simp only [reverse_eq_nil_iff] at h; simp_all)]
|
||
|
||
theorem prefix_concat (a : α) (l) : l <+: concat l a := by simp
|
||
|
||
theorem infix_iff_prefix_suffix {l₁ l₂ : List α} : l₁ <:+: l₂ ↔ ∃ t, l₁ <+: t ∧ t <:+ l₂ :=
|
||
⟨fun ⟨_, t, e⟩ => ⟨l₁ ++ t, ⟨_, rfl⟩, e ▸ append_assoc .. ▸ ⟨_, rfl⟩⟩,
|
||
fun ⟨_, ⟨t, rfl⟩, s, e⟩ => ⟨s, t, append_assoc .. ▸ e⟩⟩
|
||
|
||
theorem infix_iff_suffix_prefix {l₁ l₂ : List α} : l₁ <:+: l₂ ↔ ∃ t, l₁ <:+ t ∧ t <+: l₂ :=
|
||
⟨fun ⟨s, t, e⟩ => ⟨s ++ l₁, ⟨_, rfl⟩, ⟨t, e⟩⟩,
|
||
fun ⟨_, ⟨s, rfl⟩, t, e⟩ => ⟨s, t, append_assoc .. ▸ e⟩⟩
|
||
|
||
theorem IsInfix.eq_of_length (h : l₁ <:+: l₂) : l₁.length = l₂.length → l₁ = l₂ :=
|
||
h.sublist.eq_of_length
|
||
|
||
theorem IsInfix.eq_of_length_le (h : l₁ <:+: l₂) : l₂.length ≤ l₁.length → l₁ = l₂ :=
|
||
h.sublist.eq_of_length_le
|
||
|
||
theorem IsPrefix.eq_of_length (h : l₁ <+: l₂) : l₁.length = l₂.length → l₁ = l₂ :=
|
||
h.sublist.eq_of_length
|
||
|
||
theorem IsPrefix.eq_of_length_le (h : l₁ <+: l₂) : l₂.length ≤ l₁.length → l₁ = l₂ :=
|
||
h.sublist.eq_of_length_le
|
||
|
||
theorem IsSuffix.eq_of_length (h : l₁ <:+ l₂) : l₁.length = l₂.length → l₁ = l₂ :=
|
||
h.sublist.eq_of_length
|
||
|
||
theorem IsSuffix.eq_of_length_le (h : l₁ <:+ l₂) : l₂.length ≤ l₁.length → l₁ = l₂ :=
|
||
h.sublist.eq_of_length_le
|
||
|
||
theorem prefix_of_prefix_length_le :
|
||
∀ {l₁ l₂ l₃ : List α}, l₁ <+: l₃ → l₂ <+: l₃ → length l₁ ≤ length l₂ → l₁ <+: l₂
|
||
| [], _, _, _, _, _ => nil_prefix
|
||
| _ :: _, b :: _, _, ⟨_, rfl⟩, ⟨_, e⟩, ll => by
|
||
injection e with _ e'; subst b
|
||
rcases prefix_of_prefix_length_le ⟨_, rfl⟩ ⟨_, e'⟩ (le_of_succ_le_succ ll) with ⟨r₃, rfl⟩
|
||
exact ⟨r₃, rfl⟩
|
||
|
||
theorem prefix_or_prefix_of_prefix (h₁ : l₁ <+: l₃) (h₂ : l₂ <+: l₃) : l₁ <+: l₂ ∨ l₂ <+: l₁ :=
|
||
(Nat.le_total (length l₁) (length l₂)).imp (prefix_of_prefix_length_le h₁ h₂)
|
||
(prefix_of_prefix_length_le h₂ h₁)
|
||
|
||
theorem suffix_of_suffix_length_le
|
||
(h₁ : l₁ <:+ l₃) (h₂ : l₂ <:+ l₃) (ll : length l₁ ≤ length l₂) : l₁ <:+ l₂ :=
|
||
reverse_prefix.1 <|
|
||
prefix_of_prefix_length_le (reverse_prefix.2 h₁) (reverse_prefix.2 h₂) (by simp [ll])
|
||
|
||
theorem suffix_or_suffix_of_suffix (h₁ : l₁ <:+ l₃) (h₂ : l₂ <:+ l₃) : l₁ <:+ l₂ ∨ l₂ <:+ l₁ :=
|
||
(prefix_or_prefix_of_prefix (reverse_prefix.2 h₁) (reverse_prefix.2 h₂)).imp reverse_prefix.1
|
||
reverse_prefix.1
|
||
|
||
theorem prefix_cons_iff : l₁ <+: a :: l₂ ↔ l₁ = [] ∨ ∃ t, l₁ = a :: t ∧ t <+: l₂ := by
|
||
cases l₁ with
|
||
| nil => simp
|
||
| cons a' l₁ =>
|
||
constructor
|
||
· rintro ⟨t, h⟩
|
||
simp at h
|
||
obtain ⟨rfl, rfl⟩ := h
|
||
exact Or.inr ⟨l₁, rfl, prefix_append l₁ t⟩
|
||
· rintro (h | ⟨t, w, ⟨s, h'⟩⟩)
|
||
· simp [h]
|
||
· simp only [w]
|
||
refine ⟨s, by simp [h']⟩
|
||
|
||
@[simp] theorem cons_prefix_cons : a :: l₁ <+: b :: l₂ ↔ a = b ∧ l₁ <+: l₂ := by
|
||
simp only [prefix_cons_iff, cons.injEq, false_or, List.cons_ne_nil]
|
||
constructor
|
||
· rintro ⟨t, ⟨rfl, rfl⟩, h⟩
|
||
exact ⟨rfl, h⟩
|
||
· rintro ⟨rfl, h⟩
|
||
exact ⟨l₁, ⟨rfl, rfl⟩, h⟩
|
||
|
||
theorem suffix_cons_iff : l₁ <:+ a :: l₂ ↔ l₁ = a :: l₂ ∨ l₁ <:+ l₂ := by
|
||
constructor
|
||
· rintro ⟨⟨hd, tl⟩, hl₃⟩
|
||
· exact Or.inl hl₃
|
||
· simp only [cons_append] at hl₃
|
||
injection hl₃ with _ hl₄
|
||
exact Or.inr ⟨_, hl₄⟩
|
||
· rintro (rfl | hl₁)
|
||
· exact (a :: l₂).suffix_refl
|
||
· exact hl₁.trans (l₂.suffix_cons _)
|
||
|
||
theorem infix_cons_iff : l₁ <:+: a :: l₂ ↔ l₁ <+: a :: l₂ ∨ l₁ <:+: l₂ := by
|
||
constructor
|
||
· rintro ⟨⟨hd, tl⟩, t, hl₃⟩
|
||
· exact Or.inl ⟨t, hl₃⟩
|
||
· simp only [cons_append] at hl₃
|
||
injection hl₃ with _ hl₄
|
||
exact Or.inr ⟨_, t, hl₄⟩
|
||
· rintro (h | hl₁)
|
||
· exact h.isInfix
|
||
· exact infix_cons hl₁
|
||
|
||
theorem prefix_concat_iff {l₁ l₂ : List α} {a : α} :
|
||
l₁ <+: l₂ ++ [a] ↔ l₁ = l₂ ++ [a] ∨ l₁ <+: l₂ := by
|
||
simp only [← reverse_suffix, reverse_concat, suffix_cons_iff]
|
||
simp only [concat_eq_append, ← reverse_concat, reverse_eq_iff, reverse_reverse]
|
||
|
||
theorem suffix_concat_iff {l₁ l₂ : List α} {a : α} :
|
||
l₁ <:+ l₂ ++ [a] ↔ l₁ = [] ∨ ∃ t, l₁ = t ++ [a] ∧ t <:+ l₂ := by
|
||
rw [← reverse_prefix, reverse_concat, prefix_cons_iff]
|
||
simp only [reverse_eq_nil_iff]
|
||
apply or_congr_right
|
||
constructor
|
||
· rintro ⟨t, w, h⟩
|
||
exact ⟨t.reverse, by simpa using congrArg reverse w, by simpa using h.reverse⟩
|
||
· rintro ⟨t, rfl, h⟩
|
||
exact ⟨t.reverse, by simp, by simpa using h.reverse⟩
|
||
|
||
theorem infix_concat_iff {l₁ l₂ : List α} {a : α} :
|
||
l₁ <:+: l₂ ++ [a] ↔ l₁ <:+ l₂ ++ [a] ∨ l₁ <:+: l₂ := by
|
||
rw [← reverse_infix, reverse_concat, infix_cons_iff, reverse_infix,
|
||
← reverse_prefix, reverse_concat]
|
||
|
||
theorem isPrefix_iff : l₁ <+: l₂ ↔ ∀ i (h : i < l₁.length), l₂[i]? = some l₁[i] := by
|
||
induction l₁ generalizing l₂ with
|
||
| nil => simp
|
||
| cons a l₁ ih =>
|
||
cases l₂ with
|
||
| nil =>
|
||
simpa using ⟨0, by simp⟩
|
||
| cons b l₂ =>
|
||
simp only [cons_append, cons_prefix_cons, ih]
|
||
rw (occs := [2]) [← Nat.and_forall_add_one]
|
||
simp [Nat.succ_lt_succ_iff, eq_comm]
|
||
|
||
theorem isPrefix_iff_getElem {l₁ l₂ : List α} :
|
||
l₁ <+: l₂ ↔ ∃ (h : l₁.length ≤ l₂.length), ∀ i (hx : i < l₁.length),
|
||
l₁[i] = l₂[i]'(Nat.lt_of_lt_of_le hx h) where
|
||
mp h := ⟨h.length_le, fun _ h' ↦ h.getElem h'⟩
|
||
mpr h := by
|
||
obtain ⟨hl, h⟩ := h
|
||
induction l₂ generalizing l₁ with
|
||
| nil =>
|
||
simpa using hl
|
||
| cons _ _ tail_ih =>
|
||
cases l₁ with
|
||
| nil =>
|
||
exact nil_prefix
|
||
| cons _ _ =>
|
||
simp only [length_cons, Nat.add_le_add_iff_right, Fin.getElem_fin] at hl h
|
||
simp only [cons_prefix_cons]
|
||
exact ⟨h 0 (zero_lt_succ _), tail_ih hl fun a ha ↦ h a.succ (succ_lt_succ ha)⟩
|
||
|
||
-- See `Init.Data.List.Nat.Sublist` for `isSuffix_iff` and `ifInfix_iff`.
|
||
|
||
theorem isPrefix_filterMap_iff {β} {f : α → Option β} {l₁ : List α} {l₂ : List β} :
|
||
l₂ <+: filterMap f l₁ ↔ ∃ l, l <+: l₁ ∧ l₂ = filterMap f l := by
|
||
simp only [IsPrefix, append_eq_filterMap_iff]
|
||
constructor
|
||
· rintro ⟨_, l₁, l₂, rfl, rfl, rfl⟩
|
||
exact ⟨l₁, ⟨l₂, rfl⟩, rfl⟩
|
||
· rintro ⟨l₁, ⟨l₂, rfl⟩, rfl⟩
|
||
exact ⟨_, l₁, l₂, rfl, rfl, rfl⟩
|
||
|
||
theorem isSuffix_filterMap_iff {β} {f : α → Option β} {l₁ : List α} {l₂ : List β} :
|
||
l₂ <:+ filterMap f l₁ ↔ ∃ l, l <:+ l₁ ∧ l₂ = filterMap f l := by
|
||
simp only [IsSuffix, append_eq_filterMap_iff]
|
||
constructor
|
||
· rintro ⟨_, l₁, l₂, rfl, rfl, rfl⟩
|
||
exact ⟨l₂, ⟨l₁, rfl⟩, rfl⟩
|
||
· rintro ⟨l₁, ⟨l₂, rfl⟩, rfl⟩
|
||
exact ⟨_, l₂, l₁, rfl, rfl, rfl⟩
|
||
|
||
theorem isInfix_filterMap_iff {β} {f : α → Option β} {l₁ : List α} {l₂ : List β} :
|
||
l₂ <:+: filterMap f l₁ ↔ ∃ l, l <:+: l₁ ∧ l₂ = filterMap f l := by
|
||
simp only [IsInfix, append_eq_filterMap_iff, filterMap_eq_append_iff]
|
||
constructor
|
||
· rintro ⟨_, _, _, l₁, rfl, ⟨⟨l₂, l₃, rfl, rfl, rfl⟩, rfl⟩⟩
|
||
exact ⟨l₃, ⟨l₂, l₁, rfl⟩, rfl⟩
|
||
· rintro ⟨l₃, ⟨l₂, l₁, rfl⟩, rfl⟩
|
||
exact ⟨_, _, _, l₁, rfl, ⟨⟨l₂, l₃, rfl, rfl, rfl⟩, rfl⟩⟩
|
||
|
||
theorem isPrefix_filter_iff {p : α → Bool} {l₁ l₂ : List α} :
|
||
l₂ <+: l₁.filter p ↔ ∃ l, l <+: l₁ ∧ l₂ = l.filter p := by
|
||
rw [← filterMap_eq_filter, isPrefix_filterMap_iff]
|
||
|
||
theorem isSuffix_filter_iff {p : α → Bool} {l₁ l₂ : List α} :
|
||
l₂ <:+ l₁.filter p ↔ ∃ l, l <:+ l₁ ∧ l₂ = l.filter p := by
|
||
rw [← filterMap_eq_filter, isSuffix_filterMap_iff]
|
||
|
||
theorem isInfix_filter_iff {p : α → Bool} {l₁ l₂ : List α} :
|
||
l₂ <:+: l₁.filter p ↔ ∃ l, l <:+: l₁ ∧ l₂ = l.filter p := by
|
||
rw [← filterMap_eq_filter, isInfix_filterMap_iff]
|
||
|
||
theorem isPrefix_map_iff {β} {f : α → β} {l₁ : List α} {l₂ : List β} :
|
||
l₂ <+: l₁.map f ↔ ∃ l, l <+: l₁ ∧ l₂ = l.map f := by
|
||
rw [← filterMap_eq_map, isPrefix_filterMap_iff]
|
||
|
||
theorem isSuffix_map_iff {β} {f : α → β} {l₁ : List α} {l₂ : List β} :
|
||
l₂ <:+ l₁.map f ↔ ∃ l, l <:+ l₁ ∧ l₂ = l.map f := by
|
||
rw [← filterMap_eq_map, isSuffix_filterMap_iff]
|
||
|
||
theorem isInfix_map_iff {β} {f : α → β} {l₁ : List α} {l₂ : List β} :
|
||
l₂ <:+: l₁.map f ↔ ∃ l, l <:+: l₁ ∧ l₂ = l.map f := by
|
||
rw [← filterMap_eq_map, isInfix_filterMap_iff]
|
||
|
||
theorem isPrefix_replicate_iff {n} {a : α} {l : List α} :
|
||
l <+: List.replicate n a ↔ l.length ≤ n ∧ l = List.replicate l.length a := by
|
||
rw [IsPrefix]
|
||
simp only [append_eq_replicate_iff]
|
||
constructor
|
||
· rintro ⟨_, rfl, _, _⟩
|
||
exact ⟨le_add_right .., ‹_›⟩
|
||
· rintro ⟨h, w⟩
|
||
refine ⟨replicate (n - l.length) a, ?_, ?_⟩
|
||
· simpa using add_sub_of_le h
|
||
· simpa using w
|
||
|
||
theorem isSuffix_replicate_iff {n} {a : α} {l : List α} :
|
||
l <:+ List.replicate n a ↔ l.length ≤ n ∧ l = List.replicate l.length a := by
|
||
rw [← reverse_prefix, reverse_replicate, isPrefix_replicate_iff]
|
||
simp [reverse_eq_iff]
|
||
|
||
theorem isInfix_replicate_iff {n} {a : α} {l : List α} :
|
||
l <:+: List.replicate n a ↔ l.length ≤ n ∧ l = List.replicate l.length a := by
|
||
rw [IsInfix]
|
||
simp only [append_eq_replicate_iff, length_append]
|
||
constructor
|
||
· rintro ⟨_, _, rfl, ⟨-, _, _⟩, _⟩
|
||
exact ⟨le_add_right_of_le (le_add_left ..), ‹_›⟩
|
||
· rintro ⟨h, w⟩
|
||
refine ⟨replicate (n - l.length) a, [], ?_, ?_⟩
|
||
· simpa using Nat.sub_add_cancel h
|
||
· simpa using w
|
||
|
||
theorem infix_of_mem_flatten : ∀ {L : List (List α)}, l ∈ L → l <:+: flatten L
|
||
| l' :: _, h =>
|
||
match h with
|
||
| List.Mem.head .. => infix_append [] _ _
|
||
| List.Mem.tail _ hlMemL =>
|
||
IsInfix.trans (infix_of_mem_flatten hlMemL) <| (suffix_append _ _).isInfix
|
||
|
||
@[simp] theorem prefix_append_right_inj (l) : l ++ l₁ <+: l ++ l₂ ↔ l₁ <+: l₂ :=
|
||
exists_congr fun r => by rw [append_assoc, append_right_inj]
|
||
|
||
theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ ↔ l₁ <+: l₂ :=
|
||
prefix_append_right_inj [a]
|
||
|
||
theorem take_prefix (i) (l : List α) : take i l <+: l :=
|
||
⟨_, take_append_drop _ _⟩
|
||
|
||
theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
|
||
⟨_, take_append_drop _ _⟩
|
||
|
||
theorem take_sublist (i) (l : List α) : take i l <+ l :=
|
||
(take_prefix i l).sublist
|
||
|
||
theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
|
||
(drop_suffix i l).sublist
|
||
|
||
theorem take_subset (i) (l : List α) : take i l ⊆ l :=
|
||
(take_sublist i l).subset
|
||
|
||
theorem drop_subset (i) (l : List α) : drop i l ⊆ l :=
|
||
(drop_sublist i l).subset
|
||
|
||
theorem mem_of_mem_take {l : List α} (h : a ∈ l.take i) : a ∈ l :=
|
||
take_subset _ _ h
|
||
|
||
theorem mem_of_mem_drop {i} {l : List α} (h : a ∈ l.drop i) : a ∈ l :=
|
||
drop_subset _ _ h
|
||
|
||
theorem drop_suffix_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <:+ drop i l := by
|
||
rw [← Nat.sub_add_cancel h, Nat.add_comm, ← drop_drop]
|
||
apply drop_suffix
|
||
|
||
-- See `Init.Data.List.Nat.TakeDrop` for `take_prefix_take_left`.
|
||
|
||
theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <+ drop i l :=
|
||
(drop_suffix_drop_left l h).sublist
|
||
|
||
theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l ⊆ drop i l :=
|
||
(drop_sublist_drop_left l h).subset
|
||
|
||
theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l :=
|
||
⟨l.dropWhile p, takeWhile_append_dropWhile p l⟩
|
||
|
||
theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l :=
|
||
⟨l.takeWhile p, takeWhile_append_dropWhile p l⟩
|
||
|
||
theorem takeWhile_sublist (p : α → Bool) : l.takeWhile p <+ l :=
|
||
(takeWhile_prefix p).sublist
|
||
|
||
theorem dropWhile_sublist (p : α → Bool) : l.dropWhile p <+ l :=
|
||
(dropWhile_suffix p).sublist
|
||
|
||
theorem takeWhile_subset {l : List α} (p : α → Bool) : l.takeWhile p ⊆ l :=
|
||
(takeWhile_sublist p).subset
|
||
|
||
theorem dropWhile_subset {l : List α} (p : α → Bool) : l.dropWhile p ⊆ l :=
|
||
(dropWhile_sublist p).subset
|
||
|
||
theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l
|
||
| [] => ⟨nil, by rw [dropLast, List.append_nil]⟩
|
||
| a :: l => ⟨_, dropLast_concat_getLast (cons_ne_nil a l)⟩
|
||
|
||
theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
|
||
(dropLast_prefix l).sublist
|
||
|
||
theorem dropLast_subset (l : List α) : l.dropLast ⊆ l :=
|
||
(dropLast_sublist l).subset
|
||
|
||
theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix
|
||
|
||
theorem IsPrefix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
|
||
obtain ⟨r, rfl⟩ := h
|
||
rw [map_append]; apply prefix_append
|
||
|
||
theorem IsSuffix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
|
||
obtain ⟨r, rfl⟩ := h
|
||
rw [map_append]; apply suffix_append
|
||
|
||
theorem IsInfix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
|
||
obtain ⟨r₁, r₂, rfl⟩ := h
|
||
rw [map_append, map_append]; apply infix_append
|
||
|
||
theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||
l₁.filter p <+: l₂.filter p := by
|
||
obtain ⟨xs, rfl⟩ := h
|
||
rw [filter_append]; apply prefix_append
|
||
|
||
theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||
l₁.filter p <:+ l₂.filter p := by
|
||
obtain ⟨xs, rfl⟩ := h
|
||
rw [filter_append]; apply suffix_append
|
||
|
||
theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||
l₁.filter p <:+: l₂.filter p := by
|
||
obtain ⟨xs, ys, rfl⟩ := h
|
||
rw [filter_append, filter_append]; apply infix_append _
|
||
|
||
theorem IsPrefix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||
filterMap f l₁ <+: filterMap f l₂ := by
|
||
obtain ⟨xs, rfl⟩ := h
|
||
rw [filterMap_append]; apply prefix_append
|
||
|
||
theorem IsSuffix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||
filterMap f l₁ <:+ filterMap f l₂ := by
|
||
obtain ⟨xs, rfl⟩ := h
|
||
rw [filterMap_append]; apply suffix_append
|
||
|
||
theorem IsInfix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||
filterMap f l₁ <:+: filterMap f l₂ := by
|
||
obtain ⟨xs, ys, rfl⟩ := h
|
||
rw [filterMap_append, filterMap_append]; apply infix_append
|
||
|
||
@[simp] theorem isPrefixOf_iff_prefix [BEq α] [LawfulBEq α] {l₁ l₂ : List α} :
|
||
l₁.isPrefixOf l₂ ↔ l₁ <+: l₂ := by
|
||
induction l₁ generalizing l₂ with
|
||
| nil => simp
|
||
| cons a l₁ ih =>
|
||
cases l₂ with
|
||
| nil => simp
|
||
| cons a' l₂ => simp [isPrefixOf, ih]
|
||
|
||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+: l₂) :=
|
||
decidable_of_iff (l₁.isPrefixOf l₂) isPrefixOf_iff_prefix
|
||
|
||
@[simp] theorem isSuffixOf_iff_suffix [BEq α] [LawfulBEq α] {l₁ l₂ : List α} :
|
||
l₁.isSuffixOf l₂ ↔ l₁ <:+ l₂ := by
|
||
simp [isSuffixOf]
|
||
|
||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <:+ l₂) :=
|
||
decidable_of_iff (l₁.isSuffixOf l₂) isSuffixOf_iff_suffix
|
||
|
||
theorem prefix_iff_eq_append : l₁ <+: l₂ ↔ l₁ ++ drop (length l₁) l₂ = l₂ :=
|
||
⟨by rintro ⟨r, rfl⟩; rw [drop_left], fun e => ⟨_, e⟩⟩
|
||
|
||
theorem prefix_iff_eq_take : l₁ <+: l₂ ↔ l₁ = take (length l₁) l₂ :=
|
||
⟨fun h => append_cancel_right <| (prefix_iff_eq_append.1 h).trans (take_append_drop _ _).symm,
|
||
fun e => e.symm ▸ take_prefix _ _⟩
|
||
|
||
-- See `Init.Data.List.Nat.Sublist` for `suffix_iff_eq_append`, `prefix_take_iff`, and `suffix_iff_eq_drop`.
|
||
|
||
/-! ### Deprecations -/
|
||
|
||
@[deprecated sublist_flatten_of_mem (since := "2024-10-14")] abbrev sublist_join_of_mem := @sublist_flatten_of_mem
|
||
@[deprecated sublist_flatten_iff (since := "2024-10-14")] abbrev sublist_join_iff := @sublist_flatten_iff
|
||
@[deprecated flatten_sublist_iff (since := "2024-10-14")] abbrev flatten_join_iff := @flatten_sublist_iff
|
||
@[deprecated infix_of_mem_flatten (since := "2024-10-14")] abbrev infix_of_mem_join := @infix_of_mem_flatten
|
||
|
||
end List
|