Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions Batteries/Data/List/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -647,10 +647,12 @@ pwFilter (·<·) [0, 1, 5, 2, 6, 3, 4] = [0, 1, 2, 3, 4]
def pwFilter (R : α → α → Prop) [DecidableRel R] (l : List α) : List α :=
l.foldr (fun x IH => if ∀ y ∈ IH, R x y then x :: IH else IH) []

/-- `IsChain R l` means that `R` holds between adjacent elements of `l`.
/--
`IsChain R l` means that `R` holds between adjacent elements of `l`. Example:
```
IsChain R [a, b, c, d] ↔ R a b ∧ R b c ∧ R c d
``` -/
```
-/
inductive IsChain (R : α → α → Prop) : List α → Prop where
/-- A list of length 0 is a chain. -/
| nil : IsChain R []
Expand All @@ -665,13 +667,13 @@ attribute [simp, grind ←] IsChain.singleton
@[simp, grind =] theorem isChain_cons_cons : IsChain R (a :: b :: l) ↔ R a b ∧ IsChain R (b :: l) :=
⟨fun | .cons_cons hr h => ⟨hr, h⟩, fun ⟨hr, h⟩ => .cons_cons hr h⟩

instance instDecidableIsChain {R : α → α → Prop} [h : DecidableRel R] (l : List α) :
Decidable (l.IsChain R) := match l with | [] => isTrue .nil | a :: l => go a l
where
go (a : α) (l : List α) : Decidable ((a :: l).IsChain R) :=
match l with
| [] => isTrue <| .singleton a
| b :: l => haveI := (go b l); decidable_of_iff' _ isChain_cons_cons
instance {R : α → α → Prop} [h : DecidableRel R] : (l : List α) → Decidable (l.IsChain R)
| [] => isTrue .nil | a :: l => go a l
where
go (a : α) (l : List α) : Decidable ((a :: l).IsChain R) :=
match l with
| [] => isTrue <| .singleton a
| b :: l => haveI := (go b l); decidable_of_iff' _ isChain_cons_cons

/-- `Chain R a l` means that `R` holds between adjacent elements of `a::l`.
```
Expand Down
60 changes: 33 additions & 27 deletions Batteries/Data/List/Lemmas.lean
Original file line number Diff line number Diff line change
Expand Up @@ -379,56 +379,62 @@ alias chain_cons := isChain_cons_cons
theorem rel_of_isChain_cons_cons (p : IsChain R (a :: b :: l)) : R a b :=
(isChain_cons_cons.1 p).1

alias IsChain.rel := rel_of_isChain_cons_cons

@[deprecated (since := "2025-09-19")]
alias rel_of_chain_cons := rel_of_isChain_cons_cons

theorem isChain_cons_of_isChain_cons_cons (p : IsChain R (a :: b :: l)) :
IsChain R (b :: l) := (isChain_cons_cons.1 p).2
theorem isChain_of_isChain_cons (p : IsChain R (b :: l)) : IsChain R l := by grind [cases List]

alias IsChain.of_cons := isChain_of_isChain_cons

@[deprecated IsChain.of_cons (since := "2026-02-10")]
theorem isChain_cons_of_isChain_cons_cons : IsChain R (a :: b :: l) →
IsChain R (b :: l) := IsChain.of_cons

@[deprecated (since := "2025-09-19")]
alias chain_of_chain_cons := isChain_cons_of_isChain_cons_cons

theorem isChain_of_isChain_cons (p : IsChain R (b :: l)) :
IsChain R l := by
cases l
· exact .nil
· exact isChain_cons_of_isChain_cons_cons p

theorem isChain_of_isChain_cons_cons (p : IsChain R (a :: b :: l)) :
IsChain R l := isChain_of_isChain_cons (isChain_of_isChain_cons p)
@[deprecated IsChain.of_cons (since := "2026-02-10")]
theorem isChain_of_isChain_cons_cons : IsChain R (a :: b :: l) →
IsChain R l := IsChain.of_cons ∘ IsChain.of_cons

@[grind =>]
theorem IsChain.imp (H : ∀ ⦃a b : α⦄, R a b → S a b)
(p : IsChain R l) : IsChain S l := by induction p with grind

@[deprecated (since := "2025-09-19")]
alias Chain.imp := IsChain.imp

theorem IsChain.cons_of_imp_of_cons (h : ∀ c, R a c → R b c) :
IsChain R (a :: l) → IsChain R (b :: l) := by cases l <;> grind
theorem IsChain.cons_of_imp (h : ∀ c, R a c → R b c) :
IsChain R (a :: l) → IsChain R (b :: l) := by grind [cases List]

@[deprecated IsChain.of_cons (since := "2026-02-10")]
alias IsChain.cons_of_imp_of_cons := IsChain.cons_of_imp

@[deprecated "Use IsChain.imp and IsChain.change_head" (since := "2025-09-19")]
theorem Chain.imp' (HRS : ∀ ⦃a b : α⦄, R a b → S a b)
(Hab : ∀ ⦃c⦄, R a c → S b c) : IsChain R (a :: l) → IsChain S (b :: l) := by
cases l with grind [IsChain.imp]
theorem IsChain.cons_of_imp_of_imp (HRS : ∀ ⦃a b : α⦄, R a b → S a b)
(Hab : ∀ ⦃c⦄, R a c → S b c) (h : IsChain R (a :: l)) : IsChain S (b :: l) := by
grind [cases List]

@[deprecated (since := "2025-09-19")]
alias Chain.imp' := IsChain.cons_of_imp_of_imp

@[deprecated (since := "2025-09-19")]
protected alias Pairwise.chain := Pairwise.isChain

@[grind →] protected theorem IsChain.pairwise [Trans R R R] (c : IsChain R l) :
Pairwise R l := by
induction c with
| nil | singleton => grind
| cons_cons hr h p =>
simp only [pairwise_cons, mem_cons, forall_eq_or_imp] at p ⊢
exact ⟨⟨hr, fun _ ha => Trans.trans hr <| p.1 _ ha⟩, p⟩
theorem isChain_iff_pairwise [Trans R R R] : IsChain R l ↔ Pairwise R l := by
induction l with | nil => grind | cons a l IH => cases l with | nil => grind | cons b l =>
simp only [isChain_cons_cons, IH, pairwise_cons, mem_cons, forall_eq_or_imp, and_congr_left_iff,
iff_self_and, and_imp]
exact flip <| fun _ => flip (Trans.trans · <| · · ·)

theorem isChain_iff_pairwise [Trans R R R] : IsChain R l ↔ Pairwise R l := by grind
@[grind →] protected theorem IsChain.pairwise [Trans R R R] (c : IsChain R l) :
Pairwise R l := isChain_iff_pairwise.mp c

theorem isChain_iff_getElem {l : List α} :
IsChain R l ↔ ∀ (i : Nat) (_hi : i + 1 < l.length), R l[i] l[i + 1] := by
induction l with
| nil => grind
| cons a l IH => cases l with | nil => grind | cons b l => simp [IH, Nat.forall_lt_succ_left']
induction l with | nil => grind | cons a l IH => cases l with | nil => grind | cons b l =>
simp [IH, Nat.forall_lt_succ_left']

theorem IsChain.getElem {l : List α} (c : IsChain R l) (i : Nat) (hi : i + 1 < l.length) :
R l[i] l[i + 1] := isChain_iff_getElem.mp c _ _
Expand Down