l3lab/ntp-mathlib huggingface dataset:
/-- 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
  · change f₀ _ j = f₁ _ 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✝)
⊢ f₀ (Fin2.fs a✝) j = f₁ (Fin2.fs a✝) 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) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y :=
  Cofix.bisim r <| 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' (RelLast' α r) (dest x) (dest y)
⊢ ∀ (x y : Cofix F α), r x y → LiftR (fun {i} => RelLast α r) (dest x) (dest y)

Next tactic:
intros
/-- 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) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y :=
  Cofix.bisim r <| by intros; 

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' (RelLast' α r) (dest x) (dest y)
x✝ y✝ : Cofix F α
a✝ : r x✝ y✝
⊢ LiftR (fun {i} => RelLast α r) (dest x✝) (dest y✝)

Next tactic:
rw [← LiftR_RelLast_iff]
/-- 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) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y :=
  Cofix.bisim r <| by intros; rw [← LiftR_RelLast_iff]; 

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' (RelLast' α r) (dest x) (dest y)
x✝ y✝ : Cofix F α
a✝ : r x✝ y✝
⊢ LiftR' (RelLast' α r) (dest x✝) (dest y✝)

Next tactic:
apply 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) (Cofix.dest x) (Cofix.dest y)) :
    ∀ x y, r x y → x = y :=
  Cofix.bisim r <| by intros; rw [← LiftR_RelLast_iff]; apply h; 

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 → LiftR' (RelLast' α r) (dest x) (dest y)
x✝ y✝ : Cofix F α
a✝ : r x✝ y✝
⊢ r x✝ y✝

Next tactic:
assumption
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
⊢ LiftR (fun {i} => RelLast α R) (dest x) (dest y)

Next tactic:
rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
      

Proof state:
case intro.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
a : (P F).A
f' : B (MvPFunctor.drop (P F)) a ⟹ α
f₀ f₁ : PFunctor.B (MvPFunctor.last (P F)) a → Cofix F α
ux'eq : dest (u x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ }
vx'eq : dest (v x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ }
h' : ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
⊢ LiftR (fun {i} => RelLast α R) (dest x) (dest y)

Next tactic:
rw [liftR_iff]
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
      rw [liftR_iff]
      

Proof state:
case intro.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
a : (P F).A
f' : B (MvPFunctor.drop (P F)) a ⟹ α
f₀ f₁ : PFunctor.B (MvPFunctor.last (P F)) a → Cofix F α
ux'eq : dest (u x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ }
vx'eq : dest (v x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ }
h' : ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
⊢ ∃ a f₀ f₁,
    dest x = MvQPF.abs { fst := a, snd := f₀ } ∧
      dest y = MvQPF.abs { fst := a, snd := f₁ } ∧ ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α R (f₀ i j) (f₁ i j)

Next tactic:
refine'
        ⟨a, q.P.appendContents f' f₀, q.P.appendContents f' f₁, xeq.symm ▸ ux'eq,
          yeq.symm ▸ vx'eq, _⟩
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
      rw [liftR_iff]
      refine'
        ⟨a, q.P.appendContents f' f₀, q.P.appendContents f' f₁, xeq.symm ▸ ux'eq,
          yeq.symm ▸ vx'eq, _⟩
      

Proof state:
case intro.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
a : (P F).A
f' : B (MvPFunctor.drop (P F)) a ⟹ α
f₀ f₁ : PFunctor.B (MvPFunctor.last (P F)) a → Cofix F α
ux'eq : dest (u x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ }
vx'eq : dest (v x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ }
h' : ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
⊢ ∀ (i : Fin2 (n + 1)) (j : B (P F) a i), RelLast α R (appendContents (P F) f' f₀ i j) (appendContents (P F) f' f₁ i j)

Next tactic:
intro i
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
      rw [liftR_iff]
      refine'
        ⟨a, q.P.appendContents f' f₀, q.P.appendContents f' f₁, xeq.symm ▸ ux'eq,
          yeq.symm ▸ vx'eq, _⟩
      intro i; 

Proof state:
case intro.intro.intro.intro.intro.intro
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
a : (P F).A
f' : B (MvPFunctor.drop (P F)) a ⟹ α
f₀ f₁ : PFunctor.B (MvPFunctor.last (P F)) a → Cofix F α
ux'eq : dest (u x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ }
vx'eq : dest (v x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ }
h' : ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
i : Fin2 (n + 1)
⊢ ∀ (j : B (P F) a i), RelLast α R (appendContents (P F) f' f₀ i j) (appendContents (P F) f' f₁ i j)

Next tactic:
cases i
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
      rw [liftR_iff]
      refine'
        ⟨a, q.P.appendContents f' f₀, q.P.appendContents f' f₁, xeq.symm ▸ ux'eq,
          yeq.symm ▸ vx'eq, _⟩
      intro i; cases i
      · 

Proof state:
case intro.intro.intro.intro.intro.intro.fz
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
a : (P F).A
f' : B (MvPFunctor.drop (P F)) a ⟹ α
f₀ f₁ : PFunctor.B (MvPFunctor.last (P F)) a → Cofix F α
ux'eq : dest (u x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ }
vx'eq : dest (v x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ }
h' : ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
⊢ ∀ (j : B (P F) a Fin2.fz), RelLast α R (appendContents (P F) f' f₀ Fin2.fz j) (appendContents (P F) f' f₁ Fin2.fz j)

Next tactic:
apply h'
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
      rw [liftR_iff]
      refine'
        ⟨a, q.P.appendContents f' f₀, q.P.appendContents f' f₁, xeq.symm ▸ ux'eq,
          yeq.symm ▸ vx'eq, _⟩
      intro i; cases i
      · apply h'
      · 

Proof state:
case intro.intro.intro.intro.intro.intro.fs
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
a : (P F).A
f' : B (MvPFunctor.drop (P F)) a ⟹ α
f₀ f₁ : PFunctor.B (MvPFunctor.last (P F)) a → Cofix F α
ux'eq : dest (u x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ }
vx'eq : dest (v x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ }
h' : ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
a✝ : Fin2 (Nat.add n 0)
⊢ ∀ (j : B (P F) a (Fin2.fs a✝)),
    RelLast α R (appendContents (P F) f' f₀ (Fin2.fs a✝) j) (appendContents (P F) f' f₁ (Fin2.fs a✝) j)

Next tactic:
intro j
/-- Bisimulation principle the values `⟨a,f⟩` of the polynomial functor representing
`Cofix F α` as well as an invariant `Q : β → Prop` and a state `β` generating the
left-hand side and right-hand side of the equality through functions `u v : β → Cofix F α` -/
theorem Cofix.bisim' {α : TypeVec n} {β : Type*} (Q : β → Prop) (u v : β → Cofix F α)
    (h : ∀ x, Q x → ∃ a f' f₀ f₁,
      Cofix.dest (u x) = q.abs ⟨a, q.P.appendContents f' f₀⟩ ∧
        Cofix.dest (v x) = q.abs ⟨a, q.P.appendContents f' f₁⟩ ∧
          ∀ i, ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x') :
    ∀ x, Q x → u x = v x := fun x Qx =>
  let R := fun w z : Cofix F α => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
  Cofix.bisim R
    (fun x y ⟨x', Qx', xeq, yeq⟩ => by
      rcases h x' Qx' with ⟨a, f', f₀, f₁, ux'eq, vx'eq, h'⟩
      rw [liftR_iff]
      refine'
        ⟨a, q.P.appendContents f' f₀, q.P.appendContents f' f₁, xeq.symm ▸ ux'eq,
          yeq.symm ▸ vx'eq, _⟩
      intro i; cases i
      · apply h'
      · intro j
        

Proof state:
case intro.intro.intro.intro.intro.intro.fs
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
β : Type u_1
Q : β → Prop
u v : β → Cofix F α
h :
  ∀ (x : β),
    Q x →
      ∃ a f' f₀ f₁,
        dest (u x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ } ∧
          dest (v x) = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ } ∧
            ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
x✝¹ : β
Qx : Q x✝¹
R : Cofix F α → Cofix F α → Prop := fun w z => ∃ x', Q x' ∧ w = u x' ∧ z = v x'
x y : Cofix F α
x✝ : R x y
x' : β
Qx' : Q x'
xeq : x = u x'
yeq : y = v x'
a : (P F).A
f' : B (MvPFunctor.drop (P F)) a ⟹ α
f₀ f₁ : PFunctor.B (MvPFunctor.last (P F)) a → Cofix F α
ux'eq : dest (u x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₀ }
vx'eq : dest (v x') = MvQPF.abs { fst := a, snd := appendContents (P F) f' f₁ }
h' : ∀ (i : PFunctor.B (MvPFunctor.last (P F)) a), ∃ x', Q x' ∧ f₀ i = u x' ∧ f₁ i = v x'
a✝ : Fin2 (Nat.add n 0)
j : B (P F) a (Fin2.fs a✝)
⊢ RelLast α R (appendContents (P F) f' f₀ (Fin2.fs a✝) j) (appendContents (P F) f' f₁ (Fin2.fs a✝) j)

Next tactic:
apply Eq.refl
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
x : Cofix F α
⊢ mk (dest x) = x

Next tactic:
apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl;
  

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

Next tactic:
dsimp
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl;
  dsimp
  

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

Next tactic:
intro x y h
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl;
  dsimp
  intro x y h
  

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

Next tactic:
rw [h]
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl;
  dsimp
  intro x y h
  rw [h]
  

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

Next tactic:
conv =>
    lhs
    congr
    rfl
    rw [Cofix.mk]
    rw [Cofix.dest_corec]
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl;
  dsimp
  intro x y h
  rw [h]
  conv =>
    

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
x✝ x y : Cofix F α
h : x = mk (dest y)
| (TypeVec.id ::: Quot.mk fun x y => x = mk (dest y)) <$$> dest (mk (dest y)) =
    (TypeVec.id ::: Quot.mk fun x y => x = mk (dest y)) <$$> dest y

Next tactic:
lhs
    congr
    rfl
    rw [Cofix.mk]
    rw [Cofix.dest_corec]
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl;
  dsimp
  intro x y h
  rw [h]
  conv =>
    

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
x✝ x y : Cofix F α
h : x = mk (dest y)
| (TypeVec.id ::: Quot.mk fun x y => x = mk (dest y)) <$$> dest (mk (dest y)) =
    (TypeVec.id ::: Quot.mk fun x y => x = mk (dest y)) <$$> dest y

Next tactic:
lhs
theorem Cofix.mk_dest {α : TypeVec n} (x : Cofix F α) : Cofix.mk (Cofix.dest x) = x := by
  apply Cofix.bisim_rel (fun x y : Cofix F α => x = Cofix.mk (Cofix.dest y)) _ _ _ rfl;
  dsimp
  intro x y h
  rw [h]
  conv =>
    lhs
    

Proof state:
n : ℕ
F : TypeVec.{u} (n + 1) → Type u
mvf : MvFunctor F
q : MvQPF F
α : TypeVec.{u} n
x✝ x y : Cofix F α
h : x = mk (dest y)
| (TypeVec.id ::: Quot.mk fun x y => x = mk (dest y)) <$$> dest (mk (dest y))

Next tactic:
congr