l3lab/ntp-mathlib huggingface dataset:
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  

Proof state:
case f.f.cons.mk
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
⊢ head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f })) =
      head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })) ∧
    ∃ a_1 f_1 f'_1,
      isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
        isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
          ∀ (i : B F a_1), R (f_1 i) (f'_1 i)

Next tactic:
have h₁ := bisim.tail h₀ i
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  

Proof state:
case f.f.cons.mk
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
h₁ : R (f i) (f' i)
⊢ head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f })) =
      head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })) ∧
    ∃ a_1 f_1 f'_1,
      isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
        isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
          ∀ (i : B F a_1), R (f_1 i) (f'_1 i)

Next tactic:
induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
  

Proof state:
case f.f.cons.mk.f
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
h₁ : R (f i) (f' i)
a₀ : F.A
f₀ : B F a₀ → M F
h : f i = M.mk { fst := a₀, snd := f₀ }
⊢ head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f })) =
      head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })) ∧
    ∃ a_1 f_1 f'_1,
      isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
        isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
          ∀ (i : B F a_1), R (f_1 i) (f'_1 i)

Next tactic:
induction' h' : f' i using PFunctor.M.casesOn' with a₁ f₁
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
  induction' h' : f' i using PFunctor.M.casesOn' with a₁ f₁
  

Proof state:
case f.f.cons.mk.f.f
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
h₁ : R (f i) (f' i)
a₀ : F.A
f₀ : B F a₀ → M F
h : f i = M.mk { fst := a₀, snd := f₀ }
a₁ : F.A
f₁ : B F a₁ → M F
h' : f' i = M.mk { fst := a₁, snd := f₁ }
⊢ head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f })) =
      head (isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })) ∧
    ∃ a_1 f_1 f'_1,
      isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
        isubtree ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
          ∀ (i : B F a_1), R (f_1 i) (f'_1 i)

Next tactic:
simp only [h, h', isubtree_cons] at ps_ih ⊢
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
  induction' h' : f' i using PFunctor.M.casesOn' with a₁ f₁
  simp only [h, h', isubtree_cons] at ps_ih ⊢
  

Proof state:
case f.f.cons.mk.f.f
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
h₁ : R (f i) (f' i)
a₀ : F.A
f₀ : B F a₀ → M F
h : f i = M.mk { fst := a₀, snd := f₀ }
a₁ : F.A
f₁ : B F a₁ → M F
h' : f' i = M.mk { fst := a₁, snd := f₁ }
⊢ head (isubtree ps (M.mk { fst := a₀, snd := f₀ })) = head (isubtree ps (M.mk { fst := a₁, snd := f₁ })) ∧
    ∃ a f f',
      isubtree ps (M.mk { fst := a₀, snd := f₀ }) = M.mk { fst := a, snd := f } ∧
        isubtree ps (M.mk { fst := a₁, snd := f₁ }) = M.mk { fst := a, snd := f' } ∧ ∀ (i : B F a), R (f i) (f' i)

Next tactic:
rw [h, h'] at h₁
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
  induction' h' : f' i using PFunctor.M.casesOn' with a₁ f₁
  simp only [h, h', isubtree_cons] at ps_ih ⊢
  rw [h, h'] at h₁
  

Proof state:
case f.f.cons.mk.f.f
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
a₀ : F.A
f₀ : B F a₀ → M F
h : f i = M.mk { fst := a₀, snd := f₀ }
a₁ : F.A
f₁ : B F a₁ → M F
h₁ : R (M.mk { fst := a₀, snd := f₀ }) (M.mk { fst := a₁, snd := f₁ })
h' : f' i = M.mk { fst := a₁, snd := f₁ }
⊢ head (isubtree ps (M.mk { fst := a₀, snd := f₀ })) = head (isubtree ps (M.mk { fst := a₁, snd := f₁ })) ∧
    ∃ a f f',
      isubtree ps (M.mk { fst := a₀, snd := f₀ }) = M.mk { fst := a, snd := f } ∧
        isubtree ps (M.mk { fst := a₁, snd := f₁ }) = M.mk { fst := a, snd := f' } ∧ ∀ (i : B F a), R (f i) (f' i)

Next tactic:
obtain rfl : a₀ = a₁ := bisim.head h₁
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
  induction' h' : f' i using PFunctor.M.casesOn' with a₁ f₁
  simp only [h, h', isubtree_cons] at ps_ih ⊢
  rw [h, h'] at h₁
  obtain rfl : a₀ = a₁ := bisim.head h₁
  

Proof state:
case f.f.cons.mk.f.f
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
a₀ : F.A
f₀ : B F a₀ → M F
h : f i = M.mk { fst := a₀, snd := f₀ }
f₁ : B F a₀ → M F
h₁ : R (M.mk { fst := a₀, snd := f₀ }) (M.mk { fst := a₀, snd := f₁ })
h' : f' i = M.mk { fst := a₀, snd := f₁ }
⊢ head (isubtree ps (M.mk { fst := a₀, snd := f₀ })) = head (isubtree ps (M.mk { fst := a₀, snd := f₁ })) ∧
    ∃ a f f',
      isubtree ps (M.mk { fst := a₀, snd := f₀ }) = M.mk { fst := a, snd := f } ∧
        isubtree ps (M.mk { fst := a₀, snd := f₁ }) = M.mk { fst := a, snd := f' } ∧ ∀ (i : B F a), R (f i) (f' i)

Next tactic:
apply ps_ih _ _ _ h₁
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
  induction' h' : f' i using PFunctor.M.casesOn' with a₁ f₁
  simp only [h, h', isubtree_cons] at ps_ih ⊢
  rw [h, h'] at h₁
  obtain rfl : a₀ = a₁ := bisim.head h₁
  apply ps_ih _ _ _ h₁
  

Proof state:
case f.f.cons.mk.f.f
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
a₀ : F.A
f₀ : B F a₀ → M F
h : f i = M.mk { fst := a₀, snd := f₀ }
f₁ : B F a₀ → M F
h₁ : R (M.mk { fst := a₀, snd := f₀ }) (M.mk { fst := a₀, snd := f₁ })
h' : f' i = M.mk { fst := a₀, snd := f₁ }
⊢ IsPath ps (M.mk { fst := a₀, snd := f₀ }) ∨ IsPath ps (M.mk { fst := a₀, snd := f₁ })

Next tactic:
rw [← h, ← h']
theorem nth_of_bisim [Inhabited (M F)] (bisim : IsBisimulation R) (s₁ s₂) (ps : Path F) :
    (R s₁ s₂) →
      IsPath ps s₁ ∨ IsPath ps s₂ →
        iselect ps s₁ = iselect ps s₂ ∧
          ∃ (a : _) (f f' : F.B a → M F),
            isubtree ps s₁ = M.mk ⟨a, f⟩ ∧
              isubtree ps s₂ = M.mk ⟨a, f'⟩ ∧ ∀ i : F.B a, f i ~ f' i := by
  intro h₀ hh
  induction' s₁ using PFunctor.M.casesOn' with a f
  induction' s₂ using PFunctor.M.casesOn' with a' f'
  obtain rfl : a = a' := bisim.head h₀
  induction' ps with i ps ps_ih generalizing a f f'
  · exists rfl, a, f, f', rfl, rfl
    apply bisim.tail h₀
  cases' i with a' i
  obtain rfl : a = a' := by rcases hh with hh|hh <;> cases isPath_cons hh <;> rfl
  dsimp only [iselect] at ps_ih ⊢
  have h₁ := bisim.tail h₀ i
  induction' h : f i using PFunctor.M.casesOn' with a₀ f₀
  induction' h' : f' i using PFunctor.M.casesOn' with a₁ f₁
  simp only [h, h', isubtree_cons] at ps_ih ⊢
  rw [h, h'] at h₁
  obtain rfl : a₀ = a₁ := bisim.head h₁
  apply ps_ih _ _ _ h₁
  rw [← h, ← h']
  

Proof state:
case f.f.cons.mk.f.f
F : PFunctor.{u}
X : Type u_1
f✝ : X → ↑F X
R : M F → M F → Prop
inst✝ : Inhabited (M F)
bisim : IsBisimulation R
ps : List (Idx F)
ps_ih :
  ∀ (a : F.A) (f f' : B F a → M F),
    R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' }) →
      IsPath ps (M.mk { fst := a, snd := f }) ∨ IsPath ps (M.mk { fst := a, snd := f' }) →
        head (isubtree ps (M.mk { fst := a, snd := f })) = head (isubtree ps (M.mk { fst := a, snd := f' })) ∧
          ∃ a_1 f_1 f'_1,
            isubtree ps (M.mk { fst := a, snd := f }) = M.mk { fst := a_1, snd := f_1 } ∧
              isubtree ps (M.mk { fst := a, snd := f' }) = M.mk { fst := a_1, snd := f'_1 } ∧
                ∀ (i : B F a_1), R (f_1 i) (f'_1 i)
a : F.A
f f' : B F a → M F
h₀ : R (M.mk { fst := a, snd := f }) (M.mk { fst := a, snd := f' })
i : B F a
hh :
  IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f }) ∨
    IsPath ({ fst := a, snd := i } :: ps) (M.mk { fst := a, snd := f' })
a₀ : F.A
f₀ : B F a₀ → M F
h : f i = M.mk { fst := a₀, snd := f₀ }
f₁ : B F a₀ → M F
h₁ : R (M.mk { fst := a₀, snd := f₀ }) (M.mk { fst := a₀, snd := f₁ })
h' : f' i = M.mk { fst := a₀, snd := f₁ }
⊢ IsPath ps (f i) ∨ IsPath ps (f' i)

Next tactic:
apply Or.imp isPath_cons' isPath_cons' hh
theorem eq_of_bisim [Nonempty (M F)] (bisim : IsBisimulation R) : ∀ s₁ s₂, R s₁ s₂ → s₁ = s₂ := by
  

Proof state:
F : PFunctor.{u}
X : Type u_1
f : X → ↑F X
R : M F → M F → Prop
inst✝ : Nonempty (M F)
bisim : IsBisimulation R
⊢ ∀ (s₁ s₂ : M F), R s₁ s₂ → s₁ = s₂

Next tactic:
inhabit M F
theorem eq_of_bisim [Nonempty (M F)] (bisim : IsBisimulation R) : ∀ s₁ s₂, R s₁ s₂ → s₁ = s₂ := by
  inhabit M F
  

Proof state:
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), R s₁ s₂ → s₁ = s₂

Next tactic:
introv Hr
theorem eq_of_bisim [Nonempty (M F)] (bisim : IsBisimulation R) : ∀ s₁ s₂, R s₁ s₂ → s₁ = s₂ := by
  inhabit M F
  introv Hr; 

Proof state:
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₂
⊢ s₁ = s₂

Next tactic:
apply ext
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
  

Proof state:
case H
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), iselect ps s₁ = iselect ps s₂

Next tactic:
introv
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
  

Proof state:
case H
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
⊢ iselect ps s₁ = iselect ps s₂

Next tactic:
by_cases h : IsPath ps s₁ ∨ IsPath ps s₂
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₂
  · 

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₂
⊢ iselect ps s₁ = iselect ps s₂

Next tactic:
have H := nth_of_bisim R bisim _ _ ps Hr h