l3lab/ntp-mathlib huggingface dataset:
theorem chain'_pair {x y} : Chain' R [x, y] ↔ R x y := by
  

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
a b x y : α
⊢ Chain' R [x, y] ↔ R x y

Next tactic:
simp only [chain'_singleton, chain'_cons, and_true_iff]
theorem chain'_reverse : ∀ {l}, Chain' R (reverse l) ↔ Chain' (flip R) l
  | [] => Iff.rfl
  | [a] => by 

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
a✝ b a : α
⊢ Chain' R (reverse [a]) ↔ Chain' (flip R) [a]

Next tactic:
simp only [chain'_singleton, reverse_singleton]
theorem chain'_reverse : ∀ {l}, Chain' R (reverse l) ↔ Chain' (flip R) l
  | [] => Iff.rfl
  | [a] => by simp only [chain'_singleton, reverse_singleton]
  | a :: b :: l => by
    

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l✝ l₁ l₂ : List α
a✝ b✝ a b : α
l : List α
⊢ Chain' R (reverse (a :: b :: l)) ↔ Chain' (flip R) (a :: b :: l)

Next tactic:
rw [chain'_cons, reverse_cons, reverse_cons, append_assoc, cons_append, nil_append,
      chain'_split, ← reverse_cons, @chain'_reverse (b :: l), and_comm, chain'_pair, flip]
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by 

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a b : α
R : α → α → Prop
⊢ Chain' R []

Next tactic:
simp
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by simp) (fun _ h => by 

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a b : α
R : α → α → Prop
x✝ : ℕ
h : x✝ < length [] - 1
⊢ R (get [] { val := x✝, isLt := (_ : x✝ < length []) }) (get [] { val := x✝ + 1, isLt := (_ : succ x✝ < length []) })

Next tactic:
simp at h
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by simp) (fun _ h => by simp at h)
  | [a] => iff_of_true (by 

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a✝ b : α
R : α → α → Prop
a : α
⊢ Chain' R [a]

Next tactic:
simp
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by simp) (fun _ h => by simp at h)
  | [a] => iff_of_true (by simp) (fun _ h => by 

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a✝ b : α
R : α → α → Prop
a : α
x✝ : ℕ
h : x✝ < length [a] - 1
⊢ R (get [a] { val := x✝, isLt := (_ : x✝ < length [a]) })
    (get [a] { val := x✝ + 1, isLt := (_ : succ x✝ < length [a]) })

Next tactic:
simp at h
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by simp) (fun _ h => by simp at h)
  | [a] => iff_of_true (by simp) (fun _ h => by simp at h)
  | a :: b :: t => by
    

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a✝ b✝ : α
R : α → α → Prop
a b : α
t : List α
⊢ Chain' R (a :: b :: t) ↔
    ∀ (i : ℕ) (h : i < length (a :: b :: t) - 1),
      R (get (a :: b :: t) { val := i, isLt := (_ : i < length (a :: b :: t)) })
        (get (a :: b :: t) { val := i + 1, isLt := (_ : succ i < length (a :: b :: t)) })

Next tactic:
rw [← and_forall_succ, chain'_cons, chain'_iff_get]
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by simp) (fun _ h => by simp at h)
  | [a] => iff_of_true (by simp) (fun _ h => by simp at h)
  | a :: b :: t => by
    rw [← and_forall_succ, chain'_cons, chain'_iff_get]
    

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a✝ b✝ : α
R : α → α → Prop
a b : α
t : List α
⊢ (R a b ∧
      ∀ (i : ℕ) (h : i < length (b :: t) - 1),
        R (get (b :: t) { val := i, isLt := (_ : i < length (b :: t)) })
          (get (b :: t) { val := i + 1, isLt := (_ : succ i < length (b :: t)) })) ↔
    (∀ (h : 0 < length (a :: b :: t) - 1),
        R (get (a :: b :: t) { val := 0, isLt := (_ : 0 < length (a :: b :: t)) })
          (get (a :: b :: t) { val := 0 + 1, isLt := (_ : succ 0 < length (a :: b :: t)) })) ∧
      ∀ (n : ℕ) (h : n + 1 < length (a :: b :: t) - 1),
        R (get (a :: b :: t) { val := n + 1, isLt := (_ : n + 1 < length (a :: b :: t)) })
          (get (a :: b :: t) { val := n + 1 + 1, isLt := (_ : succ (n + 1) < length (a :: b :: t)) })

Next tactic:
simp only [length_cons, get_cons_succ, Fin.zero_eta, get_cons_zero, zero_add, Fin.mk_one,
      get_cons_cons_one, succ_sub_succ_eq_sub, nonpos_iff_eq_zero, add_eq_zero_iff, and_false,
      tsub_zero, add_pos_iff, zero_lt_one, or_true, forall_true_left, and_congr_right_iff]
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by simp) (fun _ h => by simp at h)
  | [a] => iff_of_true (by simp) (fun _ h => by simp at h)
  | a :: b :: t => by
    rw [← and_forall_succ, chain'_cons, chain'_iff_get]
    simp only [length_cons, get_cons_succ, Fin.zero_eta, get_cons_zero, zero_add, Fin.mk_one,
      get_cons_cons_one, succ_sub_succ_eq_sub, nonpos_iff_eq_zero, add_eq_zero_iff, and_false,
      tsub_zero, add_pos_iff, zero_lt_one, or_true, forall_true_left, and_congr_right_iff]
    

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a✝ b✝ : α
R : α → α → Prop
a b : α
t : List α
⊢ R a b →
    ((∀ (i : ℕ) (h : i < length t),
        R (get (b :: t) { val := i, isLt := (_ : i < length (b :: t)) })
          (get t { val := i, isLt := (_ : i < length t) })) ↔
      ∀ (n : ℕ) (h : n + 1 < length t + 1),
        R (get (b :: t) { val := n, isLt := (_ : n < length (b :: t)) })
          (get t { val := n, isLt := (_ : n < length t) }))

Next tactic:
dsimp [succ_sub_one]
theorem chain'_iff_get {R} : ∀ {l : List α}, Chain' R l ↔
    ∀ (i : ℕ) (h : i < length l - 1),
      R (get l ⟨i, lt_of_lt_pred h⟩) (get l ⟨i + 1, lt_pred_iff.mp h⟩)
  | [] => iff_of_true (by simp) (fun _ h => by simp at h)
  | [a] => iff_of_true (by simp) (fun _ h => by simp at h)
  | a :: b :: t => by
    rw [← and_forall_succ, chain'_cons, chain'_iff_get]
    simp only [length_cons, get_cons_succ, Fin.zero_eta, get_cons_zero, zero_add, Fin.mk_one,
      get_cons_cons_one, succ_sub_succ_eq_sub, nonpos_iff_eq_zero, add_eq_zero_iff, and_false,
      tsub_zero, add_pos_iff, zero_lt_one, or_true, forall_true_left, and_congr_right_iff]
    dsimp [succ_sub_one]
    

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l l₁ l₂ : List α
a✝ b✝ : α
R : α → α → Prop
a b : α
t : List α
⊢ R a b →
    ((∀ (i : ℕ) (h : i < length t),
        R (get (b :: t) { val := i, isLt := (_ : i < succ (length t)) })
          (get t { val := i, isLt := (_ : i < length t) })) ↔
      ∀ (n : ℕ) (h : n + 1 < length t + 1),
        R (get (b :: t) { val := n, isLt := (_ : n < succ (length t)) })
          (get t { val := n, isLt := (_ : n < length t) }))

Next tactic:
exact fun _ => ⟨fun h i hi => h i (Nat.lt_of_succ_lt_succ hi),
                    fun h i hi => h i (Nat.succ_lt_succ hi)⟩
set_option linter.deprecated false in
@[deprecated chain'_iff_get]
theorem chain'_iff_nthLe {R} {l : List α} : Chain' R l ↔
    ∀ (i) (h : i < length l - 1),
      R (nthLe l i (lt_of_lt_pred h)) (nthLe l (i + 1) (lt_pred_iff.mp h)) :=
  chain'_iff_get.trans <| by 

Proof state:
α : Type u
β : Type v
R✝ r : α → α → Prop
l✝ l₁ l₂ : List α
a b : α
R : α → α → Prop
l : List α
⊢ (∀ (i : ℕ) (h : i < length l - 1),
      R (get l { val := i, isLt := (_ : i < length l) }) (get l { val := i + 1, isLt := (_ : succ i < length l) })) ↔
    ∀ (i : ℕ) (h : i < length l - 1), R (nthLe l i (_ : i < length l)) (nthLe l (i + 1) (_ : succ i < length l))

Next tactic:
simp [nthLe]
/-- If `l₁ l₂` and `l₃` are lists and `l₁ ++ l₂` and `l₂ ++ l₃` both satisfy
  `Chain' R`, then so does `l₁ ++ l₂ ++ l₃` provided `l₂ ≠ []` -/
theorem Chain'.append_overlap {l₁ l₂ l₃ : List α} (h₁ : Chain' R (l₁ ++ l₂))
    (h₂ : Chain' R (l₂ ++ l₃)) (hn : l₂ ≠ []) : Chain' R (l₁ ++ l₂ ++ l₃) :=
  h₁.append h₂.right_of_append <| by
    

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁✝ l₂✝ : List α
a b : α
l₁ l₂ l₃ : List α
h₁ : Chain' R (l₁ ++ l₂)
h₂ : Chain' R (l₂ ++ l₃)
hn : l₂ ≠ []
⊢ ∀ (x : α), x ∈ getLast? (l₁ ++ l₂) → ∀ (y : α), y ∈ head? l₃ → R x y

Next tactic:
simpa only [getLast?_append_of_ne_nil _ hn] using (chain'_append.1 h₂).2.2
lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L →
    (Chain' R L.join ↔ (∀ l ∈ L, Chain' R l) ∧
    L.Chain' (fun l₁ l₂ => ∀ᵉ (x ∈ l₁.getLast?) (y ∈ l₂.head?), R x y))
| [], _ => by 

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
a b : α
x✝ : ¬[] ∈ []
⊢ Chain' R (join []) ↔
    (∀ (l : List α), l ∈ [] → Chain' R l) ∧
      Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) []

Next tactic:
simp
lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L →
    (Chain' R L.join ↔ (∀ l ∈ L, Chain' R l) ∧
    L.Chain' (fun l₁ l₂ => ∀ᵉ (x ∈ l₁.getLast?) (y ∈ l₂.head?), R x y))
| [], _ => by simp
| [l], _ => by 

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l✝ l₁ l₂ : List α
a b : α
l : List α
x✝ : ¬[] ∈ [l]
⊢ Chain' R (join [l]) ↔
    (∀ (l_1 : List α), l_1 ∈ [l] → Chain' R l_1) ∧
      Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) [l]

Next tactic:
simp [join]
lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L →
    (Chain' R L.join ↔ (∀ l ∈ L, Chain' R l) ∧
    L.Chain' (fun l₁ l₂ => ∀ᵉ (x ∈ l₁.getLast?) (y ∈ l₂.head?), R x y))
| [], _ => by simp
| [l], _ => by simp [join]
| (l₁ :: l₂ :: L), hL => by
    

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁✝ l₂✝ : List α
a b : α
l₁ l₂ : List α
L : List (List α)
hL : ¬[] ∈ l₁ :: l₂ :: L
⊢ Chain' R (join (l₁ :: l₂ :: L)) ↔
    (∀ (l : List α), l ∈ l₁ :: l₂ :: L → Chain' R l) ∧
      Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₁ :: l₂ :: L)

Next tactic:
rw [mem_cons, not_or, ← Ne.def] at hL
lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L →
    (Chain' R L.join ↔ (∀ l ∈ L, Chain' R l) ∧
    L.Chain' (fun l₁ l₂ => ∀ᵉ (x ∈ l₁.getLast?) (y ∈ l₂.head?), R x y))
| [], _ => by simp
| [l], _ => by simp [join]
| (l₁ :: l₂ :: L), hL => by
    rw [mem_cons, not_or, ← Ne.def] at hL
    

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁✝ l₂✝ : List α
a b : α
l₁ l₂ : List α
L : List (List α)
hL : [] ≠ l₁ ∧ ¬[] ∈ l₂ :: L
⊢ Chain' R (join (l₁ :: l₂ :: L)) ↔
    (∀ (l : List α), l ∈ l₁ :: l₂ :: L → Chain' R l) ∧
      Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₁ :: l₂ :: L)

Next tactic:
rw [join, chain'_append, chain'_join hL.2, forall_mem_cons, chain'_cons]
lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L →
    (Chain' R L.join ↔ (∀ l ∈ L, Chain' R l) ∧
    L.Chain' (fun l₁ l₂ => ∀ᵉ (x ∈ l₁.getLast?) (y ∈ l₂.head?), R x y))
| [], _ => by simp
| [l], _ => by simp [join]
| (l₁ :: l₂ :: L), hL => by
    rw [mem_cons, not_or, ← Ne.def] at hL
    rw [join, chain'_append, chain'_join hL.2, forall_mem_cons, chain'_cons]
    

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁✝ l₂✝ : List α
a b : α
l₁ l₂ : List α
L : List (List α)
hL : [] ≠ l₁ ∧ ¬[] ∈ l₂ :: L
⊢ (Chain' R l₁ ∧
      ((Chain' R l₂ ∧ ∀ (x : List α), x ∈ L → Chain' R x) ∧
          Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₂ :: L)) ∧
        ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? (join (l₂ :: L)) → R x y) ↔
    (∀ (l : List α), l ∈ l₁ :: l₂ :: L → Chain' R l) ∧
      (∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) ∧
        Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₂ :: L)

Next tactic:
rw [mem_cons, not_or, ← Ne.def] at hL
lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L →
    (Chain' R L.join ↔ (∀ l ∈ L, Chain' R l) ∧
    L.Chain' (fun l₁ l₂ => ∀ᵉ (x ∈ l₁.getLast?) (y ∈ l₂.head?), R x y))
| [], _ => by simp
| [l], _ => by simp [join]
| (l₁ :: l₂ :: L), hL => by
    rw [mem_cons, not_or, ← Ne.def] at hL
    rw [join, chain'_append, chain'_join hL.2, forall_mem_cons, chain'_cons]
    rw [mem_cons, not_or, ← Ne.def] at hL
    

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁✝ l₂✝ : List α
a b : α
l₁ l₂ : List α
L : List (List α)
hL : [] ≠ l₁ ∧ [] ≠ l₂ ∧ ¬[] ∈ L
⊢ (Chain' R l₁ ∧
      ((Chain' R l₂ ∧ ∀ (x : List α), x ∈ L → Chain' R x) ∧
          Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₂ :: L)) ∧
        ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? (join (l₂ :: L)) → R x y) ↔
    (∀ (l : List α), l ∈ l₁ :: l₂ :: L → Chain' R l) ∧
      (∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) ∧
        Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₂ :: L)

Next tactic:
simp only [forall_mem_cons, and_assoc, join, head?_append_of_ne_nil _ hL.2.1.symm]
lemma chain'_join : ∀ {L : List (List α)}, [] ∉ L →
    (Chain' R L.join ↔ (∀ l ∈ L, Chain' R l) ∧
    L.Chain' (fun l₁ l₂ => ∀ᵉ (x ∈ l₁.getLast?) (y ∈ l₂.head?), R x y))
| [], _ => by simp
| [l], _ => by simp [join]
| (l₁ :: l₂ :: L), hL => by
    rw [mem_cons, not_or, ← Ne.def] at hL
    rw [join, chain'_append, chain'_join hL.2, forall_mem_cons, chain'_cons]
    rw [mem_cons, not_or, ← Ne.def] at hL
    simp only [forall_mem_cons, and_assoc, join, head?_append_of_ne_nil _ hL.2.1.symm]
    

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁✝ l₂✝ : List α
a b : α
l₁ l₂ : List α
L : List (List α)
hL : [] ≠ l₁ ∧ [] ≠ l₂ ∧ ¬[] ∈ L
⊢ (Chain' R l₁ ∧
      Chain' R l₂ ∧
        (∀ (x : List α), x ∈ L → Chain' R x) ∧
          Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₂ :: L) ∧
            ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) ↔
    Chain' R l₁ ∧
      Chain' R l₂ ∧
        (∀ (x : List α), x ∈ L → Chain' R x) ∧
          (∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) ∧
            Chain' (fun l₁ l₂ => ∀ (x : α), x ∈ getLast? l₁ → ∀ (y : α), y ∈ head? l₂ → R x y) (l₂ :: L)

Next tactic:
exact Iff.rfl.and (Iff.rfl.and $ Iff.rfl.and and_comm)
/-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is an
`r`-chain starting from `a` and ending on `b`.
The converse of `relationReflTransGen_of_exists_chain`.
-/
theorem exists_chain_of_relationReflTransGen (h : Relation.ReflTransGen r a b) :
    ∃ l, Chain r a l ∧ getLast (a :: l) (cons_ne_nil _ _) = b := by
  

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
a b : α
h : Relation.ReflTransGen r a b
⊢ ∃ l, Chain r a l ∧ getLast (a :: l) (_ : a :: l ≠ []) = b

Next tactic:
refine' Relation.ReflTransGen.head_induction_on h _ _
/-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is an
`r`-chain starting from `a` and ending on `b`.
The converse of `relationReflTransGen_of_exists_chain`.
-/
theorem exists_chain_of_relationReflTransGen (h : Relation.ReflTransGen r a b) :
    ∃ l, Chain r a l ∧ getLast (a :: l) (cons_ne_nil _ _) = b := by
  refine' Relation.ReflTransGen.head_induction_on h _ _
  · 

Proof state:
case refine'_1
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
a b : α
h : Relation.ReflTransGen r a b
⊢ ∃ l, Chain r b l ∧ getLast (b :: l) (_ : b :: l ≠ []) = b

Next tactic:
exact ⟨[], Chain.nil, rfl⟩
/-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is an
`r`-chain starting from `a` and ending on `b`.
The converse of `relationReflTransGen_of_exists_chain`.
-/
theorem exists_chain_of_relationReflTransGen (h : Relation.ReflTransGen r a b) :
    ∃ l, Chain r a l ∧ getLast (a :: l) (cons_ne_nil _ _) = b := by
  refine' Relation.ReflTransGen.head_induction_on h _ _
  · exact ⟨[], Chain.nil, rfl⟩
  · 

Proof state:
case refine'_2
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
a b : α
h : Relation.ReflTransGen r a b
⊢ ∀ {a c : α},
    r a c →
      Relation.ReflTransGen r c b →
        (∃ l, Chain r c l ∧ getLast (c :: l) (_ : c :: l ≠ []) = b) →
          ∃ l, Chain r a l ∧ getLast (a :: l) (_ : a :: l ≠ []) = b

Next tactic:
intro c d e _ ih
/-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is an
`r`-chain starting from `a` and ending on `b`.
The converse of `relationReflTransGen_of_exists_chain`.
-/
theorem exists_chain_of_relationReflTransGen (h : Relation.ReflTransGen r a b) :
    ∃ l, Chain r a l ∧ getLast (a :: l) (cons_ne_nil _ _) = b := by
  refine' Relation.ReflTransGen.head_induction_on h _ _
  · exact ⟨[], Chain.nil, rfl⟩
  · intro c d e _ ih
    

Proof state:
case refine'_2
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
a b : α
h : Relation.ReflTransGen r a b
c d : α
e : r c d
h✝ : Relation.ReflTransGen r d b
ih : ∃ l, Chain r d l ∧ getLast (d :: l) (_ : d :: l ≠ []) = b
⊢ ∃ l, Chain r c l ∧ getLast (c :: l) (_ : c :: l ≠ []) = b

Next tactic:
obtain ⟨l, hl₁, hl₂⟩ := ih
/-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is an
`r`-chain starting from `a` and ending on `b`.
The converse of `relationReflTransGen_of_exists_chain`.
-/
theorem exists_chain_of_relationReflTransGen (h : Relation.ReflTransGen r a b) :
    ∃ l, Chain r a l ∧ getLast (a :: l) (cons_ne_nil _ _) = b := by
  refine' Relation.ReflTransGen.head_induction_on h _ _
  · exact ⟨[], Chain.nil, rfl⟩
  · intro c d e _ ih
    obtain ⟨l, hl₁, hl₂⟩ := ih
    

Proof state:
case refine'_2.intro.intro
α : Type u
β : Type v
R r : α → α → Prop
l✝ l₁ l₂ : List α
a b : α
h : Relation.ReflTransGen r a b
c d : α
e : r c d
h✝ : Relation.ReflTransGen r d b
l : List α
hl₁ : Chain r d l
hl₂ : getLast (d :: l) (_ : d :: l ≠ []) = b
⊢ ∃ l, Chain r c l ∧ getLast (c :: l) (_ : c :: l ≠ []) = b

Next tactic:
refine' ⟨d :: l, Chain.cons e hl₁, _⟩
/-- If `a` and `b` are related by the reflexive transitive closure of `r`, then there is an
`r`-chain starting from `a` and ending on `b`.
The converse of `relationReflTransGen_of_exists_chain`.
-/
theorem exists_chain_of_relationReflTransGen (h : Relation.ReflTransGen r a b) :
    ∃ l, Chain r a l ∧ getLast (a :: l) (cons_ne_nil _ _) = b := by
  refine' Relation.ReflTransGen.head_induction_on h _ _
  · exact ⟨[], Chain.nil, rfl⟩
  · intro c d e _ ih
    obtain ⟨l, hl₁, hl₂⟩ := ih
    refine' ⟨d :: l, Chain.cons e hl₁, _⟩
    

Proof state:
case refine'_2.intro.intro
α : Type u
β : Type v
R r : α → α → Prop
l✝ l₁ l₂ : List α
a b : α
h : Relation.ReflTransGen r a b
c d : α
e : r c d
h✝ : Relation.ReflTransGen r d b
l : List α
hl₁ : Chain r d l
hl₂ : getLast (d :: l) (_ : d :: l ≠ []) = b
⊢ getLast (c :: d :: l) (_ : c :: d :: l ≠ []) = b

Next tactic:
rwa [getLast_cons_cons]
/-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then
the predicate is true everywhere in the chain and at `a`.
That is, we can propagate the predicate up the chain.
-/
theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l)
    (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x)
    (final : p b) : ∀ i ∈ a :: l, p i := by
  

Proof state:
α : Type u
β : Type v
R r : α → α → Prop
l✝ l₁ l₂ : List α
a b : α
p : α → Prop
l : List α
h : Chain r a l
hb : getLast (a :: l) (_ : a :: l ≠ []) = b
carries : ∀ ⦃x y : α⦄, r x y → p y → p x
final : p b
⊢ ∀ (i : α), i ∈ a :: l → p i

Next tactic:
induction' l with _ _ l_ih generalizing a
/-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then
the predicate is true everywhere in the chain and at `a`.
That is, we can propagate the predicate up the chain.
-/
theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l)
    (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x)
    (final : p b) : ∀ i ∈ a :: l, p i := by
  induction' l with _ _ l_ih generalizing a
  · 

Proof state:
case nil
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
b : α
p : α → Prop
carries : ∀ ⦃x y : α⦄, r x y → p y → p x
final : p b
a : α
h : Chain r a []
hb : getLast [a] (_ : [a] ≠ []) = b
⊢ ∀ (i : α), i ∈ [a] → p i

Next tactic:
cases hb
/-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then
the predicate is true everywhere in the chain and at `a`.
That is, we can propagate the predicate up the chain.
-/
theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l)
    (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x)
    (final : p b) : ∀ i ∈ a :: l, p i := by
  induction' l with _ _ l_ih generalizing a
  · cases hb
    

Proof state:
case nil.refl
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
p : α → Prop
carries : ∀ ⦃x y : α⦄, r x y → p y → p x
a : α
h : Chain r a []
final : p (getLast [a] (_ : [a] ≠ []))
⊢ ∀ (i : α), i ∈ [a] → p i

Next tactic:
simpa using final
/-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then
the predicate is true everywhere in the chain and at `a`.
That is, we can propagate the predicate up the chain.
-/
theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l)
    (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x)
    (final : p b) : ∀ i ∈ a :: l, p i := by
  induction' l with _ _ l_ih generalizing a
  · cases hb
    simpa using final
  · 

Proof state:
case cons
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
b : α
p : α → Prop
carries : ∀ ⦃x y : α⦄, r x y → p y → p x
final : p b
head✝ : α
tail✝ : List α
l_ih : ∀ {a : α}, Chain r a tail✝ → getLast (a :: tail✝) (_ : a :: tail✝ ≠ []) = b → ∀ (i : α), i ∈ a :: tail✝ → p i
a : α
h : Chain r a (head✝ :: tail✝)
hb : getLast (a :: head✝ :: tail✝) (_ : a :: head✝ :: tail✝ ≠ []) = b
⊢ ∀ (i : α), i ∈ a :: head✝ :: tail✝ → p i

Next tactic:
rw [chain_cons] at h
/-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then
the predicate is true everywhere in the chain and at `a`.
That is, we can propagate the predicate up the chain.
-/
theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l)
    (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x)
    (final : p b) : ∀ i ∈ a :: l, p i := by
  induction' l with _ _ l_ih generalizing a
  · cases hb
    simpa using final
  · rw [chain_cons] at h
    

Proof state:
case cons
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
b : α
p : α → Prop
carries : ∀ ⦃x y : α⦄, r x y → p y → p x
final : p b
head✝ : α
tail✝ : List α
l_ih : ∀ {a : α}, Chain r a tail✝ → getLast (a :: tail✝) (_ : a :: tail✝ ≠ []) = b → ∀ (i : α), i ∈ a :: tail✝ → p i
a : α
h : r a head✝ ∧ Chain r head✝ tail✝
hb : getLast (a :: head✝ :: tail✝) (_ : a :: head✝ :: tail✝ ≠ []) = b
⊢ ∀ (i : α), i ∈ a :: head✝ :: tail✝ → p i

Next tactic:
simp only [mem_cons]
/-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then
the predicate is true everywhere in the chain and at `a`.
That is, we can propagate the predicate up the chain.
-/
theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l)
    (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x)
    (final : p b) : ∀ i ∈ a :: l, p i := by
  induction' l with _ _ l_ih generalizing a
  · cases hb
    simpa using final
  · rw [chain_cons] at h
    simp only [mem_cons]
    

Proof state:
case cons
α : Type u
β : Type v
R r : α → α → Prop
l l₁ l₂ : List α
b : α
p : α → Prop
carries : ∀ ⦃x y : α⦄, r x y → p y → p x
final : p b
head✝ : α
tail✝ : List α
l_ih : ∀ {a : α}, Chain r a tail✝ → getLast (a :: tail✝) (_ : a :: tail✝ ≠ []) = b → ∀ (i : α), i ∈ a :: tail✝ → p i
a : α
h : r a head✝ ∧ Chain r head✝ tail✝
hb : getLast (a :: head✝ :: tail✝) (_ : a :: head✝ :: tail✝ ≠ []) = b
⊢ ∀ (i : α), i = a ∨ i = head✝ ∨ i ∈ tail✝ → p i

Next tactic:
rintro _ (rfl | H)