l3lab/ntp-mathlib huggingface dataset:
/-- Bisimulation principle using `map` and `Quot.mk` to match and relate children of two trees. -/
theorem Cofix.bisim_rel {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y →
      appendFun id (Quot.mk r) <$$> Cofix.dest x = appendFun id (Quot.mk r) <$$> Cofix.dest y) :
    ∀ x y, r x y → x = y := by
  let r' (x y) := x = y ∨ r x y
  intro x y rxy
  apply Cofix.bisim_aux r'
  · intro x
    left
    rfl
  · intro x y r'xy
    cases r'xy
    case inl h =>
      rw [h]
    case inr r'xy =>
      have : ∀ x y, r x y → r' x y := fun x y h => Or.inr h
      rw [← Quot.factor_mk_eq _ _ this]
      dsimp
      

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → (TypeVec.id ::: Quot.mk r) <$$> dest x = (TypeVec.id ::: Quot.mk r) <$$> dest y
r' : Cofix F α → Cofix F α → Prop := fun x y => x = y ∨ r x y
x✝ y✝ : Cofix F α
rxy : r x✝ y✝
x y : Cofix F α
r'xy : r x y
this : ∀ (x y : Cofix F α), r x y → r' x y
⊢ (TypeVec.id ::: Quot.factor (fun x y => r x y) (fun x y => x = y ∨ r x y) this ∘ Quot.mk fun x y => r x y) <$$>
      dest x =
    (TypeVec.id ::: Quot.factor (fun x y => r x y) (fun x y => x = y ∨ r x y) this ∘ Quot.mk fun x y => r x y) <$$>
      dest y

Next tactic:
rw [appendFun_comp_id]
/-- Bisimulation principle using `map` and `Quot.mk` to match and relate children of two trees. -/
theorem Cofix.bisim_rel {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y →
      appendFun id (Quot.mk r) <$$> Cofix.dest x = appendFun id (Quot.mk r) <$$> Cofix.dest y) :
    ∀ x y, r x y → x = y := by
  let r' (x y) := x = y ∨ r x y
  intro x y rxy
  apply Cofix.bisim_aux r'
  · intro x
    left
    rfl
  · intro x y r'xy
    cases r'xy
    case inl h =>
      rw [h]
    case inr r'xy =>
      have : ∀ x y, r x y → r' x y := fun x y h => Or.inr h
      rw [← Quot.factor_mk_eq _ _ this]
      dsimp
      rw [appendFun_comp_id]
      

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → (TypeVec.id ::: Quot.mk r) <$$> dest x = (TypeVec.id ::: Quot.mk r) <$$> dest y
r' : Cofix F α → Cofix F α → Prop := fun x y => x = y ∨ r x y
x✝ y✝ : Cofix F α
rxy : r x✝ y✝
x y : Cofix F α
r'xy : r x y
this : ∀ (x y : Cofix F α), r x y → r' x y
⊢ ((TypeVec.id ::: Quot.factor (fun x y => r x y) (fun x y => x = y ∨ r x y) this) ⊚
        (TypeVec.id ::: Quot.mk fun x y => r x y)) <$$>
      dest x =
    ((TypeVec.id ::: Quot.factor (fun x y => r x y) (fun x y => x = y ∨ r x y) this) ⊚
        (TypeVec.id ::: Quot.mk fun x y => r x y)) <$$>
      dest y

Next tactic:
rw [@comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r)),
        @comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r))]
/-- Bisimulation principle using `map` and `Quot.mk` to match and relate children of two trees. -/
theorem Cofix.bisim_rel {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y →
      appendFun id (Quot.mk r) <$$> Cofix.dest x = appendFun id (Quot.mk r) <$$> Cofix.dest y) :
    ∀ x y, r x y → x = y := by
  let r' (x y) := x = y ∨ r x y
  intro x y rxy
  apply Cofix.bisim_aux r'
  · intro x
    left
    rfl
  · intro x y r'xy
    cases r'xy
    case inl h =>
      rw [h]
    case inr r'xy =>
      have : ∀ x y, r x y → r' x y := fun x y h => Or.inr h
      rw [← Quot.factor_mk_eq _ _ this]
      dsimp
      rw [appendFun_comp_id]
      rw [@comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r)),
        @comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r))]
      

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → (TypeVec.id ::: Quot.mk r) <$$> dest x = (TypeVec.id ::: Quot.mk r) <$$> dest y
r' : Cofix F α → Cofix F α → Prop := fun x y => x = y ∨ r x y
x✝ y✝ : Cofix F α
rxy : r x✝ y✝
x y : Cofix F α
r'xy : r x y
this : ∀ (x y : Cofix F α), r x y → r' x y
⊢ (TypeVec.id ::: Quot.factor (fun x y => r x y) (fun x y => x = y ∨ r x y) this) <$$>
      (TypeVec.id ::: Quot.mk r) <$$> dest x =
    (TypeVec.id ::: Quot.factor (fun x y => r x y) (fun x y => x = y ∨ r x y) this) <$$>
      (TypeVec.id ::: Quot.mk r) <$$> dest y

Next tactic:
rw [h _ _ r'xy]
/-- Bisimulation principle using `map` and `Quot.mk` to match and relate children of two trees. -/
theorem Cofix.bisim_rel {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y →
      appendFun id (Quot.mk r) <$$> Cofix.dest x = appendFun id (Quot.mk r) <$$> Cofix.dest y) :
    ∀ x y, r x y → x = y := by
  let r' (x y) := x = y ∨ r x y
  intro x y rxy
  apply Cofix.bisim_aux r'
  · intro x
    left
    rfl
  · intro x y r'xy
    cases r'xy
    case inl h =>
      rw [h]
    case inr r'xy =>
      have : ∀ x y, r x y → r' x y := fun x y h => Or.inr h
      rw [← Quot.factor_mk_eq _ _ this]
      dsimp
      rw [appendFun_comp_id]
      rw [@comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r)),
        @comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r))]
      rw [h _ _ r'xy]
  

Proof state:
case a
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → (TypeVec.id ::: Quot.mk r) <$$> dest x = (TypeVec.id ::: Quot.mk r) <$$> dest y
r' : Cofix F α → Cofix F α → Prop := fun x y => x = y ∨ r x y
x y : Cofix F α
rxy : r x y
⊢ r' x y

Next tactic:
right
/-- Bisimulation principle using `map` and `Quot.mk` to match and relate children of two trees. -/
theorem Cofix.bisim_rel {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y →
      appendFun id (Quot.mk r) <$$> Cofix.dest x = appendFun id (Quot.mk r) <$$> Cofix.dest y) :
    ∀ x y, r x y → x = y := by
  let r' (x y) := x = y ∨ r x y
  intro x y rxy
  apply Cofix.bisim_aux r'
  · intro x
    left
    rfl
  · intro x y r'xy
    cases r'xy
    case inl h =>
      rw [h]
    case inr r'xy =>
      have : ∀ x y, r x y → r' x y := fun x y h => Or.inr h
      rw [← Quot.factor_mk_eq _ _ this]
      dsimp
      rw [appendFun_comp_id]
      rw [@comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r)),
        @comp_map _ _ _ q _ _ _ (appendFun id (Quot.mk r))]
      rw [h _ _ r'xy]
  right; 

Proof state:
case a.h
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → (TypeVec.id ::: Quot.mk r) <$$> dest x = (TypeVec.id ::: Quot.mk r) <$$> dest y
r' : Cofix F α → Cofix F α → Prop := fun x y => x = y ∨ r x y
x y : Cofix F α
rxy : r x y
⊢ r x y

Next tactic:
exact rxy
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
⊢ ∀ (x y : Cofix F α), r x y → x = y

Next tactic:
apply Cofix.bisim_rel
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  

Proof state:
case h
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
⊢ ∀ (x y : Cofix F α),
    r x y →
      (TypeVec.id ::: Quot.mk fun x y => r x y) <$$> dest x = (TypeVec.id ::: Quot.mk fun x y => r x y) <$$> dest y

Next tactic:
intro x y rxy
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  

Proof state:
case h
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
⊢ (TypeVec.id ::: Quot.mk fun x y => r x y) <$$> dest x = (TypeVec.id ::: Quot.mk fun x y => r x y) <$$> dest y

Next tactic:
rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  

Proof state:
case h.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
⊢ (TypeVec.id ::: Quot.mk fun x y => r x y) <$$> dest x = (TypeVec.id ::: Quot.mk fun x y => r x y) <$$> dest y

Next tactic:
rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  

Proof state:
case h.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
⊢ MvQPF.abs { fst := a, snd := (TypeVec.id ::: Quot.mk fun x y => r x y) ⊚ f₀ } =
    MvQPF.abs { fst := a, snd := (TypeVec.id ::: Quot.mk fun x y => r x y) ⊚ f₁ }

Next tactic:
rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  

Proof state:
case h.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
⊢ MvQPF.abs { fst := a, snd := (TypeVec.id ::: Quot.mk fun x y => r x y) ⊚ splitFun (dropFun f₀) (lastFun f₀) } =
    MvQPF.abs { fst := a, snd := (TypeVec.id ::: Quot.mk fun x y => r x y) ⊚ splitFun (dropFun f₁) (lastFun f₁) }

Next tactic:
rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  

Proof state:
case h.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
⊢ MvQPF.abs { fst := a, snd := splitFun (TypeVec.id ⊚ dropFun f₀) ((Quot.mk fun x y => r x y) ∘ lastFun f₀) } =
    MvQPF.abs { fst := a, snd := splitFun (TypeVec.id ⊚ dropFun f₁) ((Quot.mk fun x y => r x y) ∘ lastFun f₁) }

Next tactic:
rw [id_comp, id_comp]
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  rw [id_comp, id_comp]
  

Proof state:
case h.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
⊢ MvQPF.abs { fst := a, snd := splitFun (dropFun f₀) ((Quot.mk fun x y => r x y) ∘ lastFun f₀) } =
    MvQPF.abs { fst := a, snd := splitFun (dropFun f₁) ((Quot.mk fun x y => r x y) ∘ lastFun f₁) }

Next tactic:
congr 2 with (i j)
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  rw [id_comp, id_comp]
  congr 2 with (i j); 

Proof state:
case h.intro.intro.intro.intro.intro.e_a.e_snd.a.h
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
i : Fin2 (n + 1)
j : B (P F) a i
⊢ splitFun (dropFun f₀) ((Quot.mk fun x y => r x y) ∘ lastFun f₀) i j =
    splitFun (dropFun f₁) ((Quot.mk fun x y => r x y) ∘ lastFun f₁) i j

Next tactic:
cases' i with _ i
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  rw [id_comp, id_comp]
  congr 2 with (i j); cases' i with _ i <;> 

Proof state:
case h.intro.intro.intro.intro.intro.e_a.e_snd.a.h.fz
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
j : B (P F) a Fin2.fz
⊢ splitFun (dropFun f₀) ((Quot.mk fun x y => r x y) ∘ lastFun f₀) Fin2.fz j =
    splitFun (dropFun f₁) ((Quot.mk fun x y => r x y) ∘ lastFun f₁) Fin2.fz j

Next tactic:
dsimp
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  rw [id_comp, id_comp]
  congr 2 with (i j); cases' i with _ i <;> 

Proof state:
case h.intro.intro.intro.intro.intro.e_a.e_snd.a.h.fs
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
a✝ : Fin2 (Nat.add n 0)
j : B (P F) a (Fin2.fs a✝)
⊢ splitFun (dropFun f₀) ((Quot.mk fun x y => r x y) ∘ lastFun f₀) (Fin2.fs a✝) j =
    splitFun (dropFun f₁) ((Quot.mk fun x y => r x y) ∘ lastFun f₁) (Fin2.fs a✝) j

Next tactic:
dsimp
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  rw [id_comp, id_comp]
  congr 2 with (i j); cases' i with _ i <;> dsimp
  · 

Proof state:
case h.intro.intro.intro.intro.intro.e_a.e_snd.a.h.fz
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
j : B (P F) a Fin2.fz
⊢ splitFun (dropFun f₀) ((Quot.mk fun x y => r x y) ∘ lastFun f₀) Fin2.fz j =
    splitFun (dropFun f₁) ((Quot.mk fun x y => r x y) ∘ lastFun f₁) Fin2.fz j

Next tactic:
apply Quot.sound
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  rw [id_comp, id_comp]
  congr 2 with (i j); cases' i with _ i <;> dsimp
  · apply Quot.sound
    

Proof state:
case h.intro.intro.intro.intro.intro.e_a.e_snd.a.h.fz.a
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
j : B (P F) a Fin2.fz
⊢ r (lastFun f₀ j) (lastFun f₁ j)

Next tactic:
apply h' _ j
/-- Bisimulation principle using `LiftR` to match and relate children of two trees. -/
theorem Cofix.bisim {α : TypeVec n} (r : Cofix F α → Cofix F α → Prop)
    (h : ∀ x y, r x y → LiftR (RelLast α r (i := _)) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y := by
  apply Cofix.bisim_rel
  intro x y rxy
  rcases (liftR_iff (fun a b => RelLast α r a b) (dest x) (dest y)).mp (h x y rxy)
    with ⟨a, f₀, f₁, dxeq, dyeq, h'⟩
  rw [dxeq, dyeq, ← abs_map, ← abs_map, MvPFunctor.map_eq, MvPFunctor.map_eq]
  rw [← split_dropFun_lastFun f₀, ← split_dropFun_lastFun f₁]
  rw [appendFun_comp_splitFun, appendFun_comp_splitFun]
  rw [id_comp, id_comp]
  congr 2 with (i j); cases' i with _ i <;> dsimp
  · apply Quot.sound
    apply h' _ j
  · 

Proof state:
case h.intro.intro.intro.intro.intro.e_a.e_snd.a.h.fs
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
r : Cofix F α → Cofix F α → Prop
h : ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)
x y : Cofix F α
rxy : r x y
a : (P F).A
f₀ f₁ : B (P F) a ⟹ fun {i} => (α ::: Cofix F α) i
dxeq : dest x = MvQPF.abs { fst := a, snd := f₀ }
dyeq : dest y = MvQPF.abs { fst := a, snd := f₁ }
h' : ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α r (f₀ i j) (f₁ i j)
a✝ : Fin2 (Nat.add n 0)
j : B (P F) a (Fin2.fs a✝)
⊢ splitFun (dropFun f₀) ((Quot.mk fun x y => r x y) ∘ lastFun f₀) (Fin2.fs a✝) j =
    splitFun (dropFun f₁) ((Quot.mk fun x y => r x y) ∘ lastFun f₁) (Fin2.fs a✝) j

Next tactic:
change f₀ _ j = f₁ _ j