l3lab/ntp-mathlib huggingface dataset:
theorem head_congr : ∀ {s t : WSeq α}, s ~ʷ t → head s ~ head t := by
  suffices ∀ {s t : WSeq α}, s ~ʷ t → ∀ {o}, o ∈ head s → o ∈ head t from fun s t h o =>
    ⟨this h, this h.symm⟩
  intro s t h o ho
  rcases @Computation.exists_of_mem_map _ _ _ _ (destruct s) ho with ⟨ds, dsm, dse⟩
  rw [← dse]
  cases' destruct_congr h with l r
  rcases l dsm with ⟨dt, dtm, dst⟩
  cases' ds with a <;> cases' dt with b
  · apply Computation.mem_map _ dtm
  · cases b
    cases dst
  · cases a
    cases dst
  · cases' a with a s'
    cases' b with b t'
    

Proof state:
case intro.intro.intro.intro.intro.some.some.mk.mk
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h : s ~ʷ t
o : Option α
ho : o ∈ head s
l : ∀ {a : Option (α × WSeq α)}, a ∈ destruct s → ∃ b, b ∈ destruct t ∧ BisimO (fun x x_1 => x ~ʷ x_1) a b
r : ∀ {b : Option (α × WSeq α)}, b ∈ destruct t → ∃ a, a ∈ destruct s ∧ BisimO (fun x x_1 => x ~ʷ x_1) a b
a : α
s' : WSeq α
dsm : some (a, s') ∈ destruct s
dse : Prod.fst <$> some (a, s') = o
b : α
t' : WSeq α
dtm : some (b, t') ∈ destruct t
dst : BisimO (fun x x_1 => x ~ʷ x_1) (some (a, s')) (some (b, t'))
⊢ Prod.fst <$> some (a, s') ∈ head t

Next tactic:
rw [dst.left]
theorem head_congr : ∀ {s t : WSeq α}, s ~ʷ t → head s ~ head t := by
  suffices ∀ {s t : WSeq α}, s ~ʷ t → ∀ {o}, o ∈ head s → o ∈ head t from fun s t h o =>
    ⟨this h, this h.symm⟩
  intro s t h o ho
  rcases @Computation.exists_of_mem_map _ _ _ _ (destruct s) ho with ⟨ds, dsm, dse⟩
  rw [← dse]
  cases' destruct_congr h with l r
  rcases l dsm with ⟨dt, dtm, dst⟩
  cases' ds with a <;> cases' dt with b
  · apply Computation.mem_map _ dtm
  · cases b
    cases dst
  · cases a
    cases dst
  · cases' a with a s'
    cases' b with b t'
    rw [dst.left]
    

Proof state:
case intro.intro.intro.intro.intro.some.some.mk.mk
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h : s ~ʷ t
o : Option α
ho : o ∈ head s
l : ∀ {a : Option (α × WSeq α)}, a ∈ destruct s → ∃ b, b ∈ destruct t ∧ BisimO (fun x x_1 => x ~ʷ x_1) a b
r : ∀ {b : Option (α × WSeq α)}, b ∈ destruct t → ∃ a, a ∈ destruct s ∧ BisimO (fun x x_1 => x ~ʷ x_1) a b
a : α
s' : WSeq α
dsm : some (a, s') ∈ destruct s
dse : Prod.fst <$> some (a, s') = o
b : α
t' : WSeq α
dtm : some (b, t') ∈ destruct t
dst : BisimO (fun x x_1 => x ~ʷ x_1) (some (a, s')) (some (b, t'))
⊢ Prod.fst <$> some (b, s') ∈ head t

Next tactic:
exact @Computation.mem_map _ _ (@Functor.map _ _ (α × WSeq α) _ Prod.fst)
      (some (b, t')) (destruct t) dtm
theorem flatten_equiv {c : Computation (WSeq α)} {s} (h : s ∈ c) : flatten c ~ʷ s := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
c : Computation (WSeq α)
s : WSeq α
h : s ∈ c
⊢ flatten c ~ʷ s

Next tactic:
apply Computation.memRecOn h
theorem flatten_equiv {c : Computation (WSeq α)} {s} (h : s ∈ c) : flatten c ~ʷ s := by
  apply Computation.memRecOn h
  · 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
c : Computation (WSeq α)
s : WSeq α
h : s ∈ c
⊢ flatten (Computation.pure s) ~ʷ s

Next tactic:
simp [Equiv.refl]
theorem flatten_equiv {c : Computation (WSeq α)} {s} (h : s ∈ c) : flatten c ~ʷ s := by
  apply Computation.memRecOn h
  · simp [Equiv.refl]
  · 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
c : Computation (WSeq α)
s : WSeq α
h : s ∈ c
⊢ ∀ (s_1 : Computation (WSeq α)), flatten s_1 ~ʷ s → flatten (Computation.think s_1) ~ʷ s

Next tactic:
intro s'
theorem flatten_equiv {c : Computation (WSeq α)} {s} (h : s ∈ c) : flatten c ~ʷ s := by
  apply Computation.memRecOn h
  · simp [Equiv.refl]
  · intro s'
    

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
c : Computation (WSeq α)
s : WSeq α
h : s ∈ c
s' : Computation (WSeq α)
⊢ flatten s' ~ʷ s → flatten (Computation.think s') ~ʷ s

Next tactic:
apply Equiv.trans
theorem flatten_equiv {c : Computation (WSeq α)} {s} (h : s ∈ c) : flatten c ~ʷ s := by
  apply Computation.memRecOn h
  · simp [Equiv.refl]
  · intro s'
    apply Equiv.trans
    

Proof state:
case h2.a
α : Type u
β : Type v
γ : Type w
c : Computation (WSeq α)
s : WSeq α
h : s ∈ c
s' : Computation (WSeq α)
⊢ flatten (Computation.think s') ~ʷ flatten s'

Next tactic:
simp [think_equiv]
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝¹ : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s : WSeq α
t : WSeq β
h✝ : S s t
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h : Computation.LiftRel (LiftRel R) c1 c2
⊢ Computation.LiftRel (LiftRelO R S) (destruct (flatten c1)) (destruct (flatten c2))

Next tactic:
simp [-exists_and_left]
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝¹ : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s : WSeq α
t : WSeq β
h✝ : S s t
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h : Computation.LiftRel (LiftRel R) c1 c2
⊢ Computation.LiftRel
    (LiftRelO R fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2)
    (c1 >>= destruct) (c2 >>= destruct)

Next tactic:
apply liftRel_bind _ _ h
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝¹ : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s : WSeq α
t : WSeq β
h✝ : S s t
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h : Computation.LiftRel (LiftRel R) c1 c2
⊢ ∀ {a : WSeq α} {b : WSeq β},
    LiftRel R a b →
      Computation.LiftRel
        (LiftRelO R fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2)
        (destruct a) (destruct b)

Next tactic:
intro a b ab
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝¹ : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s : WSeq α
t : WSeq β
h✝ : S s t
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h : Computation.LiftRel (LiftRel R) c1 c2
a : WSeq α
b : WSeq β
ab : LiftRel R a b
⊢ Computation.LiftRel
    (LiftRelO R fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2)
    (destruct a) (destruct b)

Next tactic:
apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
      

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝¹ : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s : WSeq α
t : WSeq β
h✝ : S s t
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h : Computation.LiftRel (LiftRel R) c1 c2
a : WSeq α
b : WSeq β
ab : LiftRel R a b
⊢ ∀ {a : Option (α × WSeq α)} {b : Option (β × WSeq β)},
    LiftRelO R (LiftRel R) a b →
      LiftRelO R (fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2) a b

Next tactic:
intro a b
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
      intro a b; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝¹ : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s : WSeq α
t : WSeq β
h✝ : S s t
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h : Computation.LiftRel (LiftRel R) c1 c2
a✝ : WSeq α
b✝ : WSeq β
ab : LiftRel R a✝ b✝
a : Option (α × WSeq α)
b : Option (β × WSeq β)
⊢ LiftRelO R (LiftRel R) a b →
    LiftRelO R (fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2) a b

Next tactic:
apply LiftRelO.imp_right
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
      intro a b; apply LiftRelO.imp_right
      

Proof state:
case H
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝¹ : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s : WSeq α
t : WSeq β
h✝ : S s t
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h : Computation.LiftRel (LiftRel R) c1 c2
a✝ : WSeq α
b✝ : WSeq β
ab : LiftRel R a✝ b✝
a : Option (α × WSeq α)
b : Option (β × WSeq β)
⊢ ∀ (s : WSeq α) (t : WSeq β),
    LiftRel R s t → ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2

Next tactic:
intro s t h
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
      intro a b; apply LiftRelO.imp_right
      intro s t h; 

Proof state:
case H
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝² : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s✝ : WSeq α
t✝ : WSeq β
h✝¹ : S s✝ t✝
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h✝ : Computation.LiftRel (LiftRel R) c1 c2
a✝ : WSeq α
b✝ : WSeq β
ab : LiftRel R a✝ b✝
a : Option (α × WSeq α)
b : Option (β × WSeq β)
s : WSeq α
t : WSeq β
h : LiftRel R s t
⊢ ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2

Next tactic:
refine' ⟨Computation.pure s, Computation.pure t, _, _, _⟩
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
      intro a b; apply LiftRelO.imp_right
      intro s t h; refine' ⟨Computation.pure s, Computation.pure t, _, _, _⟩ <;>
        -- Porting note: These 2 theorems should be excluded.
        

Proof state:
case H.refine'_1
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝² : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s✝ : WSeq α
t✝ : WSeq β
h✝¹ : S s✝ t✝
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h✝ : Computation.LiftRel (LiftRel R) c1 c2
a✝ : WSeq α
b✝ : WSeq β
ab : LiftRel R a✝ b✝
a : Option (α × WSeq α)
b : Option (β × WSeq β)
s : WSeq α
t : WSeq β
h : LiftRel R s t
⊢ s = flatten (Computation.pure s)

Next tactic:
simp [h, -liftRel_pure_left, -liftRel_pure_right]
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
      intro a b; apply LiftRelO.imp_right
      intro s t h; refine' ⟨Computation.pure s, Computation.pure t, _, _, _⟩ <;>
        -- Porting note: These 2 theorems should be excluded.
        

Proof state:
case H.refine'_2
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝² : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s✝ : WSeq α
t✝ : WSeq β
h✝¹ : S s✝ t✝
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h✝ : Computation.LiftRel (LiftRel R) c1 c2
a✝ : WSeq α
b✝ : WSeq β
ab : LiftRel R a✝ b✝
a : Option (α × WSeq α)
b : Option (β × WSeq β)
s : WSeq α
t : WSeq β
h : LiftRel R s t
⊢ t = flatten (Computation.pure t)

Next tactic:
simp [h, -liftRel_pure_left, -liftRel_pure_right]
theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) :=
  let S s t := ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
  ⟨S, ⟨c1, c2, rfl, rfl, h⟩, fun {s t} h =>
    match s, t, h with
    | _, _, ⟨c1, c2, rfl, rfl, h⟩ => by
      -- Porting note: `exists_and_left` should be excluded.
      simp [-exists_and_left]; apply liftRel_bind _ _ h
      intro a b ab; apply Computation.LiftRel.imp _ _ _ (liftRel_destruct ab)
      intro a b; apply LiftRelO.imp_right
      intro s t h; refine' ⟨Computation.pure s, Computation.pure t, _, _, _⟩ <;>
        -- Porting note: These 2 theorems should be excluded.
        

Proof state:
case H.refine'_3
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
c1✝ : Computation (WSeq α)
c2✝ : Computation (WSeq β)
h✝² : Computation.LiftRel (LiftRel R) c1✝ c2✝
S : WSeq α → WSeq β → Prop :=
  fun s t => ∃ c1 c2, s = flatten c1 ∧ t = flatten c2 ∧ Computation.LiftRel (LiftRel R) c1 c2
s✝ : WSeq α
t✝ : WSeq β
h✝¹ : S s✝ t✝
c1 : Computation (WSeq α)
c2 : Computation (WSeq β)
h✝ : Computation.LiftRel (LiftRel R) c1 c2
a✝ : WSeq α
b✝ : WSeq β
ab : LiftRel R a✝ b✝
a : Option (α × WSeq α)
b : Option (β × WSeq β)
s : WSeq α
t : WSeq β
h : LiftRel R s t
⊢ Computation.LiftRel (LiftRel R) (Computation.pure s) (Computation.pure t)

Next tactic:
simp [h, -liftRel_pure_left, -liftRel_pure_right]
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h : s ~ʷ t
⊢ tail s ~ʷ tail t

Next tactic:
apply flatten_congr
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  

Proof state:
case a
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h : s ~ʷ t
⊢ Computation.LiftRel Equiv ((fun o => Option.recOn o nil Prod.snd) <$> destruct s)
    ((fun o => Option.recOn o nil Prod.snd) <$> destruct t)

Next tactic:
dsimp only [(· <$> ·)]
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; 

Proof state:
case a
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h : s ~ʷ t
⊢ Computation.LiftRel Equiv (Computation.map (fun o => Option.rec nil Prod.snd o) (destruct s))
    (Computation.map (fun o => Option.rec nil Prod.snd o) (destruct t))

Next tactic:
rw [← Computation.bind_pure, ← Computation.bind_pure]
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  

Proof state:
case a
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h : s ~ʷ t
⊢ Computation.LiftRel Equiv (Computation.bind (destruct s) (Computation.pure ∘ fun o => Option.rec nil Prod.snd o))
    (Computation.bind (destruct t) (Computation.pure ∘ fun o => Option.rec nil Prod.snd o))

Next tactic:
apply liftRel_bind _ _ (destruct_congr h)
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  apply liftRel_bind _ _ (destruct_congr h)
  -- Porting note: These 2 theorems should be excluded.
  

Proof state:
case a
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h : s ~ʷ t
⊢ ∀ {a b : Option (α × WSeq α)},
    BisimO (fun x x_1 => x ~ʷ x_1) a b →
      Computation.LiftRel Equiv ((Computation.pure ∘ fun o => Option.rec nil Prod.snd o) a)
        ((Computation.pure ∘ fun o => Option.rec nil Prod.snd o) b)

Next tactic:
intro a b h
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  apply liftRel_bind _ _ (destruct_congr h)
  -- Porting note: These 2 theorems should be excluded.
  intro a b h; 

Proof state:
case a
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h✝ : s ~ʷ t
a b : Option (α × WSeq α)
h : BisimO (fun x x_1 => x ~ʷ x_1) a b
⊢ Computation.LiftRel Equiv ((Computation.pure ∘ fun o => Option.rec nil Prod.snd o) a)
    ((Computation.pure ∘ fun o => Option.rec nil Prod.snd o) b)

Next tactic:
simp [-liftRel_pure_left, -liftRel_pure_right]
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  apply liftRel_bind _ _ (destruct_congr h)
  -- Porting note: These 2 theorems should be excluded.
  intro a b h; simp [-liftRel_pure_left, -liftRel_pure_right]
  

Proof state:
case a
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h✝ : s ~ʷ t
a b : Option (α × WSeq α)
h : BisimO (fun x x_1 => x ~ʷ x_1) a b
⊢ Option.rec nil Prod.snd a ~ʷ Option.rec nil Prod.snd b

Next tactic:
cases' a with a
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  apply liftRel_bind _ _ (destruct_congr h)
  -- Porting note: These 2 theorems should be excluded.
  intro a b h; simp [-liftRel_pure_left, -liftRel_pure_right]
  cases' a with a <;> 

Proof state:
case a.none
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h✝ : s ~ʷ t
b : Option (α × WSeq α)
h : BisimO (fun x x_1 => x ~ʷ x_1) none b
⊢ Option.rec nil Prod.snd none ~ʷ Option.rec nil Prod.snd b

Next tactic:
cases' b with b
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  apply liftRel_bind _ _ (destruct_congr h)
  -- Porting note: These 2 theorems should be excluded.
  intro a b h; simp [-liftRel_pure_left, -liftRel_pure_right]
  cases' a with a <;> 

Proof state:
case a.some
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h✝ : s ~ʷ t
b : Option (α × WSeq α)
a : α × WSeq α
h : BisimO (fun x x_1 => x ~ʷ x_1) (some a) b
⊢ Option.rec nil Prod.snd (some a) ~ʷ Option.rec nil Prod.snd b

Next tactic:
cases' b with b
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  apply liftRel_bind _ _ (destruct_congr h)
  -- Porting note: These 2 theorems should be excluded.
  intro a b h; simp [-liftRel_pure_left, -liftRel_pure_right]
  cases' a with a <;> cases' b with b
  · 

Proof state:
case a.none.none
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h✝ : s ~ʷ t
h : BisimO (fun x x_1 => x ~ʷ x_1) none none
⊢ Option.rec nil Prod.snd none ~ʷ Option.rec nil Prod.snd none

Next tactic:
trivial
theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t := by
  apply flatten_congr
  dsimp only [(· <$> ·)]; rw [← Computation.bind_pure, ← Computation.bind_pure]
  apply liftRel_bind _ _ (destruct_congr h)
  -- Porting note: These 2 theorems should be excluded.
  intro a b h; simp [-liftRel_pure_left, -liftRel_pure_right]
  cases' a with a <;> cases' b with b
  · trivial
  · 

Proof state:
case a.none.some
α : Type u
β : Type v
γ : Type w
s t : WSeq α
h✝ : s ~ʷ t
b : α × WSeq α
h : BisimO (fun x x_1 => x ~ʷ x_1) none (some b)
⊢ Option.rec nil Prod.snd none ~ʷ Option.rec nil Prod.snd (some b)

Next tactic:
cases h