l3lab/ntp-mathlib huggingface dataset:
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; 

Proof state:
case left
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ head s₁ = head s₂
case right
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) (tail s₁) (tail s₂)

Next tactic:
exact h₁
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; 

Proof state:
case right
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) (tail s₁) (tail s₂)

Next tactic:
rw [← h₂, ← h₃]
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (

Proof state:
case right
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂

Next tactic:
repeat' constructor
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' 

Proof state:
case right
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂

Next tactic:
constructor
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' 

Proof state:
case right.left
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ head s₁ = head s₂

Next tactic:
constructor
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' 

Proof state:
case right.right
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ s₁ = tail s₁ ∧ s₂ = tail s₂

Next tactic:
constructor
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' 

Proof state:
case right.right.left
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ s₁ = tail s₁

Next tactic:
constructor
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' 

Proof state:
case right.right.right
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ s₂ = tail s₂

Next tactic:
constructor
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' constructor) <;> 

Proof state:
case right.left
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ head s₁ = head s₂

Next tactic:
assumption
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' constructor) <;> 

Proof state:
case right.right.left
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ s₁ = tail s₁

Next tactic:
assumption
theorem bisim_simple (s₁ s₂ : Stream' α) :
    head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ := fun hh ht₁ ht₂ =>
  eq_of_bisim (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
    (fun s₁ s₂ ⟨h₁, h₂, h₃⟩ => by
      constructor; exact h₁; rw [← h₂, ← h₃]
      (repeat' constructor) <;> 

Proof state:
case right.right.right
α : Type u
β : Type v
δ : Type w
s₁✝ s₂✝ : Stream' α
hh : head s₁✝ = head s₂✝
ht₁ : s₁✝ = tail s₁✝
ht₂ : s₂✝ = tail s₂✝
s₁ s₂ : Stream' α
x✝ : (fun s₁ s₂ => head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂) s₁ s₂
h₁ : head s₁ = head s₂
h₂ : s₁ = tail s₁
h₃ : s₂ = tail s₂
⊢ s₂ = tail s₂

Next tactic:
assumption
@[simp]
theorem iterate_id (a : α) : iterate id a = const a :=
  coinduction rfl fun β fr ch => by 

Proof state:
α : Type u
β✝ : Type v
δ : Type w
a : α
β : Type u
fr : Stream' α → β
ch : fr (iterate id a) = fr (const a)
⊢ fr (tail (iterate id a)) = fr (tail (const a))

Next tactic:
rw [tail_iterate, tail_const]
@[simp]
theorem iterate_id (a : α) : iterate id a = const a :=
  coinduction rfl fun β fr ch => by rw [tail_iterate, tail_const]; 

Proof state:
α : Type u
β✝ : Type v
δ : Type w
a : α
β : Type u
fr : Stream' α → β
ch : fr (iterate id a) = fr (const a)
⊢ fr (iterate id (id a)) = fr (const a)

Next tactic:
exact ch
theorem map_iterate (f : α → α) (a : α) : iterate f (f a) = map f (iterate f a) := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
f : α → α
a : α
⊢ iterate f (f a) = map f (iterate f a)

Next tactic:
funext n
theorem map_iterate (f : α → α) (a : α) : iterate f (f a) = map f (iterate f a) := by
  funext n
  

Proof state:
case h
α : Type u
β : Type v
δ : Type w
f : α → α
a : α
n : ℕ
⊢ iterate f (f a) n = map f (iterate f a) n

Next tactic:
induction' n with n' ih
theorem map_iterate (f : α → α) (a : α) : iterate f (f a) = map f (iterate f a) := by
  funext n
  induction' n with n' ih
  · 

Proof state:
case h.zero
α : Type u
β : Type v
δ : Type w
f : α → α
a : α
⊢ iterate f (f a) zero = map f (iterate f a) zero

Next tactic:
rfl
theorem map_iterate (f : α → α) (a : α) : iterate f (f a) = map f (iterate f a) := by
  funext n
  induction' n with n' ih
  · rfl
  · 

Proof state:
case h.succ
α : Type u
β : Type v
δ : Type w
f : α → α
a : α
n' : ℕ
ih : iterate f (f a) n' = map f (iterate f a) n'
⊢ iterate f (f a) (succ n') = map f (iterate f a) (succ n')

Next tactic:
unfold map iterate get
theorem map_iterate (f : α → α) (a : α) : iterate f (f a) = map f (iterate f a) := by
  funext n
  induction' n with n' ih
  · rfl
  · unfold map iterate get
    

Proof state:
case h.succ
α : Type u
β : Type v
δ : Type w
f : α → α
a : α
n' : ℕ
ih : iterate f (f a) n' = map f (iterate f a) n'
⊢ f (iterate f (f a) n') = f (iterate f a (succ n'))

Next tactic:
rw [map, get] at ih
theorem map_iterate (f : α → α) (a : α) : iterate f (f a) = map f (iterate f a) := by
  funext n
  induction' n with n' ih
  · rfl
  · unfold map iterate get
    rw [map, get] at ih
    

Proof state:
case h.succ
α : Type u
β : Type v
δ : Type w
f : α → α
a : α
n' : ℕ
ih : iterate f (f a) n' = f (iterate f a n')
⊢ f (iterate f (f a) n') = f (iterate f a (succ n'))

Next tactic:
rw [iterate]
theorem map_iterate (f : α → α) (a : α) : iterate f (f a) = map f (iterate f a) := by
  funext n
  induction' n with n' ih
  · rfl
  · unfold map iterate get
    rw [map, get] at ih
    rw [iterate]
    

Proof state:
case h.succ
α : Type u
β : Type v
δ : Type w
f : α → α
a : α
n' : ℕ
ih : iterate f (f a) n' = f (iterate f a n')
⊢ f (iterate f (f a) n') = f (f (iterate f a n'))

Next tactic:
exact congrArg f ih
theorem corec_eq (f : α → β) (g : α → α) (a : α) : corec f g a = f a::corec f g (g a) := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
f : α → β
g : α → α
a : α
⊢ corec f g a = f a :: corec f g (g a)

Next tactic:
rw [corec_def, map_eq, head_iterate, tail_iterate]
theorem corec_eq (f : α → β) (g : α → α) (a : α) : corec f g a = f a::corec f g (g a) := by
  rw [corec_def, map_eq, head_iterate, tail_iterate]; 

Proof state:
α : Type u
β : Type v
δ : Type w
f : α → β
g : α → α
a : α
⊢ f a :: map f (iterate g (g a)) = f a :: corec f g (g a)

Next tactic:
rfl
theorem corec_id_id_eq_const (a : α) : corec id id a = const a := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
a : α
⊢ corec id id a = const a

Next tactic:
rw [corec_def, map_id, iterate_id]
theorem unfolds_eq (g : α → β) (f : α → α) (a : α) : unfolds g f a = g a::unfolds g f (f a) := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
g : α → β
f : α → α
a : α
⊢ unfolds g f a = g a :: unfolds g f (f a)

Next tactic:
unfold unfolds
theorem unfolds_eq (g : α → β) (f : α → α) (a : α) : unfolds g f a = g a::unfolds g f (f a) := by
  unfold unfolds; 

Proof state:
α : Type u
β : Type v
δ : Type w
g : α → β
f : α → α
a : α
⊢ corec g f a = g a :: corec g f (f a)

Next tactic:
rw [corec_eq]
theorem get_unfolds_head_tail : ∀ (n : Nat) (s : Stream' α),
    get (unfolds head tail s) n = get s n := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
⊢ ∀ (n : ℕ) (s : Stream' α), get (unfolds head tail s) n = get s n

Next tactic:
intro n
theorem get_unfolds_head_tail : ∀ (n : Nat) (s : Stream' α),
    get (unfolds head tail s) n = get s n := by
  intro n; 

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
⊢ ∀ (s : Stream' α), get (unfolds head tail s) n = get s n

Next tactic:
induction' n with n' ih
theorem get_unfolds_head_tail : ∀ (n : Nat) (s : Stream' α),
    get (unfolds head tail s) n = get s n := by
  intro n; induction' n with n' ih
  · 

Proof state:
case zero
α : Type u
β : Type v
δ : Type w
⊢ ∀ (s : Stream' α), get (unfolds head tail s) zero = get s zero

Next tactic:
intro s
theorem get_unfolds_head_tail : ∀ (n : Nat) (s : Stream' α),
    get (unfolds head tail s) n = get s n := by
  intro n; induction' n with n' ih
  · intro s
    

Proof state:
case zero
α : Type u
β : Type v
δ : Type w
s : Stream' α
⊢ get (unfolds head tail s) zero = get s zero

Next tactic:
rfl
theorem get_unfolds_head_tail : ∀ (n : Nat) (s : Stream' α),
    get (unfolds head tail s) n = get s n := by
  intro n; induction' n with n' ih
  · intro s
    rfl
  · 

Proof state:
case succ
α : Type u
β : Type v
δ : Type w
n' : ℕ
ih : ∀ (s : Stream' α), get (unfolds head tail s) n' = get s n'
⊢ ∀ (s : Stream' α), get (unfolds head tail s) (succ n') = get s (succ n')

Next tactic:
intro s
theorem get_unfolds_head_tail : ∀ (n : Nat) (s : Stream' α),
    get (unfolds head tail s) n = get s n := by
  intro n; induction' n with n' ih
  · intro s
    rfl
  · intro s
    

Proof state:
case succ
α : Type u
β : Type v
δ : Type w
n' : ℕ
ih : ∀ (s : Stream' α), get (unfolds head tail s) n' = get s n'
s : Stream' α
⊢ get (unfolds head tail s) (succ n') = get s (succ n')

Next tactic:
rw [get_succ, get_succ, unfolds_eq, tail_cons, ih]
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
⊢ s₁ ⋈ s₂ = head s₁ :: head s₂ :: (tail s₁ ⋈ tail s₂)

Next tactic:
let t := tail s₁ ⋈ tail s₂
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  let t := tail s₁ ⋈ tail s₂
  

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
t : Stream' α := tail s₁ ⋈ tail s₂
⊢ s₁ ⋈ s₂ = head s₁ :: head s₂ :: (tail s₁ ⋈ tail s₂)

Next tactic:
show s₁ ⋈ s₂ = head s₁::head s₂::t
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  let t := tail s₁ ⋈ tail s₂
  show s₁ ⋈ s₂ = head s₁::head s₂::t
  

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
t : Stream' α := tail s₁ ⋈ tail s₂
⊢ s₁ ⋈ s₂ = head s₁ :: head s₂ :: t

Next tactic:
unfold interleave
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  let t := tail s₁ ⋈ tail s₂
  show s₁ ⋈ s₂ = head s₁::head s₂::t
  unfold interleave; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
t : Stream' α := tail s₁ ⋈ tail s₂
⊢ (corecOn (s₁, s₂)
      (fun x =>
        match x with
        | (s₁, snd) => head s₁)
      fun x =>
      match x with
      | (s₁, s₂) => (s₂, tail s₁)) =
    head s₁ :: head s₂ :: t

Next tactic:
unfold corecOn
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  let t := tail s₁ ⋈ tail s₂
  show s₁ ⋈ s₂ = head s₁::head s₂::t
  unfold interleave; unfold corecOn; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
t : Stream' α := tail s₁ ⋈ tail s₂
⊢ corec
      (fun x =>
        match x with
        | (s₁, snd) => head s₁)
      (fun x =>
        match x with
        | (s₁, s₂) => (s₂, tail s₁))
      (s₁, s₂) =
    head s₁ :: head s₂ :: t

Next tactic:
rw [corec_eq]
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  let t := tail s₁ ⋈ tail s₂
  show s₁ ⋈ s₂ = head s₁::head s₂::t
  unfold interleave; unfold corecOn; rw [corec_eq]; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
t : Stream' α := tail s₁ ⋈ tail s₂
⊢ (match (s₁, s₂) with
      | (s₁, snd) => head s₁) ::
      corec
        (fun x =>
          match x with
          | (s₁, snd) => head s₁)
        (fun x =>
          match x with
          | (s₁, s₂) => (s₂, tail s₁))
        (match (s₁, s₂) with
        | (s₁, s₂) => (s₂, tail s₁)) =
    head s₁ :: head s₂ :: t

Next tactic:
dsimp
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  let t := tail s₁ ⋈ tail s₂
  show s₁ ⋈ s₂ = head s₁::head s₂::t
  unfold interleave; unfold corecOn; rw [corec_eq]; dsimp; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
t : Stream' α := tail s₁ ⋈ tail s₂
⊢ head s₁ :: corec (fun x => head x.1) (fun x => (x.2, tail x.1)) (s₂, tail s₁) =
    head s₁ :: head s₂ :: (tail s₁ ⋈ tail s₂)

Next tactic:
rw [corec_eq]
theorem interleave_eq (s₁ s₂ : Stream' α) : s₁ ⋈ s₂ = head s₁::head s₂::(tail s₁ ⋈ tail s₂) := by
  let t := tail s₁ ⋈ tail s₂
  show s₁ ⋈ s₂ = head s₁::head s₂::t
  unfold interleave; unfold corecOn; rw [corec_eq]; dsimp; rw [corec_eq]; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
t : Stream' α := tail s₁ ⋈ tail s₂
⊢ head s₁ ::
      head (s₂, tail s₁).1 ::
        corec (fun x => head x.1) (fun x => (x.2, tail x.1)) ((s₂, tail s₁).2, tail (s₂, tail s₁).1) =
    head s₁ :: head s₂ :: (tail s₁ ⋈ tail s₂)

Next tactic:
rfl
theorem tail_interleave (s₁ s₂ : Stream' α) : tail (s₁ ⋈ s₂) = s₂ ⋈ tail s₁ := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
⊢ tail (s₁ ⋈ s₂) = s₂ ⋈ tail s₁

Next tactic:
unfold interleave corecOn
theorem tail_interleave (s₁ s₂ : Stream' α) : tail (s₁ ⋈ s₂) = s₂ ⋈ tail s₁ := by
  unfold interleave corecOn; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
⊢ tail
      (corec
        (fun x =>
          match x with
          | (s₁, snd) => head s₁)
        (fun x =>
          match x with
          | (s₁, s₂) => (s₂, tail s₁))
        (s₁, s₂)) =
    corec
      (fun x =>
        match x with
        | (s₁, snd) => head s₁)
      (fun x =>
        match x with
        | (s₁, s₂) => (s₂, tail s₁))
      (s₂, tail s₁)

Next tactic:
rw [corec_eq]
theorem tail_interleave (s₁ s₂ : Stream' α) : tail (s₁ ⋈ s₂) = s₂ ⋈ tail s₁ := by
  unfold interleave corecOn; rw [corec_eq]; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
⊢ tail
      ((match (s₁, s₂) with
        | (s₁, snd) => head s₁) ::
        corec
          (fun x =>
            match x with
            | (s₁, snd) => head s₁)
          (fun x =>
            match x with
            | (s₁, s₂) => (s₂, tail s₁))
          (match (s₁, s₂) with
          | (s₁, s₂) => (s₂, tail s₁))) =
    corec
      (fun x =>
        match x with
        | (s₁, snd) => head s₁)
      (fun x =>
        match x with
        | (s₁, s₂) => (s₂, tail s₁))
      (s₂, tail s₁)

Next tactic:
rfl
theorem interleave_tail_tail (s₁ s₂ : Stream' α) : tail s₁ ⋈ tail s₂ = tail (tail (s₁ ⋈ s₂)) := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
⊢ tail s₁ ⋈ tail s₂ = tail (tail (s₁ ⋈ s₂))

Next tactic:
rw [interleave_eq s₁ s₂]
theorem interleave_tail_tail (s₁ s₂ : Stream' α) : tail s₁ ⋈ tail s₂ = tail (tail (s₁ ⋈ s₂)) := by
  rw [interleave_eq s₁ s₂]; 

Proof state:
α : Type u
β : Type v
δ : Type w
s₁ s₂ : Stream' α
⊢ tail s₁ ⋈ tail s₂ = tail (tail (head s₁ :: head s₂ :: (tail s₁ ⋈ tail s₂)))

Next tactic:
rfl
theorem get_interleave_left : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n) = get s₁ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
⊢ get (s₁ ⋈ s₂) (2 * (n + 1)) = get s₁ (n + 1)

Next tactic:
change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n)
theorem get_interleave_left : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n) = get s₁ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n)
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
⊢ get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n)

Next tactic:
rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons]
theorem get_interleave_left : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n) = get s₁ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n)
    rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons]
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
⊢ get (tail s₁ ⋈ tail s₂) (2 * n) = get s₁ (succ n)

Next tactic:
have : n < succ n := Nat.lt_succ_self n
theorem get_interleave_left : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n) = get s₁ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n)
    rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons]
    have : n < succ n := Nat.lt_succ_self n
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
this : n < succ n
⊢ get (tail s₁ ⋈ tail s₂) (2 * n) = get s₁ (succ n)

Next tactic:
rw [get_interleave_left n (tail s₁) (tail s₂)]
theorem get_interleave_left : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n) = get s₁ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    change get (s₁ ⋈ s₂) (succ (succ (2 * n))) = get s₁ (succ n)
    rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons]
    have : n < succ n := Nat.lt_succ_self n
    rw [get_interleave_left n (tail s₁) (tail s₂)]
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
this : n < succ n
⊢ get (tail s₁) n = get s₁ (succ n)

Next tactic:
rfl
theorem get_interleave_right : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n + 1) = get s₂ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
⊢ get (s₁ ⋈ s₂) (2 * (n + 1) + 1) = get s₂ (n + 1)

Next tactic:
change get (s₁ ⋈ s₂) (succ (succ (2 * n + 1))) = get s₂ (succ n)
theorem get_interleave_right : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n + 1) = get s₂ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    change get (s₁ ⋈ s₂) (succ (succ (2 * n + 1))) = get s₂ (succ n)
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
⊢ get (s₁ ⋈ s₂) (succ (succ (2 * n + 1))) = get s₂ (succ n)

Next tactic:
rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons,
      get_interleave_right n (tail s₁) (tail s₂)]
theorem get_interleave_right : ∀ (n : Nat) (s₁ s₂ : Stream' α),
    get (s₁ ⋈ s₂) (2 * n + 1) = get s₂ n
  | 0, s₁, s₂ => rfl
  | n + 1, s₁, s₂ => by
    change get (s₁ ⋈ s₂) (succ (succ (2 * n + 1))) = get s₂ (succ n)
    rw [get_succ, get_succ, interleave_eq, tail_cons, tail_cons,
      get_interleave_right n (tail s₁) (tail s₂)]
    

Proof state:
α : Type u
β : Type v
δ : Type w
n : ℕ
s₁ s₂ : Stream' α
⊢ get (tail s₂) n = get s₂ (succ n)

Next tactic:
rfl
theorem mem_interleave_left {a : α} {s₁ : Stream' α} (s₂ : Stream' α) : a ∈ s₁ → a ∈ s₁ ⋈ s₂ :=
  fun ⟨n, h⟩ => Exists.intro (2 * n) (by 

Proof state:
α : Type u
β : Type v
δ : Type w
a : α
s₁ s₂ : Stream' α
x✝ : a ∈ s₁
n : ℕ
h : (fun b => a = b) (get s₁ n)
⊢ (fun b => a = b) (get (s₁ ⋈ s₂) (2 * n))

Next tactic:
rw [h, get_interleave_left]
theorem mem_interleave_right {a : α} {s₁ : Stream' α} (s₂ : Stream' α) : a ∈ s₂ → a ∈ s₁ ⋈ s₂ :=
  fun ⟨n, h⟩ => Exists.intro (2 * n + 1) (by 

Proof state:
α : Type u
β : Type v
δ : Type w
a : α
s₁ s₂ : Stream' α
x✝ : a ∈ s₂
n : ℕ
h : (fun b => a = b) (get s₂ n)
⊢ (fun b => a = b) (get (s₁ ⋈ s₂) (2 * n + 1))

Next tactic:
rw [h, get_interleave_right]
theorem tail_even (s : Stream' α) : tail (even s) = even (tail (tail s)) := by
  

Proof state:
α : Type u
β : Type v
δ : Type w
s : Stream' α
⊢ tail (even s) = even (tail (tail s))

Next tactic:
unfold even
theorem tail_even (s : Stream' α) : tail (even s) = even (tail (tail s)) := by
  unfold even
  

Proof state:
α : Type u
β : Type v
δ : Type w
s : Stream' α
⊢ tail (corec (fun s => head s) (fun s => tail (tail s)) s) =
    corec (fun s => head s) (fun s => tail (tail s)) (tail (tail s))

Next tactic:
rw [corec_eq]