l3lab/ntp-mathlib huggingface dataset:
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> 

Proof state:
case pos
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
x : α
h✝ : x = default
⊢ Option.elim' default Subtype.val none = x

Next tactic:
simp [*]
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> 

Proof state:
case neg
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
x : α
h✝ : ¬x = default
⊢ Option.elim' default Subtype.val (some { val := x, property := h✝ }) = x

Next tactic:
simp [*]
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> simp [*]
      right_inv := by
        

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
⊢ Function.RightInverse (Option.elim' default Subtype.val) fun x =>
    if h : x = default then none else some { val := x, property := h }

Next tactic:
rintro (_ | ⟨x, h⟩)
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> simp [*]
      right_inv := by
        rintro (_ | ⟨x, h⟩)
        · 

Proof state:
case none
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
⊢ (fun x => if h : x = default then none else some { val := x, property := h })
      (Option.elim' default Subtype.val none) =
    none

Next tactic:
simp
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> simp [*]
      right_inv := by
        rintro (_ | ⟨x, h⟩)
        · simp
        · 

Proof state:
case some.mk
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
x : α
h : x ≠ default
⊢ (fun x => if h : x = default then none else some { val := x, property := h })
      (Option.elim' default Subtype.val (some { val := x, property := h })) =
    some { val := x, property := h }

Next tactic:
dsimp only
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> simp [*]
      right_inv := by
        rintro (_ | ⟨x, h⟩)
        · simp
        · dsimp only
          

Proof state:
case some.mk
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
x : α
h : x ≠ default
⊢ (if h : Option.elim' default Subtype.val (some { val := x, property := h }) = default then none
    else some { val := Option.elim' default Subtype.val (some { val := x, property := h }), property := h }) =
    some { val := x, property := h }

Next tactic:
split_ifs with hi
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> simp [*]
      right_inv := by
        rintro (_ | ⟨x, h⟩)
        · simp
        · dsimp only
          split_ifs with hi
          · 

Proof state:
case pos
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
x : α
h : x ≠ default
hi : Option.elim' default Subtype.val (some { val := x, property := h }) = default
⊢ False

Next tactic:
simp [h] at hi
/--
Inhabited types are equivalent to `Option β` for some `β` by identifying `default α` with `none`.
-/
def sigmaEquivOptionOfInhabited (α : Type u) [Inhabited α] [DecidableEq α] :
    Σβ : Type u, α ≃ Option β :=
  ⟨{ x : α // x ≠ default },
    { toFun := fun x : α => if h : x = default then none else some ⟨x, h⟩
      invFun := Option.elim' default (↑)
      left_inv := fun x => by
        dsimp only
        split_ifs <;> simp [*]
      right_inv := by
        rintro (_ | ⟨x, h⟩)
        · simp
        · dsimp only
          split_ifs with hi
          · simp [h] at hi
          · 

Proof state:
case neg
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u
inst✝¹ : Inhabited α
inst✝ : DecidableEq α
x : α
h : x ≠ default
hi : ¬Option.elim' default Subtype.val (some { val := x, property := h }) = default
⊢ some { val := Option.elim' default Subtype.val (some { val := x, property := h }), property := hi } =
    some { val := x, property := h }

Next tactic:
simp
theorem disjoint_toFinset {m1 m2 : Multiset α} :
    _root_.Disjoint m1.toFinset m2.toFinset ↔ m1.Disjoint m2 := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
m1 m2 : Multiset α
⊢ _root_.Disjoint (toFinset m1) (toFinset m2) ↔ Disjoint m1 m2

Next tactic:
rw [Finset.disjoint_iff_ne]
theorem disjoint_toFinset {m1 m2 : Multiset α} :
    _root_.Disjoint m1.toFinset m2.toFinset ↔ m1.Disjoint m2 := by
  rw [Finset.disjoint_iff_ne]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
m1 m2 : Multiset α
⊢ (∀ a ∈ toFinset m1, ∀ b ∈ toFinset m2, a ≠ b) ↔ Disjoint m1 m2

Next tactic:
refine' ⟨fun h a ha1 ha2 => _, _⟩
theorem disjoint_toFinset {m1 m2 : Multiset α} :
    _root_.Disjoint m1.toFinset m2.toFinset ↔ m1.Disjoint m2 := by
  rw [Finset.disjoint_iff_ne]
  refine' ⟨fun h a ha1 ha2 => _, _⟩
  · 

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
m1 m2 : Multiset α
h : ∀ a ∈ toFinset m1, ∀ b ∈ toFinset m2, a ≠ b
a : α
ha1 : a ∈ m1
ha2 : a ∈ m2
⊢ False

Next tactic:
rw [← Multiset.mem_toFinset] at ha1 ha2
theorem disjoint_toFinset {m1 m2 : Multiset α} :
    _root_.Disjoint m1.toFinset m2.toFinset ↔ m1.Disjoint m2 := by
  rw [Finset.disjoint_iff_ne]
  refine' ⟨fun h a ha1 ha2 => _, _⟩
  · rw [← Multiset.mem_toFinset] at ha1 ha2
    

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
m1 m2 : Multiset α
h : ∀ a ∈ toFinset m1, ∀ b ∈ toFinset m2, a ≠ b
a : α
ha1 : a ∈ toFinset m1
ha2 : a ∈ toFinset m2
⊢ False

Next tactic:
exact h _ ha1 _ ha2 rfl
theorem disjoint_toFinset {m1 m2 : Multiset α} :
    _root_.Disjoint m1.toFinset m2.toFinset ↔ m1.Disjoint m2 := by
  rw [Finset.disjoint_iff_ne]
  refine' ⟨fun h a ha1 ha2 => _, _⟩
  · rw [← Multiset.mem_toFinset] at ha1 ha2
    exact h _ ha1 _ ha2 rfl
  · 

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
m1 m2 : Multiset α
⊢ Disjoint m1 m2 → ∀ a ∈ toFinset m1, ∀ b ∈ toFinset m2, a ≠ b

Next tactic:
rintro h a ha b hb rfl
theorem disjoint_toFinset {m1 m2 : Multiset α} :
    _root_.Disjoint m1.toFinset m2.toFinset ↔ m1.Disjoint m2 := by
  rw [Finset.disjoint_iff_ne]
  refine' ⟨fun h a ha1 ha2 => _, _⟩
  · rw [← Multiset.mem_toFinset] at ha1 ha2
    exact h _ ha1 _ ha2 rfl
  · rintro h a ha b hb rfl
    

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
m1 m2 : Multiset α
h : Disjoint m1 m2
a : α
ha : a ∈ toFinset m1
hb : a ∈ toFinset m2
⊢ False

Next tactic:
rw [Multiset.mem_toFinset] at ha hb
theorem disjoint_toFinset {m1 m2 : Multiset α} :
    _root_.Disjoint m1.toFinset m2.toFinset ↔ m1.Disjoint m2 := by
  rw [Finset.disjoint_iff_ne]
  refine' ⟨fun h a ha1 ha2 => _, _⟩
  · rw [← Multiset.mem_toFinset] at ha1 ha2
    exact h _ ha1 _ ha2 rfl
  · rintro h a ha b hb rfl
    rw [Multiset.mem_toFinset] at ha hb
    

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq α
m1 m2 : Multiset α
h : Disjoint m1 m2
a : α
ha : a ∈ m1
hb : a ∈ m2
⊢ False

Next tactic:
exact h ha hb
/-- Predicate asserting that the word `w₁` can be reduced to `w₂` in one step, i.e. there are words
`w₃ w₄` and letter `x` such that `w₁ = w₃xx⁻¹w₄` and `w₂ = w₃w₄`  -/
@[to_additive "Predicate asserting that the word `w₁` can be reduced to `w₂` in one step, i.e. there
  are words `w₃ w₄` and letter `x` such that `w₁ = w₃ + x + (-x) + w₄` and `w₂ = w₃w₄`"]
theorem Step.length : ∀ {L₁ L₂ : List (α × Bool)}, Step L₁ L₂ → L₂.length + 2 = L₁.length
  | _, _, @Red.Step.not _ L1 L2 x b => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ L1 L2 : List (α × Bool)
x : α
b : Bool
⊢ List.length (L1 ++ L2) + 2 = List.length (L1 ++ (x, b) :: (x, !b) :: L2)

Next tactic:
rw [List.length_append, List.length_append]
/-- Predicate asserting that the word `w₁` can be reduced to `w₂` in one step, i.e. there are words
`w₃ w₄` and letter `x` such that `w₁ = w₃xx⁻¹w₄` and `w₂ = w₃w₄`  -/
@[to_additive "Predicate asserting that the word `w₁` can be reduced to `w₂` in one step, i.e. there
  are words `w₃ w₄` and letter `x` such that `w₁ = w₃ + x + (-x) + w₄` and `w₂ = w₃w₄`"]
theorem Step.length : ∀ {L₁ L₂ : List (α × Bool)}, Step L₁ L₂ → L₂.length + 2 = L₁.length
  | _, _, @Red.Step.not _ L1 L2 x b => by rw [List.length_append, List.length_append]; 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ L1 L2 : List (α × Bool)
x : α
b : Bool
⊢ List.length L1 + List.length L2 + 2 = List.length L1 + List.length ((x, b) :: (x, !b) :: L2)

Next tactic:
rfl
@[to_additive (attr := simp)]
theorem Step.not_rev {x b} : Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂) := by
  

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
x : α
b : Bool
⊢ Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂)

Next tactic:
cases b
@[to_additive (attr := simp)]
theorem Step.not_rev {x b} : Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂) := by
  cases b <;> 

Proof state:
case false
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
x : α
⊢ Step (L₁ ++ (x, !false) :: (x, false) :: L₂) (L₁ ++ L₂)

Next tactic:
exact Step.not
@[to_additive (attr := simp)]
theorem Step.not_rev {x b} : Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂) := by
  cases b <;> 

Proof state:
case true
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
x : α
⊢ Step (L₁ ++ (x, !true) :: (x, true) :: L₂) (L₁ ++ L₂)

Next tactic:
exact Step.not
@[to_additive]
theorem Step.append_left : ∀ {L₁ L₂ L₃ : List (α × Bool)}, Step L₂ L₃ → Step (L₁ ++ L₂) (L₁ ++ L₃)
  | _, _, _, Red.Step.not => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ x✝¹ L₁✝ L₂✝ : List (α × Bool)
x✝ : α
b✝ : Bool
⊢ Step (x✝¹ ++ (L₁✝ ++ (x✝, b✝) :: (x✝, !b✝) :: L₂✝)) (x✝¹ ++ (L₁✝ ++ L₂✝))

Next tactic:
rw [← List.append_assoc, ← List.append_assoc]
@[to_additive]
theorem Step.append_left : ∀ {L₁ L₂ L₃ : List (α × Bool)}, Step L₂ L₃ → Step (L₁ ++ L₂) (L₁ ++ L₃)
  | _, _, _, Red.Step.not => by rw [← List.append_assoc, ← List.append_assoc]; 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ x✝¹ L₁✝ L₂✝ : List (α × Bool)
x✝ : α
b✝ : Bool
⊢ Step (x✝¹ ++ L₁✝ ++ (x✝, b✝) :: (x✝, !b✝) :: L₂✝) (x✝¹ ++ L₁✝ ++ L₂✝)

Next tactic:
constructor
@[to_additive]
theorem Step.append_right : ∀ {L₁ L₂ L₃ : List (α × Bool)}, Step L₁ L₂ → Step (L₁ ++ L₃) (L₂ ++ L₃)
  | _, _, _, Red.Step.not => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ x✝¹ L₁✝ L₂✝ : List (α × Bool)
x✝ : α
b✝ : Bool
⊢ Step (L₁✝ ++ (x✝, b✝) :: (x✝, !b✝) :: L₂✝ ++ x✝¹) (L₁✝ ++ L₂✝ ++ x✝¹)

Next tactic:
simp
@[to_additive]
theorem not_step_nil : ¬Step [] L := by
  

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
⊢ ¬Step [] L

Next tactic:
generalize h' : [] = L'
@[to_additive]
theorem not_step_nil : ¬Step [] L := by
  generalize h' : [] = L'
  

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ L' : List (α × Bool)
h' : [] = L'
⊢ ¬Step L' L

Next tactic:
intro h
@[to_additive]
theorem not_step_nil : ¬Step [] L := by
  generalize h' : [] = L'
  intro h
  

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ L' : List (α × Bool)
h' : [] = L'
h : Step L' L
⊢ False

Next tactic:
cases' h with L₁ L₂
@[to_additive]
theorem not_step_nil : ¬Step [] L := by
  generalize h' : [] = L'
  intro h
  cases' h with L₁ L₂
  

Proof state:
case not
α : Type u
L₁✝ L₂✝ L₃ L₄ L₁ L₂ : List (α × Bool)
x✝ : α
b✝ : Bool
h' : [] = L₁ ++ (x✝, b✝) :: (x✝, !b✝) :: L₂
⊢ False

Next tactic:
simp [List.nil_eq_append] at h'
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
a : α
b : Bool
⊢ Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, !b) :: L₂

Next tactic:
constructor
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · 

Proof state:
case mp
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
a : α
b : Bool
⊢ Step ((a, b) :: L₁) L₂ → (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, !b) :: L₂

Next tactic:
generalize hL : ((a, b) :: L₁ : List _) = L
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    

Proof state:
case mp
α : Type u
L✝ L₁ L₂ L₃ L₄ : List (α × Bool)
a : α
b : Bool
L : List (α × Bool)
hL : (a, b) :: L₁ = L
⊢ Step L L₂ → (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, !b) :: L₂

Next tactic:
rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · 

Proof state:
case mp.not.nil
α : Type u
L L₁ L₃ L₄ : List (α × Bool)
a : α
b : Bool
e : List (α × Bool)
a' : α
b' : Bool
hL : (a, b) :: L₁ = [] ++ (a', b') :: (a', !b') :: e
⊢ (∃ L, Step L₁ L ∧ [] ++ e = (a, b) :: L) ∨ L₁ = (a, !b) :: ([] ++ e)

Next tactic:
simp at hL
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      

Proof state:
case mp.not.nil
α : Type u
L L₁ L₃ L₄ : List (α × Bool)
a : α
b : Bool
e : List (α × Bool)
a' : α
b' : Bool
hL : (a = a' ∧ b = b') ∧ L₁ = (a', !b') :: e
⊢ (∃ L, Step L₁ L ∧ [] ++ e = (a, b) :: L) ∨ L₁ = (a, !b) :: ([] ++ e)

Next tactic:
simp [*]
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      simp [*]
    · 

Proof state:
case mp.not.cons
α : Type u
L L₁ L₃ L₄ : List (α × Bool)
a : α
b : Bool
e : List (α × Bool)
a' : α
b' : Bool
p : α × Bool
s' : List (α × Bool)
hL : (a, b) :: L₁ = p :: s' ++ (a', b') :: (a', !b') :: e
⊢ (∃ L, Step L₁ L ∧ p :: s' ++ e = (a, b) :: L) ∨ L₁ = (a, !b) :: (p :: s' ++ e)

Next tactic:
simp at hL
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      simp [*]
    · simp at hL
      

Proof state:
case mp.not.cons
α : Type u
L L₁ L₃ L₄ : List (α × Bool)
a : α
b : Bool
e : List (α × Bool)
a' : α
b' : Bool
p : α × Bool
s' : List (α × Bool)
hL : (a, b) = p ∧ L₁ = s' ++ (a', b') :: (a', !b') :: e
⊢ (∃ L, Step L₁ L ∧ p :: s' ++ e = (a, b) :: L) ∨ L₁ = (a, !b) :: (p :: s' ++ e)

Next tactic:
rcases hL with ⟨rfl, rfl⟩
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      simp [*]
    · simp at hL
      rcases hL with ⟨rfl, rfl⟩
      

Proof state:
case mp.not.cons.intro
α : Type u
L L₃ L₄ : List (α × Bool)
a : α
b : Bool
e : List (α × Bool)
a' : α
b' : Bool
s' : List (α × Bool)
⊢ (∃ L, Step (s' ++ (a', b') :: (a', !b') :: e) L ∧ (a, b) :: s' ++ e = (a, b) :: L) ∨
    s' ++ (a', b') :: (a', !b') :: e = (a, !b) :: ((a, b) :: s' ++ e)

Next tactic:
refine' Or.inl ⟨s' ++ e, Step.not, _⟩
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      simp [*]
    · simp at hL
      rcases hL with ⟨rfl, rfl⟩
      refine' Or.inl ⟨s' ++ e, Step.not, _⟩
      

Proof state:
case mp.not.cons.intro
α : Type u
L L₃ L₄ : List (α × Bool)
a : α
b : Bool
e : List (α × Bool)
a' : α
b' : Bool
s' : List (α × Bool)
⊢ (a, b) :: s' ++ e = (a, b) :: (s' ++ e)

Next tactic:
simp
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      simp [*]
    · simp at hL
      rcases hL with ⟨rfl, rfl⟩
      refine' Or.inl ⟨s' ++ e, Step.not, _⟩
      simp
  · 

Proof state:
case mpr
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
a : α
b : Bool
⊢ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, !b) :: L₂ → Step ((a, b) :: L₁) L₂

Next tactic:
rintro (⟨L, h, rfl⟩ | rfl)
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      simp [*]
    · simp at hL
      rcases hL with ⟨rfl, rfl⟩
      refine' Or.inl ⟨s' ++ e, Step.not, _⟩
      simp
  · rintro (⟨L, h, rfl⟩ | rfl)
    · 

Proof state:
case mpr.inl.intro.intro
α : Type u
L✝ L₁ L₃ L₄ : List (α × Bool)
a : α
b : Bool
L : List (α × Bool)
h : Step L₁ L
⊢ Step ((a, b) :: L₁) ((a, b) :: L)

Next tactic:
exact Step.cons h
@[to_additive]
theorem Step.cons_left_iff {a : α} {b : Bool} :
    Step ((a, b) :: L₁) L₂ ↔ (∃ L, Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, ! b) :: L₂ := by
  constructor
  · generalize hL : ((a, b) :: L₁ : List _) = L
    rintro @⟨_ | ⟨p, s'⟩, e, a', b'⟩
    · simp at hL
      simp [*]
    · simp at hL
      rcases hL with ⟨rfl, rfl⟩
      refine' Or.inl ⟨s' ++ e, Step.not, _⟩
      simp
  · rintro (⟨L, h, rfl⟩ | rfl)
    · exact Step.cons h
    · 

Proof state:
case mpr.inr
α : Type u
L L₂ L₃ L₄ : List (α × Bool)
a : α
b : Bool
⊢ Step ((a, b) :: (a, !b) :: L₂) L₂

Next tactic:
exact Step.cons_not
@[to_additive]
theorem not_step_singleton : ∀ {p : α × Bool}, ¬Step [p] L
  | (a, b) => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
a : α
b : Bool
⊢ ¬Step [(a, b)] L

Next tactic:
simp [Step.cons_left_iff, not_step_nil]
@[to_additive]
theorem Step.cons_cons_iff : ∀ {p : α × Bool}, Step (p :: L₁) (p :: L₂) ↔ Step L₁ L₂ := by
  

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
⊢ ∀ {p : α × Bool}, Step (p :: L₁) (p :: L₂) ↔ Step L₁ L₂

Next tactic:
simp (config := { contextual := true }) [Step.cons_left_iff, iff_def, or_imp]
@[to_additive]
theorem Step.append_left_iff : ∀ L, Step (L ++ L₁) (L ++ L₂) ↔ Step L₁ L₂
  | [] => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
⊢ Step ([] ++ L₁) ([] ++ L₂) ↔ Step L₁ L₂

Next tactic:
simp
@[to_additive]
theorem Step.append_left_iff : ∀ L, Step (L ++ L₁) (L ++ L₂) ↔ Step L₁ L₂
  | [] => by simp
  | p :: l => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ : List (α × Bool)
p : α × Bool
l : List (α × Bool)
⊢ Step (p :: l ++ L₁) (p :: l ++ L₂) ↔ Step L₁ L₂

Next tactic:
simp [Step.append_left_iff l, Step.cons_cons_iff]
@[to_additive]
theorem Step.diamond_aux :
    ∀ {L₁ L₂ L₃ L₄ : List (α × Bool)} {x1 b1 x2 b2},
      L₁ ++ (x1, b1) :: (x1, !b1) :: L₂ = L₃ ++ (x2, b2) :: (x2, !b2) :: L₄ →
        L₁ ++ L₂ = L₃ ++ L₄ ∨ ∃ L₅, Red.Step (L₁ ++ L₂) L₅ ∧ Red.Step (L₃ ++ L₄) L₅
  | [], _, [], _, _, _, _, _, H => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ x✝⁵ x✝⁴ : List (α × Bool)
x✝³ : α
x✝² : Bool
x✝¹ : α
x✝ : Bool
H : [] ++ (x✝³, x✝²) :: (x✝³, !x✝²) :: x✝⁵ = [] ++ (x✝¹, x✝) :: (x✝¹, !x✝) :: x✝⁴
⊢ [] ++ x✝⁵ = [] ++ x✝⁴ ∨ ∃ L₅, Step ([] ++ x✝⁵) L₅ ∧ Step ([] ++ x✝⁴) L₅

Next tactic:
injections
@[to_additive]
theorem Step.diamond_aux :
    ∀ {L₁ L₂ L₃ L₄ : List (α × Bool)} {x1 b1 x2 b2},
      L₁ ++ (x1, b1) :: (x1, !b1) :: L₂ = L₃ ++ (x2, b2) :: (x2, !b2) :: L₄ →
        L₁ ++ L₂ = L₃ ++ L₄ ∨ ∃ L₅, Red.Step (L₁ ++ L₂) L₅ ∧ Red.Step (L₃ ++ L₄) L₅
  | [], _, [], _, _, _, _, _, H => by injections; 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ x✝⁵ x✝⁴ : List (α × Bool)
x✝³ : α
x✝² : Bool
x✝¹ : α
x✝ : Bool
fst_eq✝¹ : x✝³ = x✝¹
snd_eq✝¹ : x✝² = x✝
tail_eq✝ : x✝⁵ = x✝⁴
fst_eq✝ : x✝³ = x✝¹
snd_eq✝ : (!x✝²) = !x✝
⊢ [] ++ x✝⁵ = [] ++ x✝⁴ ∨ ∃ L₅, Step ([] ++ x✝⁵) L₅ ∧ Step ([] ++ x✝⁴) L₅

Next tactic:
subst_vars
@[to_additive]
theorem Step.diamond_aux :
    ∀ {L₁ L₂ L₃ L₄ : List (α × Bool)} {x1 b1 x2 b2},
      L₁ ++ (x1, b1) :: (x1, !b1) :: L₂ = L₃ ++ (x2, b2) :: (x2, !b2) :: L₄ →
        L₁ ++ L₂ = L₃ ++ L₄ ∨ ∃ L₅, Red.Step (L₁ ++ L₂) L₅ ∧ Red.Step (L₃ ++ L₄) L₅
  | [], _, [], _, _, _, _, _, H => by injections; subst_vars; 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ x✝² : List (α × Bool)
x✝¹ : α
x✝ : Bool
fst_eq✝ : x✝¹ = x✝¹
snd_eq✝ : (!x✝) = !x✝
⊢ [] ++ x✝² = [] ++ x✝² ∨ ∃ L₅, Step ([] ++ x✝²) L₅ ∧ Step ([] ++ x✝²) L₅

Next tactic:
simp
@[to_additive]
theorem Step.diamond_aux :
    ∀ {L₁ L₂ L₃ L₄ : List (α × Bool)} {x1 b1 x2 b2},
      L₁ ++ (x1, b1) :: (x1, !b1) :: L₂ = L₃ ++ (x2, b2) :: (x2, !b2) :: L₄ →
        L₁ ++ L₂ = L₃ ++ L₄ ∨ ∃ L₅, Red.Step (L₁ ++ L₂) L₅ ∧ Red.Step (L₃ ++ L₄) L₅
  | [], _, [], _, _, _, _, _, H => by injections; subst_vars; simp
  | [], _, [(x3, b3)], _, _, _, _, _, H => by 

Proof state:
α : Type u
L L₁ L₂ L₃ L₄ x✝⁵ : List (α × Bool)
x3 : α
b3 : Bool
x✝⁴ : List (α × Bool)
x✝³ : α
x✝² : Bool
x✝¹ : α
x✝ : Bool
H : [] ++ (x✝³, x✝²) :: (x✝³, !x✝²) :: x✝⁵ = [(x3, b3)] ++ (x✝¹, x✝) :: (x✝¹, !x✝) :: x✝⁴
⊢ [] ++ x✝⁵ = [(x3, b3)] ++ x✝⁴ ∨ ∃ L₅, Step ([] ++ x✝⁵) L₅ ∧ Step ([(x3, b3)] ++ x✝⁴) L₅

Next tactic:
injections