lean4-htt/src/Init/Data/List/Sublist.lean

1029 lines
41 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
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`.
-/
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 h t 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 (Membership.mem : α → List α → Prop) Subset Membership.mem :=
⟨fun h₁ h₂ => h₂ h₁⟩
instance : Trans (Subset : List α → List α → Prop) Subset Subset :=
⟨Subset.trans⟩
@[simp] 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)
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⟩
@[simp] theorem subset_append_left (l₁ l₂ : List α) : l₁ ⊆ l₁ ++ l₂ := fun _ => mem_append_left _
@[simp] theorem subset_append_right (l₁ l₂ : List α) : l₂ ⊆ l₁ ++ l₂ := fun _ => mem_append_right _
theorem subset_append_of_subset_left (l₂ : List α) : l ⊆ l₁ → l ⊆ l₁ ++ l₂ :=
fun s => Subset.trans s <| subset_append_left _ _
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 (config := {contextual := true}) [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⟩
@[simp] 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
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 (Membership.mem : α → List α → Prop) Sublist 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 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]
@[simp] theorem sublist_append_left : ∀ l₁ l₂ : List α, l₁ <+ l₁ ++ l₂
| [], _ => nil_sublist _
| _ :: l₁, l₂ => (sublist_append_left l₁ l₂).cons₂ _
@[simp] 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 ..)
theorem sublist_append_of_sublist_left (s : l <+ l₁) : l <+ l₁ ++ l₂ :=
s.trans <| sublist_append_left ..
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.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_join_of_mem {L : List (List α)} {l} (h : l ∈ L) : l <+ L.join := by
induction L with
| nil => cases h
| cons l' L ih =>
rcases mem_cons.1 h with (rfl | h)
· simp [h]
· simp [ih h, join_cons, sublist_append_of_sublist_right]
theorem sublist_join_iff {L : List (List α)} {l} :
l <+ L.join ↔
∃ L' : List (List α), l = L'.join ∧ ∀ i (_ : i < L'.length), L'[i] <+ L[i]?.getD [] := by
induction L generalizing l with
| nil =>
constructor
· intro w
simp only [join_nil, sublist_nil] at w
subst w
exact ⟨[], by simp, fun i x => by cases x⟩
· rintro ⟨L', rfl, h⟩
simp only [join_nil, sublist_nil, join_eq_nil_iff]
simp only [getElem?_nil, Option.getD_none, sublist_nil] at h
exact (forall_getElem L' (· = [])).1 h
| cons l' L ih =>
simp only [join_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'.join, 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 join_sublist_iff {L : List (List α)} {l} :
L.join <+ l ↔
∃ L' : List (List α), l = L'.join ∧ ∀ 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 [join_nil, nil_sublist]
| cons l' L ih =>
simp only [join_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'.join, 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₂ → ∀ n, l₁.drop n <+ l₂.drop n
| _, _, h, 0 => h
| _, _, h, n + 1 => by rw [← drop_tail, ← drop_tail]; exact h.tail.drop n
/-! ### 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 {x y : List α} (h : x <+: y) (hx : x ≠ []) : y ≠ [] := by
rintro rfl; exact hx <| List.prefix_nil.mp h
theorem IsSuffix.ne_nil {x y : List α} (h : x <:+ y) (hx : x ≠ []) : y ≠ [] := by
rintro rfl; exact hx <| List.suffix_nil.mp h
theorem IsInfix.ne_nil {x y : List α} (h : x <:+: y) (hx : x ≠ []) : y ≠ [] := 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 {x y : List α} (h : x <+: y) {n} (hn : n < x.length) :
x[n] = y[n]'(Nat.le_trans hn h.length_le) := by
obtain ⟨_, rfl⟩ := h
exact (List.getElem_append n hn).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 {x y : List α} (h : x <+: y) (hx : x ≠ []) :
x.head hx = y.head (h.ne_nil hx) := by
cases x <;> cases y <;> simp only [head_cons, ne_eq, not_true_eq_false] at hx ⊢
all_goals (obtain ⟨_, h⟩ := h; injection h)
theorem IsSuffix.getLast {x y : List α} (h : x <:+ y) (hx : x ≠ []) :
x.getLast hx = y.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 IsPrefix.eq_of_length (h : l₁ <+: l₂) : l₁.length = l₂.length → l₁ = l₂ :=
h.sublist.eq_of_length
theorem IsSuffix.eq_of_length (h : l₁ <:+ l₂) : l₁.length = l₂.length → l₁ = l₂ :=
h.sublist.eq_of_length
theorem prefix_of_prefix_length_le :
∀ {l₁ l₂ l₃ : List α}, l₁ <+: l₃ → l₂ <+: l₃ → length l₁ ≤ length l₂ → l₁ <+: l₂
| [], l₂, _, _, _, _ => nil_prefix
| a :: l₁, b :: l₂, _, ⟨r₁, rfl⟩, ⟨r₂, 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]
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 [← concat_eq_append, ← 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, ← concat_eq_append, 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, ← concat_eq_append, 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 (config := {occs := .pos [2]}) [← Nat.and_forall_add_one]
simp [Nat.succ_lt_succ_iff, eq_comm]
-- 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]
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]
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, filterMap_eq_append]
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]
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, 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_join : ∀ {L : List (List α)}, l ∈ L → l <:+: join L
| l' :: _, h =>
match h with
| List.Mem.head .. => infix_append [] _ _
| List.Mem.tail _ hlMemL =>
IsInfix.trans (infix_of_mem_join hlMemL) <| (suffix_append _ _).isInfix
theorem prefix_append_right_inj (l) : l ++ l₁ <+: l ++ l₂ ↔ l₁ <+: l₂ :=
exists_congr fun r => by rw [append_assoc, append_right_inj]
@[simp]
theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ ↔ l₁ <+: l₂ :=
prefix_append_right_inj [a]
theorem take_prefix (n) (l : List α) : take n l <+: l :=
⟨_, take_append_drop _ _⟩
theorem drop_suffix (n) (l : List α) : drop n l <:+ l :=
⟨_, take_append_drop _ _⟩
theorem take_sublist (n) (l : List α) : take n l <+ l :=
(take_prefix n l).sublist
theorem drop_sublist (n) (l : List α) : drop n l <+ l :=
(drop_suffix n l).sublist
theorem take_subset (n) (l : List α) : take n l ⊆ l :=
(take_sublist n l).subset
theorem drop_subset (n) (l : List α) : drop n l ⊆ l :=
(drop_sublist n l).subset
theorem mem_of_mem_take {l : List α} (h : a ∈ l.take n) : a ∈ l :=
take_subset n l h
theorem mem_of_mem_drop {n} {l : List α} (h : a ∈ l.drop n) : a ∈ l :=
drop_subset _ _ h
theorem drop_suffix_drop_left (l : List α) {m n : Nat} (h : m ≤ n) : drop n l <:+ drop m l := by
rw [← Nat.sub_add_cancel h, ← drop_drop]
apply drop_suffix
-- See `Init.Data.List.Nat.TakeDrop` for `take_prefix_take_left`.
theorem drop_sublist_drop_left (l : List α) {m n : Nat} (h : m ≤ n) : drop n l <+ drop m l :=
(drop_suffix_drop_left l h).sublist
theorem drop_subset_drop_left (l : List α) {m n : Nat} (h : m ≤ n) : drop n l ⊆ drop m 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`.
end List