l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by
  apply eq_of_bisim (fun c₁ c₂ => (c₂ <|> empty α) = c₁) _ rfl
  intro s' s h; rw [← h]
  apply recOn s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
c s' s : Computation α
h : (HOrElse.hOrElse s fun x => empty α) = s'
⊢ ∀ (a : α),
    BisimO (fun c₁ c₂ => (HOrElse.hOrElse c₂ fun x => empty α) = c₁)
      (destruct (HOrElse.hOrElse (pure a) fun x => empty α)) (destruct (pure a))

Next tactic:
intro s
@[simp]
theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by
  apply eq_of_bisim (fun c₁ c₂ => (c₂ <|> empty α) = c₁) _ rfl
  intro s' s h; rw [← h]
  apply recOn s <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
c s' s : Computation α
h : (HOrElse.hOrElse s fun x => empty α) = s'
⊢ ∀ (s : Computation α),
    BisimO (fun c₁ c₂ => (HOrElse.hOrElse c₂ fun x => empty α) = c₁)
      (destruct (HOrElse.hOrElse (think s) fun x => empty α)) (destruct (think s))

Next tactic:
intro s
@[simp]
theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by
  apply eq_of_bisim (fun c₁ c₂ => (c₂ <|> empty α) = c₁) _ rfl
  intro s' s h; rw [← h]
  apply recOn s <;> intro s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
c s' s✝ : Computation α
h : (HOrElse.hOrElse s✝ fun x => empty α) = s'
s : α
⊢ BisimO (fun c₁ c₂ => (HOrElse.hOrElse c₂ fun x => empty α) = c₁)
    (destruct (HOrElse.hOrElse (pure s) fun x => empty α)) (destruct (pure s))

Next tactic:
rw [think_empty]
@[simp]
theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by
  apply eq_of_bisim (fun c₁ c₂ => (c₂ <|> empty α) = c₁) _ rfl
  intro s' s h; rw [← h]
  apply recOn s <;> intro s <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
c s' s✝ : Computation α
h : (HOrElse.hOrElse s✝ fun x => empty α) = s'
s : Computation α
⊢ BisimO (fun c₁ c₂ => (HOrElse.hOrElse c₂ fun x => empty α) = c₁)
    (destruct (HOrElse.hOrElse (think s) fun x => empty α)) (destruct (think s))

Next tactic:
rw [think_empty]
@[simp]
theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by
  apply eq_of_bisim (fun c₁ c₂ => (c₂ <|> empty α) = c₁) _ rfl
  intro s' s h; rw [← h]
  apply recOn s <;> intro s <;> rw [think_empty] <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
c s' s✝ : Computation α
h : (HOrElse.hOrElse s✝ fun x => empty α) = s'
s : α
⊢ BisimO (fun c₁ c₂ => (HOrElse.hOrElse c₂ fun x => think (empty α)) = c₁)
    (destruct (HOrElse.hOrElse (pure s) fun x => think (empty α))) (destruct (pure s))

Next tactic:
simp
@[simp]
theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by
  apply eq_of_bisim (fun c₁ c₂ => (c₂ <|> empty α) = c₁) _ rfl
  intro s' s h; rw [← h]
  apply recOn s <;> intro s <;> rw [think_empty] <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
c s' s✝ : Computation α
h : (HOrElse.hOrElse s✝ fun x => empty α) = s'
s : Computation α
⊢ BisimO (fun c₁ c₂ => (HOrElse.hOrElse c₂ fun x => think (empty α)) = c₁)
    (destruct (HOrElse.hOrElse (think s) fun x => think (empty α))) (destruct (think s))

Next tactic:
simp
@[simp]
theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by
  apply eq_of_bisim (fun c₁ c₂ => (c₂ <|> empty α) = c₁) _ rfl
  intro s' s h; rw [← h]
  apply recOn s <;> intro s <;> rw [think_empty] <;> simp
  

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
c s' s✝ : Computation α
h : (HOrElse.hOrElse s✝ fun x => empty α) = s'
s : Computation α
⊢ (HOrElse.hOrElse s fun x => think (empty α)) = HOrElse.hOrElse s fun x => empty α

Next tactic:
rw [← think_empty]
theorem equiv_of_mem {s t : Computation α} {a} (h1 : a ∈ s) (h2 : a ∈ t) : s ~ t := fun a' =>
  ⟨fun ma => by 

Proof state:
α : Type u
β : Type v
γ : Type w
s t : Computation α
a : α
h1 : a ∈ s
h2 : a ∈ t
a' : α
ma : a' ∈ s
⊢ a' ∈ t

Next tactic:
rw [mem_unique ma h1]
theorem equiv_of_mem {s t : Computation α} {a} (h1 : a ∈ s) (h2 : a ∈ t) : s ~ t := fun a' =>
  ⟨fun ma => by rw [mem_unique ma h1]; 

Proof state:
α : Type u
β : Type v
γ : Type w
s t : Computation α
a : α
h1 : a ∈ s
h2 : a ∈ t
a' : α
ma : a' ∈ s
⊢ a ∈ t

Next tactic:
exact h2
theorem equiv_of_mem {s t : Computation α} {a} (h1 : a ∈ s) (h2 : a ∈ t) : s ~ t := fun a' =>
  ⟨fun ma => by rw [mem_unique ma h1]; exact h2, fun ma => by 

Proof state:
α : Type u
β : Type v
γ : Type w
s t : Computation α
a : α
h1 : a ∈ s
h2 : a ∈ t
a' : α
ma : a' ∈ t
⊢ a' ∈ s

Next tactic:
rw [mem_unique ma h2]
theorem equiv_of_mem {s t : Computation α} {a} (h1 : a ∈ s) (h2 : a ∈ t) : s ~ t := fun a' =>
  ⟨fun ma => by rw [mem_unique ma h1]; exact h2, fun ma => by rw [mem_unique ma h2]; 

Proof state:
α : Type u
β : Type v
γ : Type w
s t : Computation α
a : α
h1 : a ∈ s
h2 : a ∈ t
a' : α
ma : a' ∈ t
⊢ a ∈ s

Next tactic:
exact h1
theorem terminates_congr {c₁ c₂ : Computation α} (h : c₁ ~ c₂) : Terminates c₁ ↔ Terminates c₂ := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
c₁ c₂ : Computation α
h : c₁ ~ c₂
⊢ Terminates c₁ ↔ Terminates c₂

Next tactic:
simp only [terminates_iff, exists_congr h]
theorem lift_eq_iff_equiv (c₁ c₂ : Computation α) : LiftRel (· = ·) c₁ c₂ ↔ c₁ ~ c₂ :=
  ⟨fun ⟨h1, h2⟩ a =>
    ⟨fun a1 => by 

Proof state:
α : Type u
β : Type v
γ : Type w
c₁ c₂ : Computation α
x✝ : LiftRel (fun x x_1 => x = x_1) c₁ c₂
a : α
h1 : ∀ {a : α}, a ∈ c₁ → ∃ b, b ∈ c₂ ∧ (fun x x_1 => x = x_1) a b
h2 : ∀ {b : α}, b ∈ c₂ → ∃ a, a ∈ c₁ ∧ (fun x x_1 => x = x_1) a b
a1 : a ∈ c₁
⊢ a ∈ c₂

Next tactic:
let ⟨b, b2, ab⟩ := h1 a1
theorem lift_eq_iff_equiv (c₁ c₂ : Computation α) : LiftRel (· = ·) c₁ c₂ ↔ c₁ ~ c₂ :=
  ⟨fun ⟨h1, h2⟩ a =>
    ⟨fun a1 => by let ⟨b, b2, ab⟩ := h1 a1; 

Proof state:
α : Type u
β : Type v
γ : Type w
c₁ c₂ : Computation α
x✝ : LiftRel (fun x x_1 => x = x_1) c₁ c₂
a : α
h1 : ∀ {a : α}, a ∈ c₁ → ∃ b, b ∈ c₂ ∧ (fun x x_1 => x = x_1) a b
h2 : ∀ {b : α}, b ∈ c₂ → ∃ a, a ∈ c₁ ∧ (fun x x_1 => x = x_1) a b
a1 : a ∈ c₁
b : α
b2 : b ∈ c₂
ab : (fun x x_1 => x = x_1) a b
⊢ a ∈ c₂

Next tactic:
rwa [ab]
theorem lift_eq_iff_equiv (c₁ c₂ : Computation α) : LiftRel (· = ·) c₁ c₂ ↔ c₁ ~ c₂ :=
  ⟨fun ⟨h1, h2⟩ a =>
    ⟨fun a1 => by let ⟨b, b2, ab⟩ := h1 a1; rwa [ab],
     fun a2 => by 

Proof state:
α : Type u
β : Type v
γ : Type w
c₁ c₂ : Computation α
x✝ : LiftRel (fun x x_1 => x = x_1) c₁ c₂
a : α
h1 : ∀ {a : α}, a ∈ c₁ → ∃ b, b ∈ c₂ ∧ (fun x x_1 => x = x_1) a b
h2 : ∀ {b : α}, b ∈ c₂ → ∃ a, a ∈ c₁ ∧ (fun x x_1 => x = x_1) a b
a2 : a ∈ c₂
⊢ a ∈ c₁

Next tactic:
let ⟨b, b1, ab⟩ := h2 a2
theorem lift_eq_iff_equiv (c₁ c₂ : Computation α) : LiftRel (· = ·) c₁ c₂ ↔ c₁ ~ c₂ :=
  ⟨fun ⟨h1, h2⟩ a =>
    ⟨fun a1 => by let ⟨b, b2, ab⟩ := h1 a1; rwa [ab],
     fun a2 => by let ⟨b, b1, ab⟩ := h2 a2; 

Proof state:
α : Type u
β : Type v
γ : Type w
c₁ c₂ : Computation α
x✝ : LiftRel (fun x x_1 => x = x_1) c₁ c₂
a : α
h1 : ∀ {a : α}, a ∈ c₁ → ∃ b, b ∈ c₂ ∧ (fun x x_1 => x = x_1) a b
h2 : ∀ {b : α}, b ∈ c₂ → ∃ a, a ∈ c₁ ∧ (fun x x_1 => x = x_1) a b
a2 : a ∈ c₂
b : α
b1 : b ∈ c₁
ab : (fun x x_1 => x = x_1) b a
⊢ a ∈ c₁

Next tactic:
rwa [← ab]
theorem LiftRel.equiv (R : α → α → Prop) : Equivalence R → Equivalence (LiftRel R)
  | ⟨refl, symm, trans⟩ => ⟨LiftRel.refl R refl, by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → α → Prop
refl : ∀ (x : α), R x x
symm : ∀ {x y : α}, R x y → R y x
trans : ∀ {x y z : α}, R x y → R y z → R x z
⊢ ∀ {x y : Computation α}, LiftRel R x y → LiftRel R y x

Next tactic:
apply LiftRel.symm
theorem LiftRel.equiv (R : α → α → Prop) : Equivalence R → Equivalence (LiftRel R)
  | ⟨refl, symm, trans⟩ => ⟨LiftRel.refl R refl, by apply LiftRel.symm; 

Proof state:
case H
α : Type u
β : Type v
γ : Type w
R : α → α → Prop
refl : ∀ (x : α), R x x
symm : ∀ {x y : α}, R x y → R y x
trans : ∀ {x y z : α}, R x y → R y z → R x z
⊢ Symmetric R

Next tactic:
apply symm
theorem LiftRel.equiv (R : α → α → Prop) : Equivalence R → Equivalence (LiftRel R)
  | ⟨refl, symm, trans⟩ => ⟨LiftRel.refl R refl, by apply LiftRel.symm; apply symm,
    by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → α → Prop
refl : ∀ (x : α), R x x
symm : ∀ {x y : α}, R x y → R y x
trans : ∀ {x y z : α}, R x y → R y z → R x z
⊢ ∀ {x y z : Computation α}, LiftRel R x y → LiftRel R y z → LiftRel R x z

Next tactic:
apply LiftRel.trans
theorem LiftRel.equiv (R : α → α → Prop) : Equivalence R → Equivalence (LiftRel R)
  | ⟨refl, symm, trans⟩ => ⟨LiftRel.refl R refl, by apply LiftRel.symm; apply symm,
    by apply LiftRel.trans; 

Proof state:
case H
α : Type u
β : Type v
γ : Type w
R : α → α → Prop
refl : ∀ (x : α), R x x
symm : ∀ {x y : α}, R x y → R y x
trans : ∀ {x y z : α}, R x y → R y z → R x z
⊢ Transitive R

Next tactic:
apply trans
theorem rel_of_liftRel {R : α → β → Prop} {ca cb} :
    LiftRel R ca cb → ∀ {a b}, a ∈ ca → b ∈ cb → R a b
  | ⟨l, _⟩, a, b, ma, mb => by
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
cb : Computation β
l : ∀ {a : α}, a ∈ ca → ∃ b, b ∈ cb ∧ R a b
right✝ : ∀ {b : β}, b ∈ cb → ∃ a, a ∈ ca ∧ R a b
a : α
b : β
ma : a ∈ ca
mb : b ∈ cb
⊢ R a b

Next tactic:
let ⟨b', mb', ab'⟩ := l ma
theorem rel_of_liftRel {R : α → β → Prop} {ca cb} :
    LiftRel R ca cb → ∀ {a b}, a ∈ ca → b ∈ cb → R a b
  | ⟨l, _⟩, a, b, ma, mb => by
    let ⟨b', mb', ab'⟩ := l ma
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
cb : Computation β
l : ∀ {a : α}, a ∈ ca → ∃ b, b ∈ cb ∧ R a b
right✝ : ∀ {b : β}, b ∈ cb → ∃ a, a ∈ ca ∧ R a b
a : α
b : β
ma : a ∈ ca
mb : b ∈ cb
b' : β
mb' : b' ∈ cb
ab' : R a b'
⊢ R a b

Next tactic:
rw [mem_unique mb mb']
theorem rel_of_liftRel {R : α → β → Prop} {ca cb} :
    LiftRel R ca cb → ∀ {a b}, a ∈ ca → b ∈ cb → R a b
  | ⟨l, _⟩, a, b, ma, mb => by
    let ⟨b', mb', ab'⟩ := l ma
    rw [mem_unique mb mb']; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
cb : Computation β
l : ∀ {a : α}, a ∈ ca → ∃ b, b ∈ cb ∧ R a b
right✝ : ∀ {b : β}, b ∈ cb → ∃ a, a ∈ ca ∧ R a b
a : α
b : β
ma : a ∈ ca
mb : b ∈ cb
b' : β
mb' : b' ∈ cb
ab' : R a b'
⊢ R a b'

Next tactic:
exact ab'
theorem liftRel_of_mem {R : α → β → Prop} {a b ca cb} (ma : a ∈ ca) (mb : b ∈ cb) (ab : R a b) :
    LiftRel R ca cb :=
  ⟨fun {a'} ma' => by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
b : β
ca : Computation α
cb : Computation β
ma : a ∈ ca
mb : b ∈ cb
ab : R a b
a' : α
ma' : a' ∈ ca
⊢ ∃ b, b ∈ cb ∧ R a' b

Next tactic:
rw [mem_unique ma' ma]
theorem liftRel_of_mem {R : α → β → Prop} {a b ca cb} (ma : a ∈ ca) (mb : b ∈ cb) (ab : R a b) :
    LiftRel R ca cb :=
  ⟨fun {a'} ma' => by rw [mem_unique ma' ma]; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
b : β
ca : Computation α
cb : Computation β
ma : a ∈ ca
mb : b ∈ cb
ab : R a b
a' : α
ma' : a' ∈ ca
⊢ ∃ b, b ∈ cb ∧ R a b

Next tactic:
exact ⟨b, mb, ab⟩
theorem liftRel_of_mem {R : α → β → Prop} {a b ca cb} (ma : a ∈ ca) (mb : b ∈ cb) (ab : R a b) :
    LiftRel R ca cb :=
  ⟨fun {a'} ma' => by rw [mem_unique ma' ma]; exact ⟨b, mb, ab⟩, fun {b'} mb' => by
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
b : β
ca : Computation α
cb : Computation β
ma : a ∈ ca
mb : b ∈ cb
ab : R a b
b' : β
mb' : b' ∈ cb
⊢ ∃ a, a ∈ ca ∧ R a b'

Next tactic:
rw [mem_unique mb' mb]
theorem liftRel_of_mem {R : α → β → Prop} {a b ca cb} (ma : a ∈ ca) (mb : b ∈ cb) (ab : R a b) :
    LiftRel R ca cb :=
  ⟨fun {a'} ma' => by rw [mem_unique ma' ma]; exact ⟨b, mb, ab⟩, fun {b'} mb' => by
    rw [mem_unique mb' mb]; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
b : β
ca : Computation α
cb : Computation β
ma : a ∈ ca
mb : b ∈ cb
ab : R a b
b' : β
mb' : b' ∈ cb
⊢ ∃ a, a ∈ ca ∧ R a b

Next tactic:
exact ⟨a, ma, ab⟩
theorem liftRel_def {R : α → β → Prop} {ca cb} :
    LiftRel R ca cb ↔ (Terminates ca ↔ Terminates cb) ∧ ∀ {a b}, a ∈ ca → b ∈ cb → R a b :=
  ⟨fun h =>
    ⟨terminates_of_liftRel h, fun {a b} ma mb => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
cb : Computation β
h : LiftRel R ca cb
a : α
b : β
ma : a ∈ ca
mb : b ∈ cb
⊢ R a b

Next tactic:
let ⟨b', mb', ab⟩ := h.left ma
theorem liftRel_def {R : α → β → Prop} {ca cb} :
    LiftRel R ca cb ↔ (Terminates ca ↔ Terminates cb) ∧ ∀ {a b}, a ∈ ca → b ∈ cb → R a b :=
  ⟨fun h =>
    ⟨terminates_of_liftRel h, fun {a b} ma mb => by
      let ⟨b', mb', ab⟩ := h.left ma
      

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
cb : Computation β
h : LiftRel R ca cb
a : α
b : β
ma : a ∈ ca
mb : b ∈ cb
b' : β
mb' : b' ∈ cb
ab : R a b'
⊢ R a b

Next tactic:
rwa [mem_unique mb mb']
@[simp]
theorem liftRel_pure_left (R : α → β → Prop) (a : α) (cb : Computation β) :
    LiftRel R (pure a) cb ↔ ∃ b, b ∈ cb ∧ R a b :=
  ⟨fun ⟨l, _⟩ => l (ret_mem _), fun ⟨b, mb, ab⟩ =>
    ⟨fun {a'} ma' => by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
cb : Computation β
x✝ : ∃ b, b ∈ cb ∧ R a b
b : β
mb : b ∈ cb
ab : R a b
a' : α
ma' : a' ∈ pure a
⊢ ∃ b, b ∈ cb ∧ R a' b

Next tactic:
rw [eq_of_pure_mem ma']
@[simp]
theorem liftRel_pure_left (R : α → β → Prop) (a : α) (cb : Computation β) :
    LiftRel R (pure a) cb ↔ ∃ b, b ∈ cb ∧ R a b :=
  ⟨fun ⟨l, _⟩ => l (ret_mem _), fun ⟨b, mb, ab⟩ =>
    ⟨fun {a'} ma' => by rw [eq_of_pure_mem ma']; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
cb : Computation β
x✝ : ∃ b, b ∈ cb ∧ R a b
b : β
mb : b ∈ cb
ab : R a b
a' : α
ma' : a' ∈ pure a
⊢ ∃ b, b ∈ cb ∧ R a b

Next tactic:
exact ⟨b, mb, ab⟩
@[simp]
theorem liftRel_pure_left (R : α → β → Prop) (a : α) (cb : Computation β) :
    LiftRel R (pure a) cb ↔ ∃ b, b ∈ cb ∧ R a b :=
  ⟨fun ⟨l, _⟩ => l (ret_mem _), fun ⟨b, mb, ab⟩ =>
    ⟨fun {a'} ma' => by rw [eq_of_pure_mem ma']; exact ⟨b, mb, ab⟩, fun {b'} mb' =>
      ⟨_, ret_mem _, by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
cb : Computation β
x✝ : ∃ b, b ∈ cb ∧ R a b
b : β
mb : b ∈ cb
ab : R a b
b' : β
mb' : b' ∈ cb
⊢ R a b'

Next tactic:
rw [mem_unique mb' mb]
@[simp]
theorem liftRel_pure_left (R : α → β → Prop) (a : α) (cb : Computation β) :
    LiftRel R (pure a) cb ↔ ∃ b, b ∈ cb ∧ R a b :=
  ⟨fun ⟨l, _⟩ => l (ret_mem _), fun ⟨b, mb, ab⟩ =>
    ⟨fun {a'} ma' => by rw [eq_of_pure_mem ma']; exact ⟨b, mb, ab⟩, fun {b'} mb' =>
      ⟨_, ret_mem _, by rw [mem_unique mb' mb]; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
cb : Computation β
x✝ : ∃ b, b ∈ cb ∧ R a b
b : β
mb : b ∈ cb
ab : R a b
b' : β
mb' : b' ∈ cb
⊢ R a b

Next tactic:
exact ab
@[simp]
theorem liftRel_pure_right (R : α → β → Prop) (ca : Computation α) (b : β) :
    LiftRel R ca (pure b) ↔ ∃ a, a ∈ ca ∧ R a b := by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
b : β
⊢ LiftRel R ca (pure b) ↔ ∃ a, a ∈ ca ∧ R a b

Next tactic:
rw [LiftRel.swap, liftRel_pure_left]
@[simp, nolint simpNF]
theorem liftRel_pure (R : α → β → Prop) (a : α) (b : β) :
    LiftRel R (pure a) (pure b) ↔ R a b := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
b : β
⊢ LiftRel R (pure a) (pure b) ↔ R a b

Next tactic:
rw [liftRel_pure_left]
@[simp, nolint simpNF]
theorem liftRel_pure (R : α → β → Prop) (a : α) (b : β) :
    LiftRel R (pure a) (pure b) ↔ R a b := by
  rw [liftRel_pure_left]
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
b : β
⊢ (∃ b_1, b_1 ∈ pure b ∧ R a b_1) ↔ R a b

Next tactic:
exact ⟨fun ⟨b', mb', ab'⟩ => by rwa [eq_of_pure_mem mb'] at ab', fun ab => ⟨_, ret_mem _, ab⟩⟩
@[simp, nolint simpNF]
theorem liftRel_pure (R : α → β → Prop) (a : α) (b : β) :
    LiftRel R (pure a) (pure b) ↔ R a b := by
  rw [liftRel_pure_left]
  exact ⟨fun ⟨b', mb', ab'⟩ => by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
a : α
b : β
x✝ : ∃ b_1, b_1 ∈ pure b ∧ R a b_1
b' : β
mb' : b' ∈ pure b
ab' : R a b'
⊢ R a b

Next tactic:
rwa [eq_of_pure_mem mb'] at ab'
@[simp]
theorem liftRel_think_right (R : α → β → Prop) (ca : Computation α) (cb : Computation β) :
    LiftRel R ca (think cb) ↔ LiftRel R ca cb := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
cb : Computation β
⊢ LiftRel R ca (think cb) ↔ LiftRel R ca cb

Next tactic:
rw [← LiftRel.swap R, ← LiftRel.swap R]
@[simp]
theorem liftRel_think_right (R : α → β → Prop) (ca : Computation α) (cb : Computation β) :
    LiftRel R ca (think cb) ↔ LiftRel R ca cb := by
  rw [← LiftRel.swap R, ← LiftRel.swap R]; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
ca : Computation α
cb : Computation β
⊢ LiftRel (swap R) (think cb) ca ↔ LiftRel (swap R) cb ca

Next tactic:
apply liftRel_think_left
theorem liftRel_map {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : Computation α}
    {s2 : Computation β} {f1 : α → γ} {f2 : β → δ} (h1 : LiftRel R s1 s2)
    (h2 : ∀ {a b}, R a b → S (f1 a) (f2 b)) : LiftRel S (map f1 s1) (map f2 s2) := by
  -- Porting note: The line below was:
  -- rw [← bind_pure, ← bind_pure]; apply lift_rel_bind _ _ h1; simp; exact @h2
  --
  -- The code fails to work on the last exact.
  

Proof state:
α : Type u
β : Type v
γ : Type w
δ : Type u_1
R : α → β → Prop
S : γ → δ → Prop
s1 : Computation α
s2 : Computation β
f1 : α → γ
f2 : β → δ
h1 : LiftRel R s1 s2
h2 : ∀ {a : α} {b : β}, R a b → S (f1 a) (f2 b)
⊢ LiftRel S (map f1 s1) (map f2 s2)

Next tactic:
rw [← bind_pure, ← bind_pure]
theorem liftRel_map {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : Computation α}
    {s2 : Computation β} {f1 : α → γ} {f2 : β → δ} (h1 : LiftRel R s1 s2)
    (h2 : ∀ {a b}, R a b → S (f1 a) (f2 b)) : LiftRel S (map f1 s1) (map f2 s2) := by
  -- Porting note: The line below was:
  -- rw [← bind_pure, ← bind_pure]; apply lift_rel_bind _ _ h1; simp; exact @h2
  --
  -- The code fails to work on the last exact.
  rw [← bind_pure, ← bind_pure]; 

Proof state:
α : Type u
β : Type v
γ : Type w
δ : Type u_1
R : α → β → Prop
S : γ → δ → Prop
s1 : Computation α
s2 : Computation β
f1 : α → γ
f2 : β → δ
h1 : LiftRel R s1 s2
h2 : ∀ {a : α} {b : β}, R a b → S (f1 a) (f2 b)
⊢ LiftRel S (bind s1 (pure ∘ f1)) (bind s2 (pure ∘ f2))

Next tactic:
apply liftRel_bind _ _ h1
theorem liftRel_map {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : Computation α}
    {s2 : Computation β} {f1 : α → γ} {f2 : β → δ} (h1 : LiftRel R s1 s2)
    (h2 : ∀ {a b}, R a b → S (f1 a) (f2 b)) : LiftRel S (map f1 s1) (map f2 s2) := by
  -- Porting note: The line below was:
  -- rw [← bind_pure, ← bind_pure]; apply lift_rel_bind _ _ h1; simp; exact @h2
  --
  -- The code fails to work on the last exact.
  rw [← bind_pure, ← bind_pure]; apply liftRel_bind _ _ h1
  

Proof state:
α : Type u
β : Type v
γ : Type w
δ : Type u_1
R : α → β → Prop
S : γ → δ → Prop
s1 : Computation α
s2 : Computation β
f1 : α → γ
f2 : β → δ
h1 : LiftRel R s1 s2
h2 : ∀ {a : α} {b : β}, R a b → S (f1 a) (f2 b)
⊢ ∀ {a : α} {b : β}, R a b → LiftRel S ((pure ∘ f1) a) ((pure ∘ f2) b)

Next tactic:
simp only [comp_apply, liftRel_pure_right]
theorem liftRel_map {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : Computation α}
    {s2 : Computation β} {f1 : α → γ} {f2 : β → δ} (h1 : LiftRel R s1 s2)
    (h2 : ∀ {a b}, R a b → S (f1 a) (f2 b)) : LiftRel S (map f1 s1) (map f2 s2) := by
  -- Porting note: The line below was:
  -- rw [← bind_pure, ← bind_pure]; apply lift_rel_bind _ _ h1; simp; exact @h2
  --
  -- The code fails to work on the last exact.
  rw [← bind_pure, ← bind_pure]; apply liftRel_bind _ _ h1
  simp only [comp_apply, liftRel_pure_right]
  

Proof state:
α : Type u
β : Type v
γ : Type w
δ : Type u_1
R : α → β → Prop
S : γ → δ → Prop
s1 : Computation α
s2 : Computation β
f1 : α → γ
f2 : β → δ
h1 : LiftRel R s1 s2
h2 : ∀ {a : α} {b : β}, R a b → S (f1 a) (f2 b)
⊢ ∀ {a : α} {b : β}, R a b → ∃ a_2, a_2 ∈ pure (f1 a) ∧ S a_2 (f2 b)

Next tactic:
intros a b h
theorem liftRel_map {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : Computation α}
    {s2 : Computation β} {f1 : α → γ} {f2 : β → δ} (h1 : LiftRel R s1 s2)
    (h2 : ∀ {a b}, R a b → S (f1 a) (f2 b)) : LiftRel S (map f1 s1) (map f2 s2) := by
  -- Porting note: The line below was:
  -- rw [← bind_pure, ← bind_pure]; apply lift_rel_bind _ _ h1; simp; exact @h2
  --
  -- The code fails to work on the last exact.
  rw [← bind_pure, ← bind_pure]; apply liftRel_bind _ _ h1
  simp only [comp_apply, liftRel_pure_right]
  intros a b h; 

Proof state:
α : Type u
β : Type v
γ : Type w
δ : Type u_1
R : α → β → Prop
S : γ → δ → Prop
s1 : Computation α
s2 : Computation β
f1 : α → γ
f2 : β → δ
h1 : LiftRel R s1 s2
h2 : ∀ {a : α} {b : β}, R a b → S (f1 a) (f2 b)
a : α
b : β
h : R a b
⊢ ∃ a_1, a_1 ∈ pure (f1 a) ∧ S a_1 (f2 b)

Next tactic:
exact ⟨f1 a, ⟨ret_mem _, @h2 a b h⟩⟩
theorem map_congr {s1 s2 : Computation α} {f : α → β}
    (h1 : s1 ~ s2) : map f s1 ~ map f s2 := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
s1 s2 : Computation α
f : α → β
h1 : s1 ~ s2
⊢ map f s1 ~ map f s2

Next tactic:
rw [← lift_eq_iff_equiv]
theorem map_congr {s1 s2 : Computation α} {f : α → β}
    (h1 : s1 ~ s2) : map f s1 ~ map f s2 := by
  rw [← lift_eq_iff_equiv]
  

Proof state:
α : Type u
β : Type v
γ : Type w
s1 s2 : Computation α
f : α → β
h1 : s1 ~ s2
⊢ LiftRel (fun x x_1 => x = x_1) (map f s1) (map f s2)

Next tactic:
exact liftRel_map Eq _ ((lift_eq_iff_equiv _ _).2 h1) fun {a} b => congr_arg _
@[simp]
theorem LiftRelAux.ret_left (R : α → β → Prop) (C : Computation α → Computation β → Prop) (a cb) :
    LiftRelAux R C (Sum.inl a) (destruct cb) ↔ ∃ b, b ∈ cb ∧ R a b := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
C : Computation α → Computation β → Prop
a : α
cb : Computation β
⊢ LiftRelAux R C (Sum.inl a) (destruct cb) ↔ ∃ b, b ∈ cb ∧ R a b

Next tactic:
apply cb.recOn (fun b => _) fun cb => _
@[simp]
theorem LiftRelAux.ret_left (R : α → β → Prop) (C : Computation α → Computation β → Prop) (a cb) :
    LiftRelAux R C (Sum.inl a) (destruct cb) ↔ ∃ b, b ∈ cb ∧ R a b := by
  apply cb.recOn (fun b => _) fun cb => _
  · 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
C : Computation α → Computation β → Prop
a : α
cb : Computation β
⊢ ∀ (b : β), LiftRelAux R C (Sum.inl a) (destruct (pure b)) ↔ ∃ b_1, b_1 ∈ pure b ∧ R a b_1

Next tactic:
intro b
@[simp]
theorem LiftRelAux.ret_left (R : α → β → Prop) (C : Computation α → Computation β → Prop) (a cb) :
    LiftRelAux R C (Sum.inl a) (destruct cb) ↔ ∃ b, b ∈ cb ∧ R a b := by
  apply cb.recOn (fun b => _) fun cb => _
  · intro b
    

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
C : Computation α → Computation β → Prop
a : α
cb : Computation β
b : β
⊢ LiftRelAux R C (Sum.inl a) (destruct (pure b)) ↔ ∃ b_1, b_1 ∈ pure b ∧ R a b_1

Next tactic:
exact
      ⟨fun h => ⟨_, ret_mem _, h⟩, fun ⟨b', mb, h⟩ => by rw [mem_unique (ret_mem _) mb]; exact h⟩
@[simp]
theorem LiftRelAux.ret_left (R : α → β → Prop) (C : Computation α → Computation β → Prop) (a cb) :
    LiftRelAux R C (Sum.inl a) (destruct cb) ↔ ∃ b, b ∈ cb ∧ R a b := by
  apply cb.recOn (fun b => _) fun cb => _
  · intro b
    exact
      ⟨fun h => ⟨_, ret_mem _, h⟩, fun ⟨b', mb, h⟩ => by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
C : Computation α → Computation β → Prop
a : α
cb : Computation β
b : β
x✝ : ∃ b_1, b_1 ∈ pure b ∧ R a b_1
b' : β
mb : b' ∈ pure b
h : R a b'
⊢ LiftRelAux R C (Sum.inl a) (destruct (pure b))

Next tactic:
rw [mem_unique (ret_mem _) mb]
@[simp]
theorem LiftRelAux.ret_left (R : α → β → Prop) (C : Computation α → Computation β → Prop) (a cb) :
    LiftRelAux R C (Sum.inl a) (destruct cb) ↔ ∃ b, b ∈ cb ∧ R a b := by
  apply cb.recOn (fun b => _) fun cb => _
  · intro b
    exact
      ⟨fun h => ⟨_, ret_mem _, h⟩, fun ⟨b', mb, h⟩ => by rw [mem_unique (ret_mem _) mb]; 

Proof state:
α : Type u
β : Type v
γ : Type w
R : α → β → Prop
C : Computation α → Computation β → Prop
a : α
cb : Computation β
b : β
x✝ : ∃ b_1, b_1 ∈ pure b ∧ R a b_1
b' : β
mb : b' ∈ pure b
h : R a b'
⊢ LiftRelAux R C (Sum.inl a) (destruct (pure b'))

Next tactic:
exact h