l3lab/ntp-mathlib huggingface dataset:
theorem eq_of_bisim [Nonempty (M F)] (bisim : IsBisimulation R) : ∀ s₁ s₂, R s₁ s₂ → s₁ = s₂ := by
  inhabit M F
  introv Hr; apply ext
  introv
  by_cases h : IsPath ps s₁ ∨ IsPath ps s₂
  · have H := nth_of_bisim R bisim _ _ ps Hr h
    

Proof state:
case pos
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
R : M F → M F → Prop
inst✝ : Nonempty (M F)
bisim : IsBisimulation R
inhabited_h : Inhabited (M F)
s₁ s₂ : M F
Hr : R s₁ s₂
ps : Path F
h : IsPath ps s₁ ∨ IsPath ps s₂
H :
  iselect ps s₁ = iselect ps s₂ ∧
    ∃ a f f',
      isubtree ps s₁ = M.mk { fst := a, snd := f } ∧
        isubtree ps s₂ = M.mk { fst := a, snd := f' } ∧ ∀ (i : B F a), R (f i) (f' i)
⊢ iselect ps s₁ = iselect ps s₂

Next tactic:
exact H.left
theorem eq_of_bisim [Nonempty (M F)] (bisim : IsBisimulation R) : ∀ s₁ s₂, R s₁ s₂ → s₁ = s₂ := by
  inhabit M F
  introv Hr; apply ext
  introv
  by_cases h : IsPath ps s₁ ∨ IsPath ps s₂
  · have H := nth_of_bisim R bisim _ _ ps Hr h
    exact H.left
  · 

Proof state:
case neg
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
R : M F → M F → Prop
inst✝ : Nonempty (M F)
bisim : IsBisimulation R
inhabited_h : Inhabited (M F)
s₁ s₂ : M F
Hr : R s₁ s₂
ps : Path F
h : ¬(IsPath ps s₁ ∨ IsPath ps s₂)
⊢ iselect ps s₁ = iselect ps s₂

Next tactic:
rw [not_or] at h
theorem eq_of_bisim [Nonempty (M F)] (bisim : IsBisimulation R) : ∀ s₁ s₂, R s₁ s₂ → s₁ = s₂ := by
  inhabit M F
  introv Hr; apply ext
  introv
  by_cases h : IsPath ps s₁ ∨ IsPath ps s₂
  · have H := nth_of_bisim R bisim _ _ ps Hr h
    exact H.left
  · rw [not_or] at h
    

Proof state:
case neg
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
R : M F → M F → Prop
inst✝ : Nonempty (M F)
bisim : IsBisimulation R
inhabited_h : Inhabited (M F)
s₁ s₂ : M F
Hr : R s₁ s₂
ps : Path F
h : ¬IsPath ps s₁ ∧ ¬IsPath ps s₂
⊢ iselect ps s₁ = iselect ps s₂

Next tactic:
cases' h with h₀ h₁
theorem eq_of_bisim [Nonempty (M F)] (bisim : IsBisimulation R) : ∀ s₁ s₂, R s₁ s₂ → s₁ = s₂ := by
  inhabit M F
  introv Hr; apply ext
  introv
  by_cases h : IsPath ps s₁ ∨ IsPath ps s₂
  · have H := nth_of_bisim R bisim _ _ ps Hr h
    exact H.left
  · rw [not_or] at h
    cases' h with h₀ h₁
    

Proof state:
case neg.intro
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
R : M F → M F → Prop
inst✝ : Nonempty (M F)
bisim : IsBisimulation R
inhabited_h : Inhabited (M F)
s₁ s₂ : M F
Hr : R s₁ s₂
ps : Path F
h₀ : ¬IsPath ps s₁
h₁ : ¬IsPath ps s₂
⊢ iselect ps s₁ = iselect ps s₂

Next tactic:
simp only [iselect_eq_default, *, not_false_iff]
theorem dest_corec (g : α → P α) (x : α) : M.dest (M.corec g x) = P.map (M.corec g) (g x) := by
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
x : α
⊢ dest (M.corec g x) = map P (M.corec g) (g x)

Next tactic:
rw [corec_def, dest_mk]
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
⊢ ∀ (x y : M P), R x y → x = y

Next tactic:
introv h'
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
x y : M P
h' : R x y
⊢ x = y

Next tactic:
haveI := Inhabited.mk x.head
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
x y : M P
h' : R x y
this : Inhabited P.A
⊢ x = y

Next tactic:
apply eq_of_bisim R _ _ _ h'
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; 

Proof state:
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
x y : M P
h' : R x y
this : Inhabited P.A
⊢ IsBisimulation R

Next tactic:
clear h' x y
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
this : Inhabited P.A
⊢ IsBisimulation R

Next tactic:
constructor
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> 

Proof state:
case head
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
this : Inhabited P.A
⊢ ∀ {a a' : P.A} {f : B P a → M P} {f' : B P a' → M P},
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a', snd := f' }) → a = a'

Next tactic:
introv ih
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> 

Proof state:
case tail
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
this : Inhabited P.A
⊢ ∀ {a : P.A} {f f' : B P a → M P},
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) → ∀ (i : B P a), R (f i) (f' i)

Next tactic:
introv ih
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> 

Proof state:
case head
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
this : Inhabited P.A
a a' : P.A
f : B P a → M P
f' : B P a' → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a', snd := f' })
⊢ a = a'

Next tactic:
rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> 

Proof state:
case tail
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
this : Inhabited P.A
a : P.A
f f' : B P a → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B P a
⊢ R (f i) (f' i)

Next tactic:
rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> 

Proof state:
case head.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
this : Inhabited P.A
a a' : P.A
f : B P a → M P
f' : B P a' → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a', snd := f' })
a'' : P.A
g g' : B P a'' → M P
h₀ : dest (M.mk { fst := a, snd := f }) = { fst := a'', snd := g }
h₁ : dest (M.mk { fst := a', snd := f' }) = { fst := a'', snd := g' }
h₂ : ∀ (i : B P a''), R (g i) (g' i)
⊢ a = a'

Next tactic:
clear h
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> 

Proof state:
case tail.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
h :
  ∀ (x y : M P),
    R x y → ∃ a f f', dest x = { fst := a, snd := f } ∧ dest y = { fst := a, snd := f' } ∧ ∀ (i : B P a), R (f i) (f' i)
this : Inhabited P.A
a : P.A
f f' : B P a → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B P a
a'' : P.A
g g' : B P a'' → M P
h₀ : dest (M.mk { fst := a, snd := f }) = { fst := a'', snd := g }
h₁ : dest (M.mk { fst := a, snd := f' }) = { fst := a'', snd := g' }
h₂ : ∀ (i : B P a''), R (g i) (g' i)
⊢ R (f i) (f' i)

Next tactic:
clear h
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · 

Proof state:
case head.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a a' : P.A
f : B P a → M P
f' : B P a' → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a', snd := f' })
a'' : P.A
g g' : B P a'' → M P
h₀ : dest (M.mk { fst := a, snd := f }) = { fst := a'', snd := g }
h₁ : dest (M.mk { fst := a', snd := f' }) = { fst := a'', snd := g' }
h₂ : ∀ (i : B P a''), R (g i) (g' i)
⊢ a = a'

Next tactic:
replace h₀ := congr_arg Sigma.fst h₀
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · replace h₀ := congr_arg Sigma.fst h₀
    

Proof state:
case head.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a a' : P.A
f : B P a → M P
f' : B P a' → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a', snd := f' })
a'' : P.A
g g' : B P a'' → M P
h₁ : dest (M.mk { fst := a', snd := f' }) = { fst := a'', snd := g' }
h₂ : ∀ (i : B P a''), R (g i) (g' i)
h₀ : (dest (M.mk { fst := a, snd := f })).fst = { fst := a'', snd := g }.fst
⊢ a = a'

Next tactic:
replace h₁ := congr_arg Sigma.fst h₁
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · replace h₀ := congr_arg Sigma.fst h₀
    replace h₁ := congr_arg Sigma.fst h₁
    

Proof state:
case head.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a a' : P.A
f : B P a → M P
f' : B P a' → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a', snd := f' })
a'' : P.A
g g' : B P a'' → M P
h₂ : ∀ (i : B P a''), R (g i) (g' i)
h₀ : (dest (M.mk { fst := a, snd := f })).fst = { fst := a'', snd := g }.fst
h₁ : (dest (M.mk { fst := a', snd := f' })).fst = { fst := a'', snd := g' }.fst
⊢ a = a'

Next tactic:
simp only [dest_mk] at h₀ h₁
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · replace h₀ := congr_arg Sigma.fst h₀
    replace h₁ := congr_arg Sigma.fst h₁
    simp only [dest_mk] at h₀ h₁
    

Proof state:
case head.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a a' : P.A
f : B P a → M P
f' : B P a' → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a', snd := f' })
a'' : P.A
g g' : B P a'' → M P
h₂ : ∀ (i : B P a''), R (g i) (g' i)
h₀ : a = a''
h₁ : a' = a''
⊢ a = a'

Next tactic:
rw [h₀, h₁]
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · replace h₀ := congr_arg Sigma.fst h₀
    replace h₁ := congr_arg Sigma.fst h₁
    simp only [dest_mk] at h₀ h₁
    rw [h₀, h₁]
  · 

Proof state:
case tail.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a : P.A
f f' : B P a → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B P a
a'' : P.A
g g' : B P a'' → M P
h₀ : dest (M.mk { fst := a, snd := f }) = { fst := a'', snd := g }
h₁ : dest (M.mk { fst := a, snd := f' }) = { fst := a'', snd := g' }
h₂ : ∀ (i : B P a''), R (g i) (g' i)
⊢ R (f i) (f' i)

Next tactic:
simp only [dest_mk] at h₀ h₁
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · replace h₀ := congr_arg Sigma.fst h₀
    replace h₁ := congr_arg Sigma.fst h₁
    simp only [dest_mk] at h₀ h₁
    rw [h₀, h₁]
  · simp only [dest_mk] at h₀ h₁
    

Proof state:
case tail.intro.intro.intro.intro.intro
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a : P.A
f f' : B P a → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B P a
a'' : P.A
g g' : B P a'' → M P
h₀ : { fst := a, snd := f } = { fst := a'', snd := g }
h₁ : { fst := a, snd := f' } = { fst := a'', snd := g' }
h₂ : ∀ (i : B P a''), R (g i) (g' i)
⊢ R (f i) (f' i)

Next tactic:
cases h₀
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · replace h₀ := congr_arg Sigma.fst h₀
    replace h₁ := congr_arg Sigma.fst h₁
    simp only [dest_mk] at h₀ h₁
    rw [h₀, h₁]
  · simp only [dest_mk] at h₀ h₁
    cases h₀
    

Proof state:
case tail.intro.intro.intro.intro.intro.refl
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a : P.A
f f' : B P a → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B P a
g' : B P a → M P
h₁ : { fst := a, snd := f' } = { fst := a, snd := g' }
h₂ : ∀ (i : B P a), R (f i) (g' i)
⊢ R (f i) (f' i)

Next tactic:
cases h₁
theorem bisim (R : M P → M P → Prop)
    (h : ∀ x y, R x y → ∃ a f f', M.dest x = ⟨a, f⟩ ∧ M.dest y = ⟨a, f'⟩ ∧ ∀ i, R (f i) (f' i)) :
    ∀ x y, R x y → x = y := by
  introv h'
  haveI := Inhabited.mk x.head
  apply eq_of_bisim R _ _ _ h'; clear h' x y
  constructor <;> introv ih <;> rcases h _ _ ih with ⟨a'', g, g', h₀, h₁, h₂⟩ <;> clear h
  · replace h₀ := congr_arg Sigma.fst h₀
    replace h₁ := congr_arg Sigma.fst h₁
    simp only [dest_mk] at h₀ h₁
    rw [h₀, h₁]
  · simp only [dest_mk] at h₀ h₁
    cases h₀
    cases h₁
    

Proof state:
case tail.intro.intro.intro.intro.intro.refl.refl
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
R : M P → M P → Prop
this : Inhabited P.A
a : P.A
f f' : B P a → M P
ih : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B P a
h₂ : ∀ (i : B P a), R (f i) (f' i)
⊢ R (f i) (f' i)

Next tactic:
apply h₂
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
⊢ f = M.corec g

Next tactic:
ext x
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  

Proof state:
case h
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
x : α
⊢ f x = M.corec g x

Next tactic:
apply bisim' (fun _ => True) _ _ _ _ trivial
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  apply bisim' (fun _ => True) _ _ _ _ trivial
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
x : α
⊢ ∀ (x : α),
    (fun x => True) x →
      ∃ a f_1 f',
        dest (f x) = { fst := a, snd := f_1 } ∧
          dest (M.corec g x) = { fst := a, snd := f' } ∧
            ∀ (i : B P a), ∃ x', (fun x => True) x' ∧ f_1 i = f x' ∧ f' i = M.corec g x'

Next tactic:
clear x
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  apply bisim' (fun _ => True) _ _ _ _ trivial
  clear x
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
⊢ ∀ (x : α),
    (fun x => True) x →
      ∃ a f_1 f',
        dest (f x) = { fst := a, snd := f_1 } ∧
          dest (M.corec g x) = { fst := a, snd := f' } ∧
            ∀ (i : B P a), ∃ x', (fun x => True) x' ∧ f_1 i = f x' ∧ f' i = M.corec g x'

Next tactic:
intro x _
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  apply bisim' (fun _ => True) _ _ _ _ trivial
  clear x
  intro x _
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
x : α
a✝ : True
⊢ ∃ a f_1 f',
    dest (f x) = { fst := a, snd := f_1 } ∧
      dest (M.corec g x) = { fst := a, snd := f' } ∧
        ∀ (i : B P a), ∃ x', (fun x => True) x' ∧ f_1 i = f x' ∧ f' i = M.corec g x'

Next tactic:
cases' gxeq : g x with a f'
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  apply bisim' (fun _ => True) _ _ _ _ trivial
  clear x
  intro x _
  cases' gxeq : g x with a f'
  

Proof state:
case mk
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
x : α
a✝ : True
a : P.A
f' : B P a → α
gxeq : g x = { fst := a, snd := f' }
⊢ ∃ a f_1 f',
    dest (f x) = { fst := a, snd := f_1 } ∧
      dest (M.corec g x) = { fst := a, snd := f' } ∧
        ∀ (i : B P a), ∃ x', (fun x => True) x' ∧ f_1 i = f x' ∧ f' i = M.corec g x'

Next tactic:
have h₀ : M.dest (f x) = ⟨a, f ∘ f'⟩ := by rw [hyp, gxeq, PFunctor.map_eq]
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  apply bisim' (fun _ => True) _ _ _ _ trivial
  clear x
  intro x _
  cases' gxeq : g x with a f'
  have h₀ : M.dest (f x) = ⟨a, f ∘ f'⟩ := by 

Proof state:
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
x : α
a✝ : True
a : P.A
f' : B P a → α
gxeq : g x = { fst := a, snd := f' }
⊢ dest (f x) = { fst := a, snd := f ∘ f' }

Next tactic:
rw [hyp, gxeq, PFunctor.map_eq]
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  apply bisim' (fun _ => True) _ _ _ _ trivial
  clear x
  intro x _
  cases' gxeq : g x with a f'
  have h₀ : M.dest (f x) = ⟨a, f ∘ f'⟩ := by rw [hyp, gxeq, PFunctor.map_eq]
  

Proof state:
case mk
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
x : α
a✝ : True
a : P.A
f' : B P a → α
gxeq : g x = { fst := a, snd := f' }
h₀ : dest (f x) = { fst := a, snd := f ∘ f' }
⊢ ∃ a f_1 f',
    dest (f x) = { fst := a, snd := f_1 } ∧
      dest (M.corec g x) = { fst := a, snd := f' } ∧
        ∀ (i : B P a), ∃ x', (fun x => True) x' ∧ f_1 i = f x' ∧ f' i = M.corec g x'

Next tactic:
have h₁ : M.dest (M.corec g x) = ⟨a, M.corec g ∘ f'⟩ := by rw [dest_corec, gxeq, PFunctor.map_eq]
theorem corec_unique (g : α → P α) (f : α → M P) (hyp : ∀ x, M.dest (f x) = P.map f (g x)) :
    f = M.corec g := by
  ext x
  apply bisim' (fun _ => True) _ _ _ _ trivial
  clear x
  intro x _
  cases' gxeq : g x with a f'
  have h₀ : M.dest (f x) = ⟨a, f ∘ f'⟩ := by rw [hyp, gxeq, PFunctor.map_eq]
  have h₁ : M.dest (M.corec g x) = ⟨a, M.corec g ∘ f'⟩ := by 

Proof state:
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
P : PFunctor.{u}
α : Type u_2
g : α → ↑P α
f : α → M P
hyp : ∀ (x : α), dest (f x) = map P f (g x)
x : α
a✝ : True
a : P.A
f' : B P a → α
gxeq : g x = { fst := a, snd := f' }
h₀ : dest (f x) = { fst := a, snd := f ∘ f' }
⊢ dest (M.corec g x) = { fst := a, snd := M.corec g ∘ f' }

Next tactic:
rw [dest_corec, gxeq, PFunctor.map_eq]