l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem bind_ret (f : α → β) (s) : bind s (ret ∘ f) ~ʷ map f s := by
  dsimp [bind]
  rw [map_comp]
  

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
s : WSeq α
⊢ join (map ret (map f s)) ~ʷ map f s

Next tactic:
apply join_map_ret
@[simp]
theorem ret_bind (a : α) (f : α → WSeq β) : bind (ret a) f ~ʷ f a := by 

Proof state:
α : Type u
β : Type v
γ : Type w
a : α
f : α → WSeq β
⊢ bind (ret a) f ~ʷ f a

Next tactic:
simp [bind]
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
S : WSeq (WSeq α)
⊢ map f (join S) = join (map (map f) S)

Next tactic:
apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · 

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
f : α → β
S : WSeq (WSeq α)
⊢ Seq.IsBisimulation fun s1 s2 => ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))

Next tactic:
intro s1 s2 h
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
f : α → β
S : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
⊢ Seq.BisimO (fun s1 s2 => ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S)))
    (Seq.destruct s1) (Seq.destruct s2)

Next tactic:
exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> simp
        · exact ⟨_, _, rfl, rfl⟩
        · exact ⟨_, _, rfl, rfl⟩
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
s : WSeq β
S : WSeq (WSeq α)
⊢ Seq.BisimO (fun s1 s2 => ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S)))
    (Seq.destruct (append s (map f (join S)))) (Seq.destruct (append s (join (map (map f) S))))

Next tactic:
induction' s using WSeq.recOn with a s s
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
⊢ Seq.BisimO (fun s1 s2 => ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S)))
    (Seq.destruct (append nil (map f (join S)))) (Seq.destruct (append nil (join (map (map f) S))))

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
a : β
s : WSeq β
⊢ Seq.BisimO (fun s1 s2 => ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S)))
    (Seq.destruct (append (cons a s) (map f (join S)))) (Seq.destruct (append (cons a s) (join (map (map f) S))))

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> 

Proof state:
case h3
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
s : WSeq β
⊢ Seq.BisimO (fun s1 s2 => ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S)))
    (Seq.destruct (append (think s) (map f (join S)))) (Seq.destruct (append (think s) (join (map (map f) S))))

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
⊢ match Seq.destruct (map f (join S)), Seq.destruct (join (map (map f) S)) with
  | none, none => True
  | some (a, s), some (a', s') =>
    a = a' ∧ ∃ s_1 S, s = append s_1 (map f (join S)) ∧ s' = append s_1 (join (map (map f) S))
  | x, x_1 => False

Next tactic:
induction' S using WSeq.recOn with s S S
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> 

Proof state:
case h1.h1
α : Type u
β : Type v
γ : Type w
f : α → β
S : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
⊢ match Seq.destruct (map f (join nil)), Seq.destruct (join (map (map f) nil)) with
  | none, none => True
  | some (a, s), some (a', s') =>
    a = a' ∧ ∃ s_1 S, s = append s_1 (map f (join S)) ∧ s' = append s_1 (join (map (map f) S))
  | x, x_1 => False

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> 

Proof state:
case h1.h2
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
s : WSeq α
S : WSeq (WSeq α)
⊢ match Seq.destruct (map f (join (cons s S))), Seq.destruct (join (map (map f) (cons s S))) with
  | none, none => True
  | some (a, s), some (a', s') =>
    a = a' ∧ ∃ s_1 S, s = append s_1 (map f (join S)) ∧ s' = append s_1 (join (map (map f) S))
  | x, x_1 => False

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> 

Proof state:
case h1.h3
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
⊢ match Seq.destruct (map f (join (think S))), Seq.destruct (join (map (map f) (think S))) with
  | none, none => True
  | some (a, s), some (a', s') =>
    a = a' ∧ ∃ s_1 S, s = append s_1 (map f (join S)) ∧ s' = append s_1 (join (map (map f) S))
  | x, x_1 => False

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · 

Proof state:
case h1.h2
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
s : WSeq α
S : WSeq (WSeq α)
⊢ ∃ s_1 S_1,
    append (map f s) (map f (join S)) = append s_1 (map f (join S_1)) ∧
      append (map f s) (join (map (map f) S)) = append s_1 (join (map (map f) S_1))

Next tactic:
exact ⟨map f s, S, rfl, rfl⟩
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · 

Proof state:
case h1.h3
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
⊢ ∃ s S_1, map f (join S) = append s (map f (join S_1)) ∧ join (map (map f) S) = append s (join (map (map f) S_1))

Next tactic:
refine' ⟨nil, S, _, _⟩
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> 

Proof state:
case h1.h3.refine'_1
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
⊢ map f (join S) = append nil (map f (join S))

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> 

Proof state:
case h1.h3.refine'_2
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
⊢ join (map (map f) S) = append nil (join (map (map f) S))

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> simp
        · 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
a : β
s : WSeq β
⊢ ∃ s_1 S_1,
    append s (map f (join S)) = append s_1 (map f (join S_1)) ∧
      append s (join (map (map f) S)) = append s_1 (join (map (map f) S_1))

Next tactic:
exact ⟨_, _, rfl, rfl⟩
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> simp
        · exact ⟨_, _, rfl, rfl⟩
        · 

Proof state:
case h3
α : Type u
β : Type v
γ : Type w
f : α → β
S✝ : WSeq (WSeq α)
s1 s2 : Seq (Option β)
h : ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
S : WSeq (WSeq α)
s : WSeq β
⊢ ∃ s_1 S_1,
    append s (map f (join S)) = append s_1 (map f (join S_1)) ∧
      append s (join (map (map f) S)) = append s_1 (join (map (map f) S_1))

Next tactic:
exact ⟨_, _, rfl, rfl⟩
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> simp
        · exact ⟨_, _, rfl, rfl⟩
        · exact ⟨_, _, rfl, rfl⟩
  · 

Proof state:
case r
α : Type u
β : Type v
γ : Type w
f : α → β
S : WSeq (WSeq α)
⊢ ∃ s S_1, map f (join S) = append s (map f (join S_1)) ∧ join (map (map f) S) = append s (join (map (map f) S_1))

Next tactic:
refine' ⟨nil, S, _, _⟩
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> simp
        · exact ⟨_, _, rfl, rfl⟩
        · exact ⟨_, _, rfl, rfl⟩
  · refine' ⟨nil, S, _, _⟩ <;> 

Proof state:
case r.refine'_1
α : Type u
β : Type v
γ : Type w
f : α → β
S : WSeq (WSeq α)
⊢ map f (join S) = append nil (map f (join S))

Next tactic:
simp
@[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) := by
  apply
    Seq.eq_of_bisim fun s1 s2 =>
      ∃ s S, s1 = append s (map f (join S)) ∧ s2 = append s (join (map (map f) S))
  · intro s1 s2 h
    exact
      match s1, s2, h with
      | _, _, ⟨s, S, rfl, rfl⟩ => by
        induction' s using WSeq.recOn with a s s <;> simp
        · induction' S using WSeq.recOn with s S S <;> simp
          · exact ⟨map f s, S, rfl, rfl⟩
          · refine' ⟨nil, S, _, _⟩ <;> simp
        · exact ⟨_, _, rfl, rfl⟩
        · exact ⟨_, _, rfl, rfl⟩
  · refine' ⟨nil, S, _, _⟩ <;> 

Proof state:
case r.refine'_2
α : Type u
β : Type v
γ : Type w
f : α → β
S : WSeq (WSeq α)
⊢ join (map (map f) S) = append nil (join (map (map f) S))

Next tactic:
simp
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
SS : WSeq (WSeq (WSeq α))
⊢ join (join SS) ~ʷ join (map join SS)

Next tactic:
refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by simp, by simp⟩, _⟩
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by 

Proof state:
α : Type u
β : Type v
γ : Type w
SS : WSeq (WSeq (WSeq α))
⊢ join (join SS) = append nil (join (append nil (join SS)))

Next tactic:
simp
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by simp, by 

Proof state:
α : Type u
β : Type v
γ : Type w
SS : WSeq (WSeq (WSeq α))
⊢ join (map join SS) = append nil (append (join nil) (join (map join SS)))

Next tactic:
simp
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by simp, by simp⟩, _⟩
  

Proof state:
α : Type u
β : Type v
γ : Type w
SS : WSeq (WSeq (WSeq α))
⊢ ∀ {s t : WSeq α},
    (fun s1 s2 =>
          ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS))))
        s t →
      Computation.LiftRel
        (LiftRelO (fun x x_1 => x = x_1) fun s1 s2 =>
          ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS))))
        (destruct s) (destruct t)

Next tactic:
intro s1 s2 h
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by simp, by simp⟩, _⟩
  intro s1 s2 h
  

Proof state:
α : Type u
β : Type v
γ : Type w
SS : WSeq (WSeq (WSeq α))
s1 s2 : WSeq α
h : ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS)))
⊢ Computation.LiftRel
    (LiftRelO (fun x x_1 => x = x_1) fun s1 s2 =>
      ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS))))
    (destruct s1) (destruct s2)

Next tactic:
apply
    liftRel_rec
      (fun c1 c2 =>
        ∃ s S SS,
          c1 = destruct (append s (join (append S (join SS)))) ∧
            c2 = destruct (append s (append (join S) (join (map join SS)))))
      _ (destruct s1) (destruct s2)
      (let ⟨s, S, SS, h1, h2⟩ := h
      ⟨s, S, SS, by simp [h1], by simp [h2]⟩)
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by simp, by simp⟩, _⟩
  intro s1 s2 h
  apply
    liftRel_rec
      (fun c1 c2 =>
        ∃ s S SS,
          c1 = destruct (append s (join (append S (join SS)))) ∧
            c2 = destruct (append s (append (join S) (join (map join SS)))))
      _ (destruct s1) (destruct s2)
      (let ⟨s, S, SS, h1, h2⟩ := h
      ⟨s, S, SS, by 

Proof state:
α : Type u
β : Type v
γ : Type w
SS✝ : WSeq (WSeq (WSeq α))
s1 s2 : WSeq α
h : ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS)))
s : WSeq α
S : WSeq (WSeq α)
SS : WSeq (WSeq (WSeq α))
h1 : s1 = append s (join (append S (join SS)))
h2 : s2 = append s (append (join S) (join (map join SS)))
⊢ destruct s1 = destruct (append s (join (append S (join SS))))

Next tactic:
simp [h1]
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by simp, by simp⟩, _⟩
  intro s1 s2 h
  apply
    liftRel_rec
      (fun c1 c2 =>
        ∃ s S SS,
          c1 = destruct (append s (join (append S (join SS)))) ∧
            c2 = destruct (append s (append (join S) (join (map join SS)))))
      _ (destruct s1) (destruct s2)
      (let ⟨s, S, SS, h1, h2⟩ := h
      ⟨s, S, SS, by simp [h1], by 

Proof state:
α : Type u
β : Type v
γ : Type w
SS✝ : WSeq (WSeq (WSeq α))
s1 s2 : WSeq α
h : ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS)))
s : WSeq α
S : WSeq (WSeq α)
SS : WSeq (WSeq (WSeq α))
h1 : s1 = append s (join (append S (join SS)))
h2 : s2 = append s (append (join S) (join (map join SS)))
⊢ destruct s2 = destruct (append s (append (join S) (join (map join SS))))

Next tactic:
simp [h2]
@[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) := by
  refine'
    ⟨fun s1 s2 =>
      ∃ s S SS,
        s1 = append s (join (append S (join SS))) ∧
          s2 = append s (append (join S) (join (map join SS))),
      ⟨nil, nil, SS, by simp, by simp⟩, _⟩
  intro s1 s2 h
  apply
    liftRel_rec
      (fun c1 c2 =>
        ∃ s S SS,
          c1 = destruct (append s (join (append S (join SS)))) ∧
            c2 = destruct (append s (append (join S) (join (map join SS)))))
      _ (destruct s1) (destruct s2)
      (let ⟨s, S, SS, h1, h2⟩ := h
      ⟨s, S, SS, by simp [h1], by simp [h2]⟩)
  

Proof state:
α : Type u
β : Type v
γ : Type w
SS : WSeq (WSeq (WSeq α))
s1 s2 : WSeq α
h : ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS)))
⊢ ∀ {ca cb : Computation (Option (α × WSeq α))},
    (fun c1 c2 =>
          ∃ s S SS,
            c1 = destruct (append s (join (append S (join SS)))) ∧
              c2 = destruct (append s (append (join S) (join (map join SS)))))
        ca cb →
      LiftRelAux
        (LiftRelO (fun x x_1 => x = x_1) fun s1 s2 =>
          ∃ s S SS, s1 = append s (join (append S (join SS))) ∧ s2 = append s (append (join S) (join (map join SS))))
        (fun c1 c2 =>
          ∃ s S SS,
            c1 = destruct (append s (join (append S (join SS)))) ∧
              c2 = destruct (append s (append (join S) (join (map join SS)))))
        (Computation.destruct ca) (Computation.destruct cb)

Next tactic:
intro c1 c2 h