chore: upstream IsPrefix/IsSuffix/IsInfix (#4836)
Further lemmas to follow; this is the basic material from Batteries.
This commit is contained in:
parent
54c22efca1
commit
8c87a90cea
2 changed files with 257 additions and 40 deletions
|
|
@ -826,46 +826,6 @@ def dropLast {α} : List α → List α
|
|||
have ih := length_dropLast_cons b bs
|
||||
simp [dropLast, ih]
|
||||
|
||||
/-! ### isPrefixOf -/
|
||||
|
||||
/-- `isPrefixOf l₁ l₂` returns `true` Iff `l₁` is a prefix of `l₂`.
|
||||
That is, there exists a `t` such that `l₂ == l₁ ++ t`. -/
|
||||
def isPrefixOf [BEq α] : List α → List α → Bool
|
||||
| [], _ => true
|
||||
| _, [] => false
|
||||
| a::as, b::bs => a == b && isPrefixOf as bs
|
||||
|
||||
@[simp] theorem isPrefixOf_nil_left [BEq α] : isPrefixOf ([] : List α) l = true := by
|
||||
simp [isPrefixOf]
|
||||
@[simp] theorem isPrefixOf_cons_nil [BEq α] : isPrefixOf (a::as) ([] : List α) = false := rfl
|
||||
theorem isPrefixOf_cons₂ [BEq α] {a : α} :
|
||||
isPrefixOf (a::as) (b::bs) = (a == b && isPrefixOf as bs) := rfl
|
||||
|
||||
/-! ### isPrefixOf? -/
|
||||
|
||||
/-- `isPrefixOf? l₁ l₂` returns `some t` when `l₂ == l₁ ++ t`. -/
|
||||
def isPrefixOf? [BEq α] : List α → List α → Option (List α)
|
||||
| [], l₂ => some l₂
|
||||
| _, [] => none
|
||||
| (x₁ :: l₁), (x₂ :: l₂) =>
|
||||
if x₁ == x₂ then isPrefixOf? l₁ l₂ else none
|
||||
|
||||
/-! ### isSuffixOf -/
|
||||
|
||||
/-- `isSuffixOf l₁ l₂` returns `true` Iff `l₁` is a suffix of `l₂`.
|
||||
That is, there exists a `t` such that `l₂ == t ++ l₁`. -/
|
||||
def isSuffixOf [BEq α] (l₁ l₂ : List α) : Bool :=
|
||||
isPrefixOf l₁.reverse l₂.reverse
|
||||
|
||||
@[simp] theorem isSuffixOf_nil_left [BEq α] : isSuffixOf ([] : List α) l = true := by
|
||||
simp [isSuffixOf]
|
||||
|
||||
/-! ### isSuffixOf? -/
|
||||
|
||||
/-- `isSuffixOf? l₁ l₂` returns `some t` when `l₂ == t ++ l₁`.-/
|
||||
def isSuffixOf? [BEq α] (l₁ l₂ : List α) : Option (List α) :=
|
||||
Option.map List.reverse <| isPrefixOf? l₁.reverse l₂.reverse
|
||||
|
||||
/-! ### Subset -/
|
||||
|
||||
/--
|
||||
|
|
@ -900,6 +860,68 @@ def isSublist [BEq α] : List α → List α → Bool
|
|||
then tl₁.isSublist tl₂
|
||||
else l₁.isSublist tl₂
|
||||
|
||||
/-! ### IsPrefix / isPrefixOf / isPrefixOf? -/
|
||||
|
||||
/--
|
||||
`IsPrefix l₁ l₂`, or `l₁ <+: l₂`, means that `l₁` is a prefix of `l₂`,
|
||||
that is, `l₂` has the form `l₁ ++ t` for some `t`.
|
||||
-/
|
||||
def IsPrefix (l₁ : List α) (l₂ : List α) : Prop := Exists fun t => l₁ ++ t = l₂
|
||||
|
||||
@[inherit_doc] infixl:50 " <+: " => IsPrefix
|
||||
|
||||
/-- `isPrefixOf l₁ l₂` returns `true` Iff `l₁` is a prefix of `l₂`.
|
||||
That is, there exists a `t` such that `l₂ == l₁ ++ t`. -/
|
||||
def isPrefixOf [BEq α] : List α → List α → Bool
|
||||
| [], _ => true
|
||||
| _, [] => false
|
||||
| a::as, b::bs => a == b && isPrefixOf as bs
|
||||
|
||||
@[simp] theorem isPrefixOf_nil_left [BEq α] : isPrefixOf ([] : List α) l = true := by
|
||||
simp [isPrefixOf]
|
||||
@[simp] theorem isPrefixOf_cons_nil [BEq α] : isPrefixOf (a::as) ([] : List α) = false := rfl
|
||||
theorem isPrefixOf_cons₂ [BEq α] {a : α} :
|
||||
isPrefixOf (a::as) (b::bs) = (a == b && isPrefixOf as bs) := rfl
|
||||
|
||||
/-- `isPrefixOf? l₁ l₂` returns `some t` when `l₂ == l₁ ++ t`. -/
|
||||
def isPrefixOf? [BEq α] : List α → List α → Option (List α)
|
||||
| [], l₂ => some l₂
|
||||
| _, [] => none
|
||||
| (x₁ :: l₁), (x₂ :: l₂) =>
|
||||
if x₁ == x₂ then isPrefixOf? l₁ l₂ else none
|
||||
|
||||
/-! ### IsSuffix / isSuffixOf / isSuffixOf? -/
|
||||
|
||||
/-- `isSuffixOf l₁ l₂` returns `true` Iff `l₁` is a suffix of `l₂`.
|
||||
That is, there exists a `t` such that `l₂ == t ++ l₁`. -/
|
||||
def isSuffixOf [BEq α] (l₁ l₂ : List α) : Bool :=
|
||||
isPrefixOf l₁.reverse l₂.reverse
|
||||
|
||||
@[simp] theorem isSuffixOf_nil_left [BEq α] : isSuffixOf ([] : List α) l = true := by
|
||||
simp [isSuffixOf]
|
||||
|
||||
/-- `isSuffixOf? l₁ l₂` returns `some t` when `l₂ == t ++ l₁`.-/
|
||||
def isSuffixOf? [BEq α] (l₁ l₂ : List α) : Option (List α) :=
|
||||
Option.map List.reverse <| isPrefixOf? l₁.reverse l₂.reverse
|
||||
|
||||
/--
|
||||
`IsSuffix l₁ l₂`, or `l₁ <:+ l₂`, means that `l₁` is a suffix of `l₂`,
|
||||
that is, `l₂` has the form `t ++ l₁` for some `t`.
|
||||
-/
|
||||
def IsSuffix (l₁ : List α) (l₂ : List α) : Prop := Exists fun t => t ++ l₁ = l₂
|
||||
|
||||
@[inherit_doc] infixl:50 " <:+ " => IsSuffix
|
||||
|
||||
/-! ### IsInfix -/
|
||||
|
||||
/--
|
||||
`IsInfix l₁ l₂`, or `l₁ <:+: l₂`, means that `l₁` is a contiguous
|
||||
substring of `l₂`, that is, `l₂` has the form `s ++ l₁ ++ t` for some `s, t`.
|
||||
-/
|
||||
def IsInfix (l₁ : List α) (l₂ : List α) : Prop := Exists fun s => Exists fun t => s ++ l₁ ++ t = l₂
|
||||
|
||||
@[inherit_doc] infixl:50 " <:+: " => IsInfix
|
||||
|
||||
/-! ### rotateLeft -/
|
||||
|
||||
/--
|
||||
|
|
|
|||
|
|
@ -2700,6 +2700,201 @@ theorem join_sublist_iff {L : List (List α)} {l} :
|
|||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
|
||||
decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist
|
||||
|
||||
/-! ### 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]⟩
|
||||
|
||||
theorem nil_prefix (l : List α) : [] <+: l := ⟨l, rfl⟩
|
||||
|
||||
theorem nil_suffix (l : List α) : [] <:+ l := ⟨l, append_nil _⟩
|
||||
|
||||
theorem nil_infix (l : List α) : [] <:+: l := (nil_prefix _).isInfix
|
||||
|
||||
theorem prefix_refl (l : List α) : l <+: l := ⟨[], append_nil _⟩
|
||||
|
||||
theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
|
||||
|
||||
theorem infix_refl (l : List α) : l <:+: l := (prefix_refl l).isInfix
|
||||
|
||||
@[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 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.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
|
||||
|
||||
@[simp] theorem infix_nil : l <:+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ infix_refl _)⟩
|
||||
|
||||
@[simp] theorem prefix_nil : l <+: [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ prefix_refl _)⟩
|
||||
|
||||
@[simp] theorem suffix_nil : l <:+ [] ↔ l = [] := ⟨(sublist_nil.1 ·.sublist), (· ▸ suffix_refl _)⟩
|
||||
|
||||
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 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 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 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 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 _
|
||||
|
||||
/-! ### rotateLeft -/
|
||||
|
||||
@[simp] theorem rotateLeft_zero (l : List α) : rotateLeft l 0 = l := by
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue