l3lab/ntp-mathlib huggingface dataset:
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  induction l₁ generalizing l₂ i
  · simp [zipWith]
  · 

Proof state:
case cons
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
z : γ
head✝ : α
tail✝ : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail✝ l₂) i = some z ↔ ∃ x y, get? tail✝ i = some x ∧ get? l₂ i = some y ∧ f x y = z
l₂ : List β
i : ℕ
⊢ get? (zipWith f (head✝ :: tail✝) l₂) i = some z ↔
    ∃ x y, get? (head✝ :: tail✝) i = some x ∧ get? l₂ i = some y ∧ f x y = z

Next tactic:
cases l₂
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  induction l₁ generalizing l₂ i
  · simp [zipWith]
  · cases l₂ <;> 

Proof state:
case cons.nil
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
z : γ
head✝ : α
tail✝ : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail✝ l₂) i = some z ↔ ∃ x y, get? tail✝ i = some x ∧ get? l₂ i = some y ∧ f x y = z
i : ℕ
⊢ get? (zipWith f (head✝ :: tail✝) []) i = some z ↔
    ∃ x y, get? (head✝ :: tail✝) i = some x ∧ get? [] i = some y ∧ f x y = z

Next tactic:
simp only [zipWith, get?, exists_false, and_false_iff, false_and_iff]
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  induction l₁ generalizing l₂ i
  · simp [zipWith]
  · cases l₂ <;> 

Proof state:
case cons.cons
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
z : γ
head✝¹ : α
tail✝¹ : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail✝¹ l₂) i = some z ↔ ∃ x y, get? tail✝¹ i = some x ∧ get? l₂ i = some y ∧ f x y = z
i : ℕ
head✝ : β
tail✝ : List β
⊢ get? (zipWith f (head✝¹ :: tail✝¹) (head✝ :: tail✝)) i = some z ↔
    ∃ x y, get? (head✝¹ :: tail✝¹) i = some x ∧ get? (head✝ :: tail✝) i = some y ∧ f x y = z

Next tactic:
simp only [zipWith, get?, exists_false, and_false_iff, false_and_iff]
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  induction l₁ generalizing l₂ i
  · simp [zipWith]
  · cases l₂ <;> simp only [zipWith, get?, exists_false, and_false_iff, false_and_iff]
    

Proof state:
case cons.cons
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
z : γ
head✝¹ : α
tail✝¹ : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail✝¹ l₂) i = some z ↔ ∃ x y, get? tail✝¹ i = some x ∧ get? l₂ i = some y ∧ f x y = z
i : ℕ
head✝ : β
tail✝ : List β
⊢ get? (f head✝¹ head✝ :: zipWith f tail✝¹ tail✝) i = some z ↔
    ∃ x y, get? (head✝¹ :: tail✝¹) i = some x ∧ get? (head✝ :: tail✝) i = some y ∧ f x y = z

Next tactic:
cases i
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  induction l₁ generalizing l₂ i
  · simp [zipWith]
  · cases l₂ <;> simp only [zipWith, get?, exists_false, and_false_iff, false_and_iff]
    cases i <;> 

Proof state:
case cons.cons.zero
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
z : γ
head✝¹ : α
tail✝¹ : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail✝¹ l₂) i = some z ↔ ∃ x y, get? tail✝¹ i = some x ∧ get? l₂ i = some y ∧ f x y = z
head✝ : β
tail✝ : List β
⊢ get? (f head✝¹ head✝ :: zipWith f tail✝¹ tail✝) zero = some z ↔
    ∃ x y, get? (head✝¹ :: tail✝¹) zero = some x ∧ get? (head✝ :: tail✝) zero = some y ∧ f x y = z

Next tactic:
simp [*]
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  induction l₁ generalizing l₂ i
  · simp [zipWith]
  · cases l₂ <;> simp only [zipWith, get?, exists_false, and_false_iff, false_and_iff]
    cases i <;> 

Proof state:
case cons.cons.succ
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
z : γ
head✝¹ : α
tail✝¹ : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail✝¹ l₂) i = some z ↔ ∃ x y, get? tail✝¹ i = some x ∧ get? l₂ i = some y ∧ f x y = z
head✝ : β
tail✝ : List β
n✝ : ℕ
⊢ get? (f head✝¹ head✝ :: zipWith f tail✝¹ tail✝) (succ n✝) = some z ↔
    ∃ x y, get? (head✝¹ :: tail✝¹) (succ n✝) = some x ∧ get? (head✝ :: tail✝) (succ n✝) = some y ∧ f x y = z

Next tactic:
simp [*]
theorem get?_zip_eq_some (l₁ : List α) (l₂ : List β) (z : α × β) (i : ℕ) :
    (zip l₁ l₂).get? i = some z ↔ l₁.get? i = some z.1 ∧ l₂.get? i = some z.2 := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
z : α × β
i : ℕ
⊢ get? (zip l₁ l₂) i = some z ↔ get? l₁ i = some z.1 ∧ get? l₂ i = some z.2

Next tactic:
cases z
theorem get?_zip_eq_some (l₁ : List α) (l₂ : List β) (z : α × β) (i : ℕ) :
    (zip l₁ l₂).get? i = some z ↔ l₁.get? i = some z.1 ∧ l₂.get? i = some z.2 := by
  cases z
  

Proof state:
case mk
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
i : ℕ
fst✝ : α
snd✝ : β
⊢ get? (zip l₁ l₂) i = some (fst✝, snd✝) ↔ get? l₁ i = some (fst✝, snd✝).1 ∧ get? l₂ i = some (fst✝, snd✝).2

Next tactic:
rw [zip, get?_zip_with_eq_some]
theorem get?_zip_eq_some (l₁ : List α) (l₂ : List β) (z : α × β) (i : ℕ) :
    (zip l₁ l₂).get? i = some z ↔ l₁.get? i = some z.1 ∧ l₂.get? i = some z.2 := by
  cases z
  rw [zip, get?_zip_with_eq_some]; 

Proof state:
case mk
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
i : ℕ
fst✝ : α
snd✝ : β
⊢ (∃ x y, get? l₁ i = some x ∧ get? l₂ i = some y ∧ (x, y) = (fst✝, snd✝)) ↔
    get? l₁ i = some (fst✝, snd✝).1 ∧ get? l₂ i = some (fst✝, snd✝).2

Next tactic:
constructor
theorem get?_zip_eq_some (l₁ : List α) (l₂ : List β) (z : α × β) (i : ℕ) :
    (zip l₁ l₂).get? i = some z ↔ l₁.get? i = some z.1 ∧ l₂.get? i = some z.2 := by
  cases z
  rw [zip, get?_zip_with_eq_some]; constructor
  · 

Proof state:
case mk.mp
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
i : ℕ
fst✝ : α
snd✝ : β
⊢ (∃ x y, get? l₁ i = some x ∧ get? l₂ i = some y ∧ (x, y) = (fst✝, snd✝)) →
    get? l₁ i = some (fst✝, snd✝).1 ∧ get? l₂ i = some (fst✝, snd✝).2

Next tactic:
rintro ⟨x, y, h₀, h₁, h₂⟩
theorem get?_zip_eq_some (l₁ : List α) (l₂ : List β) (z : α × β) (i : ℕ) :
    (zip l₁ l₂).get? i = some z ↔ l₁.get? i = some z.1 ∧ l₂.get? i = some z.2 := by
  cases z
  rw [zip, get?_zip_with_eq_some]; constructor
  · rintro ⟨x, y, h₀, h₁, h₂⟩
    

Proof state:
case mk.mp.intro.intro.intro.intro
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
i : ℕ
fst✝ : α
snd✝ : β
x : α
y : β
h₀ : get? l₁ i = some x
h₁ : get? l₂ i = some y
h₂ : (x, y) = (fst✝, snd✝)
⊢ get? l₁ i = some (fst✝, snd✝).1 ∧ get? l₂ i = some (fst✝, snd✝).2

Next tactic:
simpa [h₀, h₁] using h₂
theorem get?_zip_eq_some (l₁ : List α) (l₂ : List β) (z : α × β) (i : ℕ) :
    (zip l₁ l₂).get? i = some z ↔ l₁.get? i = some z.1 ∧ l₂.get? i = some z.2 := by
  cases z
  rw [zip, get?_zip_with_eq_some]; constructor
  · rintro ⟨x, y, h₀, h₁, h₂⟩
    simpa [h₀, h₁] using h₂
  · 

Proof state:
case mk.mpr
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
i : ℕ
fst✝ : α
snd✝ : β
⊢ get? l₁ i = some (fst✝, snd✝).1 ∧ get? l₂ i = some (fst✝, snd✝).2 →
    ∃ x y, get? l₁ i = some x ∧ get? l₂ i = some y ∧ (x, y) = (fst✝, snd✝)

Next tactic:
rintro ⟨h₀, h₁⟩
theorem get?_zip_eq_some (l₁ : List α) (l₂ : List β) (z : α × β) (i : ℕ) :
    (zip l₁ l₂).get? i = some z ↔ l₁.get? i = some z.1 ∧ l₂.get? i = some z.2 := by
  cases z
  rw [zip, get?_zip_with_eq_some]; constructor
  · rintro ⟨x, y, h₀, h₁, h₂⟩
    simpa [h₀, h₁] using h₂
  · rintro ⟨h₀, h₁⟩
    

Proof state:
case mk.mpr.intro
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
i : ℕ
fst✝ : α
snd✝ : β
h₀ : get? l₁ i = some (fst✝, snd✝).1
h₁ : get? l₂ i = some (fst✝, snd✝).2
⊢ ∃ x y, get? l₁ i = some x ∧ get? l₂ i = some y ∧ (x, y) = (fst✝, snd✝)

Next tactic:
exact ⟨_, _, h₀, h₁, rfl⟩
@[simp]
theorem get_zipWith {f : α → β → γ} {l : List α} {l' : List β} {i : Fin (zipWith f l l').length} :
    (zipWith f l l').get i =
      f (l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩)
        (l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩) := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l : List α
l' : List β
i : Fin (length (zipWith f l l'))
⊢ get (zipWith f l l') i =
    f (get l { val := ↑i, isLt := (_ : ↑i < length l) }) (get l' { val := ↑i, isLt := (_ : ↑i < length l') })

Next tactic:
rw [← Option.some_inj, ← get?_eq_get, get?_zip_with_eq_some]
@[simp]
theorem get_zipWith {f : α → β → γ} {l : List α} {l' : List β} {i : Fin (zipWith f l l').length} :
    (zipWith f l l').get i =
      f (l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩)
        (l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩) := by
  rw [← Option.some_inj, ← get?_eq_get, get?_zip_with_eq_some]
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l : List α
l' : List β
i : Fin (length (zipWith f l l'))
⊢ ∃ x y,
    get? l ↑i = some x ∧
      get? l' ↑i = some y ∧
        f x y =
          f (get l { val := ↑i, isLt := (_ : ↑i < length l) }) (get l' { val := ↑i, isLt := (_ : ↑i < length l') })

Next tactic:
exact
    ⟨l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩, l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩,
      by rw [get?_eq_get], by rw [get?_eq_get]; exact ⟨rfl, rfl⟩⟩
@[simp]
theorem get_zipWith {f : α → β → γ} {l : List α} {l' : List β} {i : Fin (zipWith f l l').length} :
    (zipWith f l l').get i =
      f (l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩)
        (l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩) := by
  rw [← Option.some_inj, ← get?_eq_get, get?_zip_with_eq_some]
  exact
    ⟨l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩, l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩,
      by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l : List α
l' : List β
i : Fin (length (zipWith f l l'))
⊢ get? l ↑i = some (get l { val := ↑i, isLt := (_ : ↑i < length l) })

Next tactic:
rw [get?_eq_get]
@[simp]
theorem get_zipWith {f : α → β → γ} {l : List α} {l' : List β} {i : Fin (zipWith f l l').length} :
    (zipWith f l l').get i =
      f (l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩)
        (l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩) := by
  rw [← Option.some_inj, ← get?_eq_get, get?_zip_with_eq_some]
  exact
    ⟨l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩, l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩,
      by rw [get?_eq_get], by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l : List α
l' : List β
i : Fin (length (zipWith f l l'))
⊢ get? l' ↑i = some (get l' { val := ↑i, isLt := (_ : ↑i < length l') }) ∧
    f (get l { val := ↑i, isLt := (_ : ↑i < length l) }) (get l' { val := ↑i, isLt := (_ : ↑i < length l') }) =
      f (get l { val := ↑i, isLt := (_ : ↑i < length l) }) (get l' { val := ↑i, isLt := (_ : ↑i < length l') })

Next tactic:
rw [get?_eq_get]
@[simp]
theorem get_zipWith {f : α → β → γ} {l : List α} {l' : List β} {i : Fin (zipWith f l l').length} :
    (zipWith f l l').get i =
      f (l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩)
        (l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩) := by
  rw [← Option.some_inj, ← get?_eq_get, get?_zip_with_eq_some]
  exact
    ⟨l.get ⟨i, lt_length_left_of_zipWith i.isLt⟩, l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩,
      by rw [get?_eq_get], by rw [get?_eq_get]; 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l : List α
l' : List β
i : Fin (length (zipWith f l l'))
⊢ some (get l' { val := ↑i, isLt := ?m.48545 }) = some (get l' { val := ↑i, isLt := (_ : ↑i < length l') }) ∧
    f (get l { val := ↑i, isLt := (_ : ↑i < length l) }) (get l' { val := ↑i, isLt := (_ : ↑i < length l') }) =
      f (get l { val := ↑i, isLt := (_ : ↑i < length l) }) (get l' { val := ↑i, isLt := (_ : ↑i < length l') })
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l : List α
l' : List β
i : Fin (length (zipWith f l l'))
⊢ ↑i < length l'

Next tactic:
exact ⟨rfl, rfl⟩
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l init tail : List α
⊢ (init, tail) ∈ zip (inits l) (tails l) ↔ init ++ tail = l

Next tactic:
induction' l with hd tl ih generalizing init tail
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> 

Proof state:
case nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
init tail : List α
⊢ (init, tail) ∈ zip (inits []) (tails []) ↔ init ++ tail = []

Next tactic:
simp_rw [tails, inits, zip_cons_cons]
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> 

Proof state:
case cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
init tail : List α
⊢ (init, tail) ∈ zip (inits (hd :: tl)) (tails (hd :: tl)) ↔ init ++ tail = hd :: tl

Next tactic:
simp_rw [tails, inits, zip_cons_cons]
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · 

Proof state:
case nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
init tail : List α
⊢ (init, tail) ∈ ([], []) :: zip [] [] ↔ init ++ tail = []

Next tactic:
simp
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · 

Proof state:
case cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
init tail : List α
⊢ (init, tail) ∈ ([], hd :: tl) :: zip (map (fun t => hd :: t) (inits tl)) (tails tl) ↔ init ++ tail = hd :: tl

Next tactic:
constructor
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> 

Proof state:
case cons.mp
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
init tail : List α
⊢ (init, tail) ∈ ([], hd :: tl) :: zip (map (fun t => hd :: t) (inits tl)) (tails tl) → init ++ tail = hd :: tl

Next tactic:
rw [mem_cons, zip_map_left, mem_map, Prod.exists]
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> 

Proof state:
case cons.mpr
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
init tail : List α
⊢ init ++ tail = hd :: tl → (init, tail) ∈ ([], hd :: tl) :: zip (map (fun t => hd :: t) (inits tl)) (tails tl)

Next tactic:
rw [mem_cons, zip_map_left, mem_map, Prod.exists]
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · 

Proof state:
case cons.mp
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
init tail : List α
⊢ ((init, tail) = ([], hd :: tl) ∨
      ∃ a b, (a, b) ∈ zip (inits tl) (tails tl) ∧ Prod.map (fun t => hd :: t) id (a, b) = (init, tail)) →
    init ++ tail = hd :: tl

Next tactic:
rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · 

Proof state:
case cons.mp.inl.refl
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
⊢ [] ++ hd :: tl = hd :: tl

Next tactic:
simp
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · simp
      · 

Proof state:
case cons.mp.inr.intro.intro.intro.refl
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
w✝¹ w✝ : List α
h : (w✝¹, w✝) ∈ zip (inits tl) (tails tl)
⊢ (fun t => hd :: t) w✝¹ ++ id w✝ = hd :: tl

Next tactic:
simp [ih.mp h]
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · simp
      · simp [ih.mp h]
    · 

Proof state:
case cons.mpr
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
init tail : List α
⊢ init ++ tail = hd :: tl →
    (init, tail) = ([], hd :: tl) ∨
      ∃ a b, (a, b) ∈ zip (inits tl) (tails tl) ∧ Prod.map (fun t => hd :: t) id (a, b) = (init, tail)

Next tactic:
cases' init with hd' tl'
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · simp
      · simp [ih.mp h]
    · cases' init with hd' tl'
      · 

Proof state:
case cons.mpr.nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
tail : List α
⊢ [] ++ tail = hd :: tl →
    ([], tail) = ([], hd :: tl) ∨
      ∃ a b, (a, b) ∈ zip (inits tl) (tails tl) ∧ Prod.map (fun t => hd :: t) id (a, b) = ([], tail)

Next tactic:
rintro rfl
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · simp
      · simp [ih.mp h]
    · cases' init with hd' tl'
      · rintro rfl
        

Proof state:
case cons.mpr.nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
⊢ ([], hd :: tl) = ([], hd :: tl) ∨
    ∃ a b, (a, b) ∈ zip (inits tl) (tails tl) ∧ Prod.map (fun t => hd :: t) id (a, b) = ([], hd :: tl)

Next tactic:
simp
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · simp
      · simp [ih.mp h]
    · cases' init with hd' tl'
      · rintro rfl
        simp
      · 

Proof state:
case cons.mpr.cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
tail : List α
hd' : α
tl' : List α
⊢ hd' :: tl' ++ tail = hd :: tl →
    (hd' :: tl', tail) = ([], hd :: tl) ∨
      ∃ a b, (a, b) ∈ zip (inits tl) (tails tl) ∧ Prod.map (fun t => hd :: t) id (a, b) = (hd' :: tl', tail)

Next tactic:
intro h
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · simp
      · simp [ih.mp h]
    · cases' init with hd' tl'
      · rintro rfl
        simp
      · intro h
        

Proof state:
case cons.mpr.cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
tail : List α
hd' : α
tl' : List α
h : hd' :: tl' ++ tail = hd :: tl
⊢ (hd' :: tl', tail) = ([], hd :: tl) ∨
    ∃ a b, (a, b) ∈ zip (inits tl) (tails tl) ∧ Prod.map (fun t => hd :: t) id (a, b) = (hd' :: tl', tail)

Next tactic:
right
theorem mem_zip_inits_tails {l : List α} {init tail : List α} :
    (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by
  induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons]
  · simp
  · constructor <;> rw [mem_cons, zip_map_left, mem_map, Prod.exists]
    · rintro (⟨rfl, rfl⟩ | ⟨_, _, h, rfl, rfl⟩)
      · simp
      · simp [ih.mp h]
    · cases' init with hd' tl'
      · rintro rfl
        simp
      · intro h
        right
        

Proof state:
case cons.mpr.cons.h
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
hd : α
tl : List α
ih : ∀ {init tail : List α}, (init, tail) ∈ zip (inits tl) (tails tl) ↔ init ++ tail = tl
tail : List α
hd' : α
tl' : List α
h : hd' :: tl' ++ tail = hd :: tl
⊢ ∃ a b, (a, b) ∈ zip (inits tl) (tails tl) ∧ Prod.map (fun t => hd :: t) id (a, b) = (hd' :: tl', tail)

Next tactic:
use tl', tail