File: Mathlib/GroupTheory/FreeGroup/Basic.lean

full_name: FreeAddGroup.Red.Step.not
code: /-- Reduction step for the additive free group relation: `w + x + (-x) + v ~> w + v` -/
inductive FreeAddGroup.Red.Step : List (α × Bool) → List (α × Bool) → Prop
  | not {L₁ L₂ x b} : FreeAddGroup.Red.Step (L₁ ++ (x, b) :: (x, not b) :: L₂) (L₁ ++ L₂)
goal: FreeAddGroup.Red.Step (L₁ ++ (x, b) :: (x, !b) :: L₂) (L₁ ++ L₂)

full_name: FreeAddGroup.Red.Step
code: /-- Reduction step for the additive free group relation: `w + x + (-x) + v ~> w + v` -/
inductive FreeAddGroup.Red.Step : List (α × Bool) → List (α × Bool) → Prop
  | not {L₁ L₂ x b} : FreeAddGroup.Red.Step (L₁ ++ (x, b) :: (x, not b) :: L₂) (L₁ ++ L₂)
goal: List (α × Bool) → List (α × Bool) → Prop

full_name: FreeGroup.Red.Step
code: /-- Reduction step for the multiplicative free group relation: `w * x * x⁻¹ * v ~> w * v` -/
@[to_additive FreeAddGroup.Red.Step]
inductive FreeGroup.Red.Step : List (α × Bool) → List (α × Bool) → Prop
  | not {L₁ L₂ x b} : FreeGroup.Red.Step (L₁ ++ (x, b) :: (x, not b) :: L₂) (L₁ ++ L₂)
goal: List (α × Bool) → List (α × Bool) → Prop

full_name: FreeGroup.Red.Step.not
code: /-- Reduction step for the multiplicative free group relation: `w * x * x⁻¹ * v ~> w * v` -/
@[to_additive FreeAddGroup.Red.Step]
inductive FreeGroup.Red.Step : List (α × Bool) → List (α × Bool) → Prop
  | not {L₁ L₂ x b} : FreeGroup.Red.Step (L₁ ++ (x, b) :: (x, not b) :: L₂) (L₁ ++ L₂)
goal: FreeGroup.Red.Step (L₁ ++ (x, b) :: (x, !b) :: L₂) (L₁ ++ L₂)

full_name: FreeGroup.Red
code: /-- Reflexive-transitive closure of `Red.Step` -/
@[to_additive FreeAddGroup.Red "Reflexive-transitive closure of `Red.Step`"]
def Red : List (α × Bool) → List (α × Bool) → Prop 
goal: List (α × Bool) → List (α × Bool) → Prop

full_name: FreeAddGroup.Red
code: /-- Reflexive-transitive closure of `Red.Step` -/
@[to_additive FreeAddGroup.Red "Reflexive-transitive closure of `Red.Step`"]
def Red : List (α × Bool) → List (α × Bool) → Prop 
goal: List (α × Bool) → List (α × Bool) → Prop

full_name: FreeAddGroup.Red.refl
code: @[to_additive (attr := refl)]
theorem Red.refl : Red L L 
goal: FreeAddGroup.Red L L

full_name: FreeGroup.Red.refl
code: @[to_additive (attr := refl)]
theorem Red.refl : Red L L 
goal: FreeGroup.Red L L

full_name: FreeAddGroup.Red.trans
code: @[to_additive (attr := trans)]
theorem Red.trans : Red L₁ L₂ → Red L₂ L₃ → Red L₁ L₃ 
goal: FreeAddGroup.Red L₁ L₂ → FreeAddGroup.Red L₂ L₃ → FreeAddGroup.Red L₁ L₃

full_name: FreeGroup.Red.trans
code: @[to_additive (attr := trans)]
theorem Red.trans : Red L₁ L₂ → Red L₂ L₃ → Red L₁ L₃ 
goal: FreeGroup.Red L₁ L₂ → FreeGroup.Red L₂ L₃ → FreeGroup.Red L₁ L₃

full_name: FreeAddGroup.Red.Step.length
code: /-- 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
  
goal: FreeAddGroup.Red.Step L₁ L₂ → L₂.length + 2 = L₁.length

full_name: FreeGroup.Red.Step.length
code: /-- 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
  
goal: FreeGroup.Red.Step L₁ L₂ → L₂.length + 2 = L₁.length

full_name: FreeGroup.Red.Step.not_rev
code: @[to_additive (attr := simp)]
theorem Step.not_rev {x b} : Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂) 
goal: FreeGroup.Red.Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂)

full_name: FreeAddGroup.Red.Step.not_rev
code: @[to_additive (attr := simp)]
theorem Step.not_rev {x b} : Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂) 
goal: FreeAddGroup.Red.Step (L₁ ++ (x, !b) :: (x, b) :: L₂) (L₁ ++ L₂)

full_name: FreeGroup.Red.Step.cons_not
code: @[to_additive (attr := simp)]
theorem Step.cons_not {x b} : Red.Step ((x, b) :: (x, !b) :: L) L 
goal: FreeGroup.Red.Step ((x, b) :: (x, !b) :: L) L

full_name: FreeAddGroup.Red.Step.cons_not
code: @[to_additive (attr := simp)]
theorem Step.cons_not {x b} : Red.Step ((x, b) :: (x, !b) :: L) L 
goal: FreeAddGroup.Red.Step ((x, b) :: (x, !b) :: L) L

full_name: FreeAddGroup.Red.Step.cons_not_rev
code: @[to_additive (attr := simp)]
theorem Step.cons_not_rev {x b} : Red.Step ((x, !b) :: (x, b) :: L) L 
goal: FreeAddGroup.Red.Step ((x, !b) :: (x, b) :: L) L

full_name: FreeGroup.Red.Step.cons_not_rev
code: @[to_additive (attr := simp)]
theorem Step.cons_not_rev {x b} : Red.Step ((x, !b) :: (x, b) :: L) L 
goal: FreeGroup.Red.Step ((x, !b) :: (x, b) :: L) L

full_name: FreeAddGroup.Red.Step.append_left
code: @[to_additive]
theorem Step.append_left : ∀ {L₁ L₂ L₃ : List (α × Bool)}, Step L₂ L₃ → Step (L₁ ++ L₂) (L₁ ++ L₃)
  
goal: FreeAddGroup.Red.Step L₂ L₃ → FreeAddGroup.Red.Step (L₁ ++ L₂) (L₁ ++ L₃)

full_name: FreeGroup.Red.Step.append_left
code: @[to_additive]
theorem Step.append_left : ∀ {L₁ L₂ L₃ : List (α × Bool)}, Step L₂ L₃ → Step (L₁ ++ L₂) (L₁ ++ L₃)
  
goal: FreeGroup.Red.Step L₂ L₃ → FreeGroup.Red.Step (L₁ ++ L₂) (L₁ ++ L₃)

full_name: FreeAddGroup.Red.Step.cons
code: @[to_additive]
theorem Step.cons {x} (H : Red.Step L₁ L₂) : Red.Step (x :: L₁) (x :: L₂) 
goal: FreeAddGroup.Red.Step (x :: L₁) (x :: L₂)

full_name: FreeGroup.Red.Step.cons
code: @[to_additive]
theorem Step.cons {x} (H : Red.Step L₁ L₂) : Red.Step (x :: L₁) (x :: L₂) 
goal: FreeGroup.Red.Step (x :: L₁) (x :: L₂)

full_name: FreeAddGroup.Red.Step.append_right
code: @[to_additive]
theorem Step.append_right : ∀ {L₁ L₂ L₃ : List (α × Bool)}, Step L₁ L₂ → Step (L₁ ++ L₃) (L₂ ++ L₃)
  
goal: FreeAddGroup.Red.Step L₁ L₂ → FreeAddGroup.Red.Step (L₁ ++ L₃) (L₂ ++ L₃)

full_name: FreeGroup.Red.Step.append_right
code: @[to_additive]
theorem Step.append_right : ∀ {L₁ L₂ L₃ : List (α × Bool)}, Step L₁ L₂ → Step (L₁ ++ L₃) (L₂ ++ L₃)
  
goal: FreeGroup.Red.Step L₁ L₂ → FreeGroup.Red.Step (L₁ ++ L₃) (L₂ ++ L₃)

full_name: FreeGroup.Red.not_step_nil
code: @[to_additive]
theorem not_step_nil : ¬Step [] L 
goal: ¬FreeGroup.Red.Step [] L

full_name: FreeAddGroup.Red.not_step_nil
code: @[to_additive]
theorem not_step_nil : ¬Step [] L 
goal: ¬FreeAddGroup.Red.Step [] L

full_name: FreeAddGroup.Red.Step.cons_left_iff
code: @[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₂ 
goal: FreeAddGroup.Red.Step ((a, b) :: L₁) L₂ ↔ (∃ L, FreeAddGroup.Red.Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, !b) :: L₂

full_name: FreeGroup.Red.Step.cons_left_iff
code: @[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₂ 
goal: FreeGroup.Red.Step ((a, b) :: L₁) L₂ ↔ (∃ L, FreeGroup.Red.Step L₁ L ∧ L₂ = (a, b) :: L) ∨ L₁ = (a, !b) :: L₂

full_name: FreeGroup.Red.not_step_singleton
code: @[to_additive]
theorem not_step_singleton : ∀ {p : α × Bool}, ¬Step [p] L
  
goal: ¬FreeGroup.Red.Step [p] L

full_name: FreeAddGroup.Red.not_step_singleton
code: @[to_additive]
theorem not_step_singleton : ∀ {p : α × Bool}, ¬Step [p] L
  
goal: ¬FreeAddGroup.Red.Step [p] L

full_name: FreeAddGroup.Red.Step.cons_cons_iff
code: @[to_additive]
theorem Step.cons_cons_iff : ∀ {p : α × Bool}, Step (p :: L₁) (p :: L₂) ↔ Step L₁ L₂ 
goal: FreeAddGroup.Red.Step (p :: L₁) (p :: L₂) ↔ FreeAddGroup.Red.Step L₁ L₂

full_name: FreeGroup.Red.Step.cons_cons_iff
code: @[to_additive]
theorem Step.cons_cons_iff : ∀ {p : α × Bool}, Step (p :: L₁) (p :: L₂) ↔ Step L₁ L₂ 
goal: FreeGroup.Red.Step (p :: L₁) (p :: L₂) ↔ FreeGroup.Red.Step L₁ L₂

full_name: FreeGroup.Red.Step.append_left_iff
code: @[to_additive]
theorem Step.append_left_iff : ∀ L, Step (L ++ L₁) (L ++ L₂) ↔ Step L₁ L₂
  
goal: FreeGroup.Red.Step (L ++ L₁) (L ++ L₂) ↔ FreeGroup.Red.Step L₁ L₂

full_name: FreeAddGroup.Red.Step.append_left_iff
code: @[to_additive]
theorem Step.append_left_iff : ∀ L, Step (L ++ L₁) (L ++ L₂) ↔ Step L₁ L₂
  
goal: FreeAddGroup.Red.Step (L ++ L₁) (L ++ L₂) ↔ FreeAddGroup.Red.Step L₁ L₂

full_name: FreeAddGroup.Red.Step.diamond_aux
code: @[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₅
  
goal: L₁ ++ (x1, b1) :: (x1, !b1) :: L₂ = L₃ ++ (x2, b2) :: (x2, !b2) :: L₄ →
  L₁ ++ L₂ = L₃ ++ L₄ ∨ ∃ L₅, FreeAddGroup.Red.Step (L₁ ++ L₂) L₅ ∧ FreeAddGroup.Red.Step (L₃ ++ L₄) L₅

full_name: FreeGroup.Red.Step.diamond_aux
code: @[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₅
  
goal: L₁ ++ (x1, b1) :: (x1, !b1) :: L₂ = L₃ ++ (x2, b2) :: (x2, !b2) :: L₄ →
  L₁ ++ L₂ = L₃ ++ L₄ ∨ ∃ L₅, FreeGroup.Red.Step (L₁ ++ L₂) L₅ ∧ FreeGroup.Red.Step (L₃ ++ L₄) L₅

full_name: FreeAddGroup.Red.Step.diamond
code: @[to_additive]
theorem Step.diamond :
    ∀ {L₁ L₂ L₃ L₄ : List (α × Bool)},
      Red.Step L₁ L₃ → Red.Step L₂ L₄ → L₁ = L₂ → L₃ = L₄ ∨ ∃ L₅, Red.Step L₃ L₅ ∧ Red.Step L₄ L₅
  
goal: FreeAddGroup.Red.Step L₁ L₃ →
  FreeAddGroup.Red.Step L₂ L₄ → L₁ = L₂ → L₃ = L₄ ∨ ∃ L₅, FreeAddGroup.Red.Step L₃ L₅ ∧ FreeAddGroup.Red.Step L₄ L₅

full_name: FreeGroup.Red.Step.diamond
code: @[to_additive]
theorem Step.diamond :
    ∀ {L₁ L₂ L₃ L₄ : List (α × Bool)},
      Red.Step L₁ L₃ → Red.Step L₂ L₄ → L₁ = L₂ → L₃ = L₄ ∨ ∃ L₅, Red.Step L₃ L₅ ∧ Red.Step L₄ L₅
  
goal: FreeGroup.Red.Step L₁ L₃ →
  FreeGroup.Red.Step L₂ L₄ → L₁ = L₂ → L₃ = L₄ ∨ ∃ L₅, FreeGroup.Red.Step L₃ L₅ ∧ FreeGroup.Red.Step L₄ L₅

full_name: FreeGroup.Red.Step.to_red
code: @[to_additive]
theorem Step.to_red : Step L₁ L₂ → Red L₁ L₂ 
goal: FreeGroup.Red.Step L₁ L₂ → FreeGroup.Red L₁ L₂

full_name: FreeAddGroup.Red.Step.to_red
code: @[to_additive]
theorem Step.to_red : Step L₁ L₂ → Red L₁ L₂ 
goal: FreeAddGroup.Red.Step L₁ L₂ → FreeAddGroup.Red L₁ L₂

full_name: FreeAddGroup.Red.church_rosser
code: /-- **Church-Rosser theorem** for word reduction: If `w1 w2 w3` are words such that `w1` reduces
to `w2` and `w3` respectively, then there is a word `w4` such that `w2` and `w3` reduce to `w4`
respectively. This is also known as Newman's diamond lemma. -/
@[to_additive
  "**Church-Rosser theorem** for word reduction: If `w1 w2 w3` are words such that `w1` reduces
  to `w2` and `w3` respectively, then there is a word `w4` such that `w2` and `w3` reduce to `w4`
  respectively. This is also known as Newman's diamond lemma."]
theorem church_rosser : Red L₁ L₂ → Red L₁ L₃ → Join Red L₂ L₃ 
goal: FreeAddGroup.Red L₁ L₂ → FreeAddGroup.Red L₁ L₃ → Relation.Join FreeAddGroup.Red L₂ L₃

full_name: FreeGroup.Red.church_rosser
code: /-- **Church-Rosser theorem** for word reduction: If `w1 w2 w3` are words such that `w1` reduces
to `w2` and `w3` respectively, then there is a word `w4` such that `w2` and `w3` reduce to `w4`
respectively. This is also known as Newman's diamond lemma. -/
@[to_additive
  "**Church-Rosser theorem** for word reduction: If `w1 w2 w3` are words such that `w1` reduces
  to `w2` and `w3` respectively, then there is a word `w4` such that `w2` and `w3` reduce to `w4`
  respectively. This is also known as Newman's diamond lemma."]
theorem church_rosser : Red L₁ L₂ → Red L₁ L₃ → Join Red L₂ L₃ 
goal: FreeGroup.Red L₁ L₂ → FreeGroup.Red L₁ L₃ → Relation.Join FreeGroup.Red L₂ L₃

full_name: FreeGroup.Red.cons_cons
code: @[to_additive]
theorem cons_cons {p} : Red L₁ L₂ → Red (p :: L₁) (p :: L₂) 
goal: FreeGroup.Red L₁ L₂ → FreeGroup.Red (p :: L₁) (p :: L₂)

full_name: FreeAddGroup.Red.cons_cons
code: @[to_additive]
theorem cons_cons {p} : Red L₁ L₂ → Red (p :: L₁) (p :: L₂) 
goal: FreeAddGroup.Red L₁ L₂ → FreeAddGroup.Red (p :: L₁) (p :: L₂)

full_name: FreeAddGroup.Red.cons_cons_iff
code: @[to_additive]
theorem cons_cons_iff (p) : Red (p :: L₁) (p :: L₂) ↔ Red L₁ L₂ 
goal: FreeAddGroup.Red (p :: L₁) (p :: L₂) ↔ FreeAddGroup.Red L₁ L₂

full_name: FreeGroup.Red.cons_cons_iff
code: @[to_additive]
theorem cons_cons_iff (p) : Red (p :: L₁) (p :: L₂) ↔ Red L₁ L₂ 
goal: FreeGroup.Red (p :: L₁) (p :: L₂) ↔ FreeGroup.Red L₁ L₂

full_name: FreeAddGroup.Red.append_append_left_iff
code: @[to_additive]
theorem append_append_left_iff : ∀ L, Red (L ++ L₁) (L ++ L₂) ↔ Red L₁ L₂
  
goal: FreeAddGroup.Red (L ++ L₁) (L ++ L₂) ↔ FreeAddGroup.Red L₁ L₂

full_name: FreeGroup.Red.append_append_left_iff
code: @[to_additive]
theorem append_append_left_iff : ∀ L, Red (L ++ L₁) (L ++ L₂) ↔ Red L₁ L₂
  
goal: FreeGroup.Red (L ++ L₁) (L ++ L₂) ↔ FreeGroup.Red L₁ L₂

full_name: FreeGroup.Red.append_append
code: @[to_additive]
theorem append_append (h₁ : Red L₁ L₃) (h₂ : Red L₂ L₄) : Red (L₁ ++ L₂) (L₃ ++ L₄) 
goal: FreeGroup.Red (L₁ ++ L₂) (L₃ ++ L₄)

full_name: FreeAddGroup.Red.append_append
code: @[to_additive]
theorem append_append (h₁ : Red L₁ L₃) (h₂ : Red L₂ L₄) : Red (L₁ ++ L₂) (L₃ ++ L₄) 
goal: FreeAddGroup.Red (L₁ ++ L₂) (L₃ ++ L₄)

full_name: FreeAddGroup.Red.to_append_iff
code: @[to_additive]
theorem to_append_iff : Red L (L₁ ++ L₂) ↔ ∃ L₃ L₄, L = L₃ ++ L₄ ∧ Red L₃ L₁ ∧ Red L₄ L₂ 
goal: FreeAddGroup.Red L (L₁ ++ L₂) ↔ ∃ L₃ L₄, L = L₃ ++ L₄ ∧ FreeAddGroup.Red L₃ L₁ ∧ FreeAddGroup.Red L₄ L₂

full_name: FreeGroup.Red.to_append_iff
code: @[to_additive]
theorem to_append_iff : Red L (L₁ ++ L₂) ↔ ∃ L₃ L₄, L = L₃ ++ L₄ ∧ Red L₃ L₁ ∧ Red L₄ L₂ 
goal: FreeGroup.Red L (L₁ ++ L₂) ↔ ∃ L₃ L₄, L = L₃ ++ L₄ ∧ FreeGroup.Red L₃ L₁ ∧ FreeGroup.Red L₄ L₂

full_name: FreeAddGroup.Red.nil_iff
code: /-- The empty word `[]` only reduces to itself. -/
@[to_additive "The empty word `[]` only reduces to itself."]
theorem nil_iff : Red [] L ↔ L = [] 
goal: FreeAddGroup.Red [] L ↔ L = []

full_name: FreeGroup.Red.nil_iff
code: /-- The empty word `[]` only reduces to itself. -/
@[to_additive "The empty word `[]` only reduces to itself."]
theorem nil_iff : Red [] L ↔ L = [] 
goal: FreeGroup.Red [] L ↔ L = []

full_name: FreeAddGroup.Red.singleton_iff
code: /-- A letter only reduces to itself. -/
@[to_additive "A letter only reduces to itself."]
theorem singleton_iff {x} : Red [x] L₁ ↔ L₁ = [x] 
goal: FreeAddGroup.Red [x] L₁ ↔ L₁ = [x]

full_name: FreeGroup.Red.singleton_iff
code: /-- A letter only reduces to itself. -/
@[to_additive "A letter only reduces to itself."]
theorem singleton_iff {x} : Red [x] L₁ ↔ L₁ = [x] 
goal: FreeGroup.Red [x] L₁ ↔ L₁ = [x]

full_name: FreeAddGroup.Red.cons_nil_iff_singleton
code: /-- If `x` is a letter and `w` is a word such that `xw` reduces to the empty word, then `w` reduces
to `x⁻¹` -/
@[to_additive
  "If `x` is a letter and `w` is a word such that `x + w` reduces to the empty word, then `w`
  reduces to `-x`."]
theorem cons_nil_iff_singleton {x b} : Red ((x, b) :: L) [] ↔ Red L [(x, not b)] 
goal: FreeAddGroup.Red ((x, b) :: L) [] ↔ FreeAddGroup.Red L [(x, !b)]

full_name: FreeGroup.Red.cons_nil_iff_singleton
code: /-- If `x` is a letter and `w` is a word such that `xw` reduces to the empty word, then `w` reduces
to `x⁻¹` -/
@[to_additive
  "If `x` is a letter and `w` is a word such that `x + w` reduces to the empty word, then `w`
  reduces to `-x`."]
theorem cons_nil_iff_singleton {x b} : Red ((x, b) :: L) [] ↔ Red L [(x, not b)] 
goal: FreeGroup.Red ((x, b) :: L) [] ↔ FreeGroup.Red L [(x, !b)]

full_name: FreeAddGroup.Red.red_iff_irreducible
code: @[to_additive]
theorem red_iff_irreducible {x1 b1 x2 b2} (h : (x1, b1) ≠ (x2, b2)) :
    Red [(x1, !b1), (x2, b2)] L ↔ L = [(x1, !b1), (x2, b2)] 
goal: FreeAddGroup.Red [(x1, !b1), (x2, b2)] L ↔ L = [(x1, !b1), (x2, b2)]

full_name: FreeGroup.Red.red_iff_irreducible
code: @[to_additive]
theorem red_iff_irreducible {x1 b1 x2 b2} (h : (x1, b1) ≠ (x2, b2)) :
    Red [(x1, !b1), (x2, b2)] L ↔ L = [(x1, !b1), (x2, b2)] 
goal: FreeGroup.Red [(x1, !b1), (x2, b2)] L ↔ L = [(x1, !b1), (x2, b2)]

full_name: FreeAddGroup.Red.neg_of_red_of_ne
code: /-- If `x` and `y` are distinct letters and `w₁ w₂` are words such that `xw₁` reduces to `yw₂`, then
`w₁` reduces to `x⁻¹yw₂`. -/
@[to_additive "If `x` and `y` are distinct letters and `w₁ w₂` are words such that `x + w₁` reduces
  to `y + w₂`, then `w₁` reduces to `-x + y + w₂`."]
theorem inv_of_red_of_ne {x1 b1 x2 b2} (H1 : (x1, b1) ≠ (x2, b2))
    (H2 : Red ((x1, b1) :: L₁) ((x2, b2) :: L₂)) : Red L₁ ((x1, not b1) :: (x2, b2) :: L₂) 
goal: FreeAddGroup.Red L₁ ((x1, !b1) :: (x2, b2) :: L₂)

full_name: FreeGroup.Red.inv_of_red_of_ne
code: /-- If `x` and `y` are distinct letters and `w₁ w₂` are words such that `xw₁` reduces to `yw₂`, then
`w₁` reduces to `x⁻¹yw₂`. -/
@[to_additive "If `x` and `y` are distinct letters and `w₁ w₂` are words such that `x + w₁` reduces
  to `y + w₂`, then `w₁` reduces to `-x + y + w₂`."]
theorem inv_of_red_of_ne {x1 b1 x2 b2} (H1 : (x1, b1) ≠ (x2, b2))
    (H2 : Red ((x1, b1) :: L₁) ((x2, b2) :: L₂)) : Red L₁ ((x1, not b1) :: (x2, b2) :: L₂) 
goal: FreeGroup.Red L₁ ((x1, !b1) :: (x2, b2) :: L₂)

full_name: FreeAddGroup.Red.Step.sublist
code: @[to_additive]
theorem Step.sublist (H : Red.Step L₁ L₂) : Sublist L₂ L₁ 
goal: L₂.Sublist L₁

full_name: FreeGroup.Red.Step.sublist
code: @[to_additive]
theorem Step.sublist (H : Red.Step L₁ L₂) : Sublist L₂ L₁ 
goal: L₂.Sublist L₁

full_name: FreeAddGroup.Red.sublist
code: /-- If `w₁ w₂` are words such that `w₁` reduces to `w₂`, then `w₂` is a sublist of `w₁`. -/
@[to_additive "If `w₁ w₂` are words such that `w₁` reduces to `w₂`, then `w₂` is a sublist of
  `w₁`."]
protected theorem sublist : Red L₁ L₂ → L₂ <+ L₁ 
goal: FreeAddGroup.Red L₁ L₂ → L₂.Sublist L₁

full_name: FreeGroup.Red.sublist
code: /-- If `w₁ w₂` are words such that `w₁` reduces to `w₂`, then `w₂` is a sublist of `w₁`. -/
@[to_additive "If `w₁ w₂` are words such that `w₁` reduces to `w₂`, then `w₂` is a sublist of
  `w₁`."]
protected theorem sublist : Red L₁ L₂ → L₂ <+ L₁ 
goal: FreeGroup.Red L₁ L₂ → L₂.Sublist L₁

full_name: FreeGroup.Red.length_le
code: @[to_additive]
theorem length_le (h : Red L₁ L₂) : L₂.length ≤ L₁.length 
goal: L₂.length ≤ L₁.length

full_name: FreeAddGroup.Red.length_le
code: @[to_additive]
theorem length_le (h : Red L₁ L₂) : L₂.length ≤ L₁.length 
goal: L₂.length ≤ L₁.length

full_name: FreeGroup.Red.sizeof_of_step
code: @[to_additive]
theorem sizeof_of_step : ∀ {L₁ L₂ : List (α × Bool)},
    Step L₁ L₂ → sizeOf L₂ < sizeOf L₁
  
goal: FreeGroup.Red.Step L₁ L₂ → sizeOf L₂ < sizeOf L₁

full_name: FreeAddGroup.Red.sizeof_of_step
code: @[to_additive]
theorem sizeof_of_step : ∀ {L₁ L₂ : List (α × Bool)},
    Step L₁ L₂ → sizeOf L₂ < sizeOf L₁
  
goal: FreeAddGroup.Red.Step L₁ L₂ → sizeOf L₂ < sizeOf L₁

full_name: FreeAddGroup.Red.length
code: @[to_additive]
theorem length (h : Red L₁ L₂) : ∃ n, L₁.length = L₂.length + 2 * n 
goal: ∃ n, L₁.length = L₂.length + 2 * n

full_name: FreeGroup.Red.length
code: @[to_additive]
theorem length (h : Red L₁ L₂) : ∃ n, L₁.length = L₂.length + 2 * n 
goal: ∃ n, L₁.length = L₂.length + 2 * n

full_name: FreeAddGroup.Red.antisymm
code: @[to_additive]
theorem antisymm (h₁₂ : Red L₁ L₂) (h₂₁ : Red L₂ L₁) : L₁ = L₂ 
goal: L₁ = L₂

full_name: FreeGroup.Red.antisymm
code: @[to_additive]
theorem antisymm (h₁₂ : Red L₁ L₂) (h₂₁ : Red L₂ L₁) : L₁ = L₂ 
goal: L₁ = L₂

full_name: FreeGroup.equivalence_join_red
code: @[to_additive FreeAddGroup.equivalence_join_red]
theorem equivalence_join_red : Equivalence (Join (@Red α)) 
goal: Equivalence (Relation.Join FreeGroup.Red)

full_name: FreeAddGroup.equivalence_join_red
code: @[to_additive FreeAddGroup.equivalence_join_red]
theorem equivalence_join_red : Equivalence (Join (@Red α)) 
goal: Equivalence (Relation.Join FreeAddGroup.Red)

full_name: FreeGroup.join_red_of_step
code: @[to_additive FreeAddGroup.join_red_of_step]
theorem join_red_of_step (h : Red.Step L₁ L₂) : Join Red L₁ L₂ 
goal: Relation.Join FreeGroup.Red L₁ L₂

full_name: FreeAddGroup.join_red_of_step
code: @[to_additive FreeAddGroup.join_red_of_step]
theorem join_red_of_step (h : Red.Step L₁ L₂) : Join Red L₁ L₂ 
goal: Relation.Join FreeAddGroup.Red L₁ L₂

full_name: FreeAddGroup.eqvGen_step_iff_join_red
code: @[to_additive FreeAddGroup.eqvGen_step_iff_join_red]
theorem eqvGen_step_iff_join_red : EqvGen Red.Step L₁ L₂ ↔ Join Red L₁ L₂ 
goal: EqvGen FreeAddGroup.Red.Step L₁ L₂ ↔ Relation.Join FreeAddGroup.Red L₁ L₂

full_name: FreeGroup.eqvGen_step_iff_join_red
code: @[to_additive FreeAddGroup.eqvGen_step_iff_join_red]
theorem eqvGen_step_iff_join_red : EqvGen Red.Step L₁ L₂ ↔ Join Red L₁ L₂ 
goal: EqvGen FreeGroup.Red.Step L₁ L₂ ↔ Relation.Join FreeGroup.Red L₁ L₂

full_name: FreeAddGroup
code: /-- The free group over a type, i.e. the words formed by the elements of the type and their formal
inverses, quotient by one step reduction. -/
@[to_additive "The free additive group over a type, i.e. the words formed by the elements of the
  type and their formal inverses, quotient by one step reduction."]
def FreeGroup (α : Type u) : Type u 
goal: Type u

full_name: FreeGroup
code: /-- The free group over a type, i.e. the words formed by the elements of the type and their formal
inverses, quotient by one step reduction. -/
@[to_additive "The free additive group over a type, i.e. the words formed by the elements of the
  type and their formal inverses, quotient by one step reduction."]
def FreeGroup (α : Type u) : Type u 
goal: Type u

full_name: FreeGroup.mk
code: /-- The canonical map from `List (α × Bool)` to the free group on `α`. -/
@[to_additive "The canonical map from `list (α × bool)` to the free additive group on `α`."]
def mk (L : List (α × Bool)) : FreeGroup α 
goal: FreeGroup α

full_name: FreeAddGroup.mk
code: /-- The canonical map from `List (α × Bool)` to the free group on `α`. -/
@[to_additive "The canonical map from `list (α × bool)` to the free additive group on `α`."]
def mk (L : List (α × Bool)) : FreeGroup α 
goal: FreeAddGroup α

full_name: FreeAddGroup.quot_mk_eq_mk
code: @[to_additive (attr := simp)]
theorem quot_mk_eq_mk : Quot.mk Red.Step L = mk L 
goal: Quot.mk FreeAddGroup.Red.Step L = FreeAddGroup.mk L

full_name: FreeGroup.quot_mk_eq_mk
code: @[to_additive (attr := simp)]
theorem quot_mk_eq_mk : Quot.mk Red.Step L = mk L 
goal: Quot.mk FreeGroup.Red.Step L = FreeGroup.mk L

full_name: FreeAddGroup.quot_lift_mk
code: @[to_additive (attr := simp)]
theorem quot_lift_mk (β : Type v) (f : List (α × Bool) → β)
    (H : ∀ L₁ L₂, Red.Step L₁ L₂ → f L₁ = f L₂) : Quot.lift f H (mk L) = f L 
goal: Quot.lift f H (FreeAddGroup.mk L) = f L

full_name: FreeGroup.quot_lift_mk
code: @[to_additive (attr := simp)]
theorem quot_lift_mk (β : Type v) (f : List (α × Bool) → β)
    (H : ∀ L₁ L₂, Red.Step L₁ L₂ → f L₁ = f L₂) : Quot.lift f H (mk L) = f L 
goal: Quot.lift f H (FreeGroup.mk L) = f L

full_name: FreeGroup.quot_liftOn_mk
code: @[to_additive (attr := simp)]
theorem quot_liftOn_mk (β : Type v) (f : List (α × Bool) → β)
    (H : ∀ L₁ L₂, Red.Step L₁ L₂ → f L₁ = f L₂) : Quot.liftOn (mk L) f H = f L 
goal: Quot.liftOn (FreeGroup.mk L) f H = f L

full_name: FreeAddGroup.quot_liftOn_mk
code: @[to_additive (attr := simp)]
theorem quot_liftOn_mk (β : Type v) (f : List (α × Bool) → β)
    (H : ∀ L₁ L₂, Red.Step L₁ L₂ → f L₁ = f L₂) : Quot.liftOn (mk L) f H = f L 
goal: Quot.liftOn (FreeAddGroup.mk L) f H = f L

full_name: FreeGroup.quot_map_mk
code: @[to_additive (attr := simp)]
theorem quot_map_mk (β : Type v) (f : List (α × Bool) → List (β × Bool))
    (H : (Red.Step ⇒ Red.Step) f f) : Quot.map f H (mk L) = mk (f L) 
goal: Quot.map f H (FreeGroup.mk L) = FreeGroup.mk (f L)

full_name: FreeAddGroup.quot_map_mk
code: @[to_additive (attr := simp)]
theorem quot_map_mk (β : Type v) (f : List (α × Bool) → List (β × Bool))
    (H : (Red.Step ⇒ Red.Step) f f) : Quot.map f H (mk L) = mk (f L) 
goal: Quot.map f H (FreeAddGroup.mk L) = FreeAddGroup.mk (f L)

full_name: FreeGroup.instOne
code: @[to_additive]
instance : One (FreeGroup α) 
goal: One (FreeGroup α)

full_name: FreeAddGroup.instZero
code: @[to_additive]
instance : One (FreeGroup α) 
goal: Zero (FreeAddGroup α)

full_name: FreeGroup.one_eq_mk
code: @[to_additive]
theorem one_eq_mk : (1 : FreeGroup α) = mk [] 
goal: 1 = FreeGroup.mk []

full_name: FreeAddGroup.zero_eq_mk
code: @[to_additive]
theorem one_eq_mk : (1 : FreeGroup α) = mk [] 
goal: 0 = FreeAddGroup.mk []

full_name: FreeGroup.instInhabited
code: @[to_additive]
instance : Inhabited (FreeGroup α) 
goal: Inhabited (FreeGroup α)

full_name: FreeAddGroup.instInhabited
code: @[to_additive]
instance : Inhabited (FreeGroup α) 
goal: Inhabited (FreeAddGroup α)

full_name: FreeGroup.instUniqueOfIsEmpty
code: @[to_additive]
instance [IsEmpty α] : Unique (FreeGroup α) 
goal: Unique (FreeGroup α)

full_name: FreeAddGroup.instUniqueOfIsEmpty
code: @[to_additive]
instance [IsEmpty α] : Unique (FreeGroup α) 
goal: Unique (FreeAddGroup α)

full_name: FreeGroup.instMul
code: @[to_additive]
instance : Mul (FreeGroup α) 
goal: Mul (FreeGroup α)

full_name: FreeAddGroup.instAdd
code: @[to_additive]
instance : Mul (FreeGroup α) 
goal: Add (FreeAddGroup α)

full_name: FreeAddGroup.add_mk
code: @[to_additive (attr := simp)]
theorem mul_mk : mk L₁ * mk L₂ = mk (L₁ ++ L₂) 
goal: FreeAddGroup.mk L₁ + FreeAddGroup.mk L₂ = FreeAddGroup.mk (L₁ ++ L₂)

full_name: FreeGroup.mul_mk
code: @[to_additive (attr := simp)]
theorem mul_mk : mk L₁ * mk L₂ = mk (L₁ ++ L₂) 
goal: FreeGroup.mk L₁ * FreeGroup.mk L₂ = FreeGroup.mk (L₁ ++ L₂)

full_name: FreeAddGroup.negRev
code: /-- Transform a word representing a free group element into a word representing its inverse. -/
@[to_additive "Transform a word representing a free group element into a word representing its
  negative."]
def invRev (w : List (α × Bool)) : List (α × Bool) 
goal: List (α × Bool)

full_name: FreeGroup.invRev
code: /-- Transform a word representing a free group element into a word representing its inverse. -/
@[to_additive "Transform a word representing a free group element into a word representing its
  negative."]
def invRev (w : List (α × Bool)) : List (α × Bool) 
goal: List (α × Bool)

full_name: FreeAddGroup.negRev_length
code: @[to_additive (attr := simp)]
theorem invRev_length : (invRev L₁).length = L₁.length 
goal: (FreeAddGroup.negRev L₁).length = L₁.length

full_name: FreeGroup.invRev_length
code: @[to_additive (attr := simp)]
theorem invRev_length : (invRev L₁).length = L₁.length 
goal: (FreeGroup.invRev L₁).length = L₁.length

full_name: FreeGroup.invRev_invRev
code: @[to_additive (attr := simp)]
theorem invRev_invRev : invRev (invRev L₁) = L₁ 
goal: FreeGroup.invRev (FreeGroup.invRev L₁) = L₁

full_name: FreeAddGroup.negRev_negRev
code: @[to_additive (attr := simp)]
theorem invRev_invRev : invRev (invRev L₁) = L₁ 
goal: FreeAddGroup.negRev (FreeAddGroup.negRev L₁) = L₁

full_name: FreeGroup.invRev_empty
code: @[to_additive (attr := simp)]
theorem invRev_empty : invRev ([] : List (α × Bool)) = [] 
goal: FreeGroup.invRev [] = []

full_name: FreeAddGroup.negRev_empty
code: @[to_additive (attr := simp)]
theorem invRev_empty : invRev ([] : List (α × Bool)) = [] 
goal: FreeAddGroup.negRev [] = []

full_name: FreeAddGroup.negRev_involutive
code: @[to_additive]
theorem invRev_involutive : Function.Involutive (@invRev α) 
goal: Function.Involutive FreeAddGroup.negRev

full_name: FreeGroup.invRev_involutive
code: @[to_additive]
theorem invRev_involutive : Function.Involutive (@invRev α) 
goal: Function.Involutive FreeGroup.invRev

full_name: FreeGroup.invRev_injective
code: @[to_additive]
theorem invRev_injective : Function.Injective (@invRev α) 
goal: Function.Injective FreeGroup.invRev

full_name: FreeAddGroup.negRev_injective
code: @[to_additive]
theorem invRev_injective : Function.Injective (@invRev α) 
goal: Function.Injective FreeAddGroup.negRev

full_name: FreeAddGroup.negRev_surjective
code: @[to_additive]
theorem invRev_surjective : Function.Surjective (@invRev α) 
goal: Function.Surjective FreeAddGroup.negRev

full_name: FreeGroup.invRev_surjective
code: @[to_additive]
theorem invRev_surjective : Function.Surjective (@invRev α) 
goal: Function.Surjective FreeGroup.invRev

full_name: FreeAddGroup.negRev_bijective
code: @[to_additive]
theorem invRev_bijective : Function.Bijective (@invRev α) 
goal: Function.Bijective FreeAddGroup.negRev

full_name: FreeGroup.invRev_bijective
code: @[to_additive]
theorem invRev_bijective : Function.Bijective (@invRev α) 
goal: Function.Bijective FreeGroup.invRev

full_name: FreeAddGroup.instNeg
code: @[to_additive]
instance : Inv (FreeGroup α) 
goal: Neg (FreeAddGroup α)

full_name: FreeGroup.instInv
code: @[to_additive]
instance : Inv (FreeGroup α) 
goal: Inv (FreeGroup α)

full_name: FreeGroup.inv_mk
code: @[to_additive (attr := simp)]
theorem inv_mk : (mk L)⁻¹ = mk (invRev L) 
goal: (FreeGroup.mk L)⁻¹ = FreeGroup.mk (FreeGroup.invRev L)

full_name: FreeAddGroup.neg_mk
code: @[to_additive (attr := simp)]
theorem inv_mk : (mk L)⁻¹ = mk (invRev L) 
goal: -FreeAddGroup.mk L = FreeAddGroup.mk (FreeAddGroup.negRev L)

full_name: FreeGroup.Red.Step.invRev
code: @[to_additive]
theorem Red.Step.invRev {L₁ L₂ : List (α × Bool)} (h : Red.Step L₁ L₂) :
    Red.Step (FreeGroup.invRev L₁) (FreeGroup.invRev L₂) 
goal: FreeGroup.Red.Step (FreeGroup.invRev L₁) (FreeGroup.invRev L₂)

full_name: FreeAddGroup.Red.Step.negRev
code: @[to_additive]
theorem Red.Step.invRev {L₁ L₂ : List (α × Bool)} (h : Red.Step L₁ L₂) :
    Red.Step (FreeGroup.invRev L₁) (FreeGroup.invRev L₂) 
goal: FreeAddGroup.Red.Step (FreeAddGroup.negRev L₁) (FreeAddGroup.negRev L₂)

full_name: FreeAddGroup.Red.negRev
code: @[to_additive]
theorem Red.invRev {L₁ L₂ : List (α × Bool)} (h : Red L₁ L₂) : Red (invRev L₁) (invRev L₂) 
goal: FreeAddGroup.Red (FreeAddGroup.negRev L₁) (FreeAddGroup.negRev L₂)

full_name: FreeGroup.Red.invRev
code: @[to_additive]
theorem Red.invRev {L₁ L₂ : List (α × Bool)} (h : Red L₁ L₂) : Red (invRev L₁) (invRev L₂) 
goal: FreeGroup.Red (FreeGroup.invRev L₁) (FreeGroup.invRev L₂)

full_name: FreeAddGroup.Red.step_negRev_iff
code: @[to_additive (attr := simp)]
theorem Red.step_invRev_iff :
    Red.Step (FreeGroup.invRev L₁) (FreeGroup.invRev L₂) ↔ Red.Step L₁ L₂ 
goal: FreeAddGroup.Red.Step (FreeAddGroup.negRev L₁) (FreeAddGroup.negRev L₂) ↔ FreeAddGroup.Red.Step L₁ L₂

full_name: FreeGroup.Red.step_invRev_iff
code: @[to_additive (attr := simp)]
theorem Red.step_invRev_iff :
    Red.Step (FreeGroup.invRev L₁) (FreeGroup.invRev L₂) ↔ Red.Step L₁ L₂ 
goal: FreeGroup.Red.Step (FreeGroup.invRev L₁) (FreeGroup.invRev L₂) ↔ FreeGroup.Red.Step L₁ L₂

full_name: FreeAddGroup.red_negRev_iff
code: @[to_additive (attr := simp)]
theorem red_invRev_iff : Red (invRev L₁) (invRev L₂) ↔ Red L₁ L₂ 
goal: FreeAddGroup.Red (FreeAddGroup.negRev L₁) (FreeAddGroup.negRev L₂) ↔ FreeAddGroup.Red L₁ L₂

full_name: FreeGroup.red_invRev_iff
code: @[to_additive (attr := simp)]
theorem red_invRev_iff : Red (invRev L₁) (invRev L₂) ↔ Red L₁ L₂ 
goal: FreeGroup.Red (FreeGroup.invRev L₁) (FreeGroup.invRev L₂) ↔ FreeGroup.Red L₁ L₂

full_name: FreeGroup.instGroup
code: @[to_additive]
instance : Group (FreeGroup α) 
goal: Group (FreeGroup α)

full_name: FreeAddGroup.instAddGroup
code: @[to_additive]
instance : Group (FreeGroup α) 
goal: AddGroup (FreeAddGroup α)

full_name: FreeAddGroup.of
code: /-- `of` is the canonical injection from the type to the free group over that type by sending each
element to the equivalence class of the letter that is the element. -/
@[to_additive "`of` is the canonical injection from the type to the free group over that type
  by sending each element to the equivalence class of the letter that is the element."]
def of (x : α) : FreeGroup α 
goal: FreeAddGroup α

full_name: FreeGroup.of
code: /-- `of` is the canonical injection from the type to the free group over that type by sending each
element to the equivalence class of the letter that is the element. -/
@[to_additive "`of` is the canonical injection from the type to the free group over that type
  by sending each element to the equivalence class of the letter that is the element."]
def of (x : α) : FreeGroup α 
goal: FreeGroup α

full_name: FreeGroup.Red.exact
code: @[to_additive]
theorem Red.exact : mk L₁ = mk L₂ ↔ Join Red L₁ L₂ 
goal: FreeGroup.mk L₁ = FreeGroup.mk L₂ ↔ Relation.Join FreeGroup.Red L₁ L₂

full_name: FreeAddGroup.Red.exact
code: @[to_additive]
theorem Red.exact : mk L₁ = mk L₂ ↔ Join Red L₁ L₂ 
goal: FreeAddGroup.mk L₁ = FreeAddGroup.mk L₂ ↔ Relation.Join FreeAddGroup.Red L₁ L₂

full_name: FreeAddGroup.of_injective
code: /-- The canonical map from the type to the free group is an injection. -/
@[to_additive "The canonical map from the type to the additive free group is an injection."]
theorem of_injective : Function.Injective (@of α) 
goal: Function.Injective FreeAddGroup.of

full_name: FreeGroup.of_injective
code: /-- The canonical map from the type to the free group is an injection. -/
@[to_additive "The canonical map from the type to the additive free group is an injection."]
theorem of_injective : Function.Injective (@of α) 
goal: Function.Injective FreeGroup.of

full_name: FreeAddGroup.Lift.aux
code: /-- Given `f : α → β` with `β` a group, the canonical map `List (α × Bool) → β` -/
@[to_additive "Given `f : α → β` with `β` an additive group, the canonical map
  `list (α × bool) → β`"]
def Lift.aux : List (α × Bool) → β 
goal: List (α × Bool) → β

full_name: FreeGroup.Lift.aux
code: /-- Given `f : α → β` with `β` a group, the canonical map `List (α × Bool) → β` -/
@[to_additive "Given `f : α → β` with `β` an additive group, the canonical map
  `list (α × bool) → β`"]
def Lift.aux : List (α × Bool) → β 
goal: List (α × Bool) → β

full_name: FreeAddGroup.Red.Step.lift
code: @[to_additive]
theorem Red.Step.lift {f : α → β} (H : Red.Step L₁ L₂) : Lift.aux f L₁ = Lift.aux f L₂ 
goal: FreeAddGroup.Lift.aux f L₁ = FreeAddGroup.Lift.aux f L₂

full_name: FreeGroup.Red.Step.lift
code: @[to_additive]
theorem Red.Step.lift {f : α → β} (H : Red.Step L₁ L₂) : Lift.aux f L₁ = Lift.aux f L₂ 
goal: FreeGroup.Lift.aux f L₁ = FreeGroup.Lift.aux f L₂

full_name: FreeGroup.lift_symm_apply
code: /-- If `β` is a group, then any function from `α` to `β` extends uniquely to a group homomorphism
from the free group over `α` to `β` -/
@[to_additive (attr := simps symm_apply)
  "If `β` is an additive group, then any function from `α` to `β` extends uniquely to an
  additive group homomorphism from the free additive group over `α` to `β`"]
def lift : (α → β) ≃ (FreeGroup α →* β) 
goal: ∀ (a : α), FreeGroup.lift.symm g a = (⇑g ∘ FreeGroup.of) a

full_name: FreeAddGroup.lift
code: /-- If `β` is a group, then any function from `α` to `β` extends uniquely to a group homomorphism
from the free group over `α` to `β` -/
@[to_additive (attr := simps symm_apply)
  "If `β` is an additive group, then any function from `α` to `β` extends uniquely to an
  additive group homomorphism from the free additive group over `α` to `β`"]
def lift : (α → β) ≃ (FreeGroup α →* β) 
goal: (α → β) ≃ (FreeAddGroup α →+ β)

full_name: FreeGroup.lift
code: /-- If `β` is a group, then any function from `α` to `β` extends uniquely to a group homomorphism
from the free group over `α` to `β` -/
@[to_additive (attr := simps symm_apply)
  "If `β` is an additive group, then any function from `α` to `β` extends uniquely to an
  additive group homomorphism from the free additive group over `α` to `β`"]
def lift : (α → β) ≃ (FreeGroup α →* β) 
goal: (α → β) ≃ (FreeGroup α →* β)

full_name: FreeAddGroup.lift_symm_apply
code: /-- If `β` is a group, then any function from `α` to `β` extends uniquely to a group homomorphism
from the free group over `α` to `β` -/
@[to_additive (attr := simps symm_apply)
  "If `β` is an additive group, then any function from `α` to `β` extends uniquely to an
  additive group homomorphism from the free additive group over `α` to `β`"]
def lift : (α → β) ≃ (FreeGroup α →* β) 
goal: ∀ (a : α), FreeAddGroup.lift.symm g a = (⇑g ∘ FreeAddGroup.of) a

full_name: FreeAddGroup.lift.mk
code: @[to_additive (attr := simp)]
theorem lift.mk : lift f (mk L) = List.prod (L.map fun x => cond x.2 (f x.1) (f x.1)⁻¹) 
goal: (FreeAddGroup.lift f) (FreeAddGroup.mk L) = (List.map (fun x => bif x.2 then f x.1 else -f x.1) L).sum

full_name: FreeGroup.lift.mk
code: @[to_additive (attr := simp)]
theorem lift.mk : lift f (mk L) = List.prod (L.map fun x => cond x.2 (f x.1) (f x.1)⁻¹) 
goal: (FreeGroup.lift f) (FreeGroup.mk L) = (List.map (fun x => bif x.2 then f x.1 else (f x.1)⁻¹) L).prod

full_name: FreeGroup.lift.of
code: @[to_additive (attr := simp)]
theorem lift.of {x} : lift f (of x) = f x 
goal: (FreeGroup.lift f) (FreeGroup.of x) = f x

full_name: FreeAddGroup.lift.of
code: @[to_additive (attr := simp)]
theorem lift.of {x} : lift f (of x) = f x 
goal: (FreeAddGroup.lift f) (FreeAddGroup.of x) = f x

full_name: FreeAddGroup.lift.unique
code: @[to_additive]
theorem lift.unique (g : FreeGroup α →* β) (hg : ∀ x, g (FreeGroup.of x) = f x) {x} :
    g x = FreeGroup.lift f x 
goal: g x = (FreeAddGroup.lift f) x

full_name: FreeGroup.lift.unique
code: @[to_additive]
theorem lift.unique (g : FreeGroup α →* β) (hg : ∀ x, g (FreeGroup.of x) = f x) {x} :
    g x = FreeGroup.lift f x 
goal: g x = (FreeGroup.lift f) x

full_name: FreeGroup.ext_hom
code: /-- Two homomorphisms out of a free group are equal if they are equal on generators.

See note [partially-applied ext lemmas]. -/
@[to_additive (attr := ext) "Two homomorphisms out of a free additive group are equal if they are
  equal on generators. See note [partially-applied ext lemmas]."]
theorem ext_hom {G : Type*} [Group G] (f g : FreeGroup α →* G) (h : ∀ a, f (of a) = g (of a)) :
    f = g 
goal: f = g

full_name: FreeAddGroup.ext_hom
code: /-- Two homomorphisms out of a free group are equal if they are equal on generators.

See note [partially-applied ext lemmas]. -/
@[to_additive (attr := ext) "Two homomorphisms out of a free additive group are equal if they are
  equal on generators. See note [partially-applied ext lemmas]."]
theorem ext_hom {G : Type*} [Group G] (f g : FreeGroup α →* G) (h : ∀ a, f (of a) = g (of a)) :
    f = g 
goal: f = g

full_name: FreeGroup.lift_of_eq_id
code: @[to_additive]
theorem lift_of_eq_id (α) : lift of = MonoidHom.id (FreeGroup α) 
goal: FreeGroup.lift FreeGroup.of = MonoidHom.id (FreeGroup α)

full_name: FreeAddGroup.lift_of_eq_id
code: @[to_additive]
theorem lift_of_eq_id (α) : lift of = MonoidHom.id (FreeGroup α) 
goal: FreeAddGroup.lift FreeAddGroup.of = AddMonoidHom.id (FreeAddGroup α)

full_name: FreeGroup.lift.of_eq
code: @[to_additive]
theorem lift.of_eq (x : FreeGroup α) : lift FreeGroup.of x = x 
goal: (FreeGroup.lift FreeGroup.of) x = x

full_name: FreeAddGroup.lift.of_eq
code: @[to_additive]
theorem lift.of_eq (x : FreeGroup α) : lift FreeGroup.of x = x 
goal: (FreeAddGroup.lift FreeAddGroup.of) x = x

full_name: FreeGroup.lift.range_le
code: @[to_additive]
theorem lift.range_le {s : Subgroup β} (H : Set.range f ⊆ s) : (lift f).range ≤ s 
goal: (FreeGroup.lift f).range ≤ s

full_name: FreeAddGroup.lift.range_le
code: @[to_additive]
theorem lift.range_le {s : Subgroup β} (H : Set.range f ⊆ s) : (lift f).range ≤ s 
goal: (FreeAddGroup.lift f).range ≤ s

full_name: FreeGroup.lift.range_eq_closure
code: @[to_additive]
theorem lift.range_eq_closure : (lift f).range = Subgroup.closure (Set.range f) 
goal: (FreeGroup.lift f).range = Subgroup.closure (Set.range f)

full_name: FreeAddGroup.lift.range_eq_closure
code: @[to_additive]
theorem lift.range_eq_closure : (lift f).range = Subgroup.closure (Set.range f) 
goal: (FreeAddGroup.lift f).range = AddSubgroup.closure (Set.range f)

full_name: FreeGroup.closure_range_of
code: /-- The generators of `FreeGroup α` generate `FreeGroup α`. That is, the subgroup closure of the
set of generators equals `⊤`. -/
@[to_additive (attr := simp)]
theorem closure_range_of (α) :
    Subgroup.closure (Set.range (FreeGroup.of : α → FreeGroup α)) = ⊤ 
goal: Subgroup.closure (Set.range FreeGroup.of) = ⊤

full_name: FreeAddGroup.closure_range_of
code: /-- The generators of `FreeGroup α` generate `FreeGroup α`. That is, the subgroup closure of the
set of generators equals `⊤`. -/
@[to_additive (attr := simp)]
theorem closure_range_of (α) :
    Subgroup.closure (Set.range (FreeGroup.of : α → FreeGroup α)) = ⊤ 
goal: AddSubgroup.closure (Set.range FreeAddGroup.of) = ⊤

full_name: FreeAddGroup.map
code: /-- Any function from `α` to `β` extends uniquely to a group homomorphism from the free group over
  `α` to the free group over `β`. -/
@[to_additive "Any function from `α` to `β` extends uniquely to an additive group homomorphism from
  the additive free group over `α` to the additive free group over `β`."]
def map : FreeGroup α →* FreeGroup β 
goal: FreeAddGroup α →+ FreeAddGroup β

full_name: FreeGroup.map
code: /-- Any function from `α` to `β` extends uniquely to a group homomorphism from the free group over
  `α` to the free group over `β`. -/
@[to_additive "Any function from `α` to `β` extends uniquely to an additive group homomorphism from
  the additive free group over `α` to the additive free group over `β`."]
def map : FreeGroup α →* FreeGroup β 
goal: FreeGroup α →* FreeGroup β

full_name: FreeGroup.map.mk
code: @[to_additive (attr := simp)]
theorem map.mk : map f (mk L) = mk (L.map fun x => (f x.1, x.2)) 
goal: (FreeGroup.map f) (FreeGroup.mk L) = FreeGroup.mk (List.map (fun x => (f x.1, x.2)) L)

full_name: FreeAddGroup.map.mk
code: @[to_additive (attr := simp)]
theorem map.mk : map f (mk L) = mk (L.map fun x => (f x.1, x.2)) 
goal: (FreeAddGroup.map f) (FreeAddGroup.mk L) = FreeAddGroup.mk (List.map (fun x => (f x.1, x.2)) L)

full_name: FreeGroup.map.id
code: @[to_additive (attr := simp)]
theorem map.id (x : FreeGroup α) : map id x = x 
goal: (FreeGroup.map id) x = x

full_name: FreeAddGroup.map.id
code: @[to_additive (attr := simp)]
theorem map.id (x : FreeGroup α) : map id x = x 
goal: (FreeAddGroup.map id) x = x

full_name: FreeGroup.map.id'
code: @[to_additive (attr := simp)]
theorem map.id' (x : FreeGroup α) : map (fun z => z) x = x 
goal: (FreeGroup.map fun z => z) x = x

full_name: FreeAddGroup.map.id'
code: @[to_additive (attr := simp)]
theorem map.id' (x : FreeGroup α) : map (fun z => z) x = x 
goal: (FreeAddGroup.map fun z => z) x = x

full_name: FreeAddGroup.map.comp
code: @[to_additive]
theorem map.comp {γ : Type w} (f : α → β) (g : β → γ) (x) :
    map g (map f x) = map (g ∘ f) x 
goal: (FreeAddGroup.map g) ((FreeAddGroup.map f) x) = (FreeAddGroup.map (g ∘ f)) x

full_name: FreeGroup.map.comp
code: @[to_additive]
theorem map.comp {γ : Type w} (f : α → β) (g : β → γ) (x) :
    map g (map f x) = map (g ∘ f) x 
goal: (FreeGroup.map g) ((FreeGroup.map f) x) = (FreeGroup.map (g ∘ f)) x

full_name: FreeAddGroup.map.of
code: @[to_additive (attr := simp)]
theorem map.of {x} : map f (of x) = of (f x) 
goal: (FreeAddGroup.map f) (FreeAddGroup.of x) = FreeAddGroup.of (f x)

full_name: FreeGroup.map.of
code: @[to_additive (attr := simp)]
theorem map.of {x} : map f (of x) = of (f x) 
goal: (FreeGroup.map f) (FreeGroup.of x) = FreeGroup.of (f x)

full_name: FreeAddGroup.map.unique
code: @[to_additive]
theorem map.unique (g : FreeGroup α →* FreeGroup β)
    (hg : ∀ x, g (FreeGroup.of x) = FreeGroup.of (f x)) :
    ∀ {x}, g x = map f x 
goal: g x = (FreeAddGroup.map f) x

full_name: FreeGroup.map.unique
code: @[to_additive]
theorem map.unique (g : FreeGroup α →* FreeGroup β)
    (hg : ∀ x, g (FreeGroup.of x) = FreeGroup.of (f x)) :
    ∀ {x}, g x = map f x 
goal: g x = (FreeGroup.map f) x

full_name: FreeGroup.map_eq_lift
code: @[to_additive]
theorem map_eq_lift : map f x = lift (of ∘ f) x 
goal: (FreeGroup.map f) x = (FreeGroup.lift (FreeGroup.of ∘ f)) x

full_name: FreeAddGroup.map_eq_lift
code: @[to_additive]
theorem map_eq_lift : map f x = lift (of ∘ f) x 
goal: (FreeAddGroup.map f) x = (FreeAddGroup.lift (FreeAddGroup.of ∘ f)) x

full_name: FreeGroup.freeGroupCongr_apply
code: /-- Equivalent types give rise to multiplicatively equivalent free groups.

The converse can be found in `GroupTheory.FreeAbelianGroupFinsupp`,
as `Equiv.of_freeGroupEquiv`
 -/
@[to_additive (attr := simps apply)
  "Equivalent types give rise to additively equivalent additive free groups."]
def freeGroupCongr {α β} (e : α ≃ β) : FreeGroup α ≃* FreeGroup β 
goal: (FreeGroup.freeGroupCongr e) a = (FreeGroup.map ⇑e) a

full_name: FreeGroup.freeGroupCongr
code: /-- Equivalent types give rise to multiplicatively equivalent free groups.

The converse can be found in `GroupTheory.FreeAbelianGroupFinsupp`,
as `Equiv.of_freeGroupEquiv`
 -/
@[to_additive (attr := simps apply)
  "Equivalent types give rise to additively equivalent additive free groups."]
def freeGroupCongr {α β} (e : α ≃ β) : FreeGroup α ≃* FreeGroup β 
goal: FreeGroup α ≃* FreeGroup β

full_name: FreeAddGroup.freeAddGroupCongr
code: /-- Equivalent types give rise to multiplicatively equivalent free groups.

The converse can be found in `GroupTheory.FreeAbelianGroupFinsupp`,
as `Equiv.of_freeGroupEquiv`
 -/
@[to_additive (attr := simps apply)
  "Equivalent types give rise to additively equivalent additive free groups."]
def freeGroupCongr {α β} (e : α ≃ β) : FreeGroup α ≃* FreeGroup β 
goal: FreeAddGroup α ≃+ FreeAddGroup β

full_name: FreeAddGroup.freeAddGroupCongr_apply
code: /-- Equivalent types give rise to multiplicatively equivalent free groups.

The converse can be found in `GroupTheory.FreeAbelianGroupFinsupp`,
as `Equiv.of_freeGroupEquiv`
 -/
@[to_additive (attr := simps apply)
  "Equivalent types give rise to additively equivalent additive free groups."]
def freeGroupCongr {α β} (e : α ≃ β) : FreeGroup α ≃* FreeGroup β 
goal: (FreeAddGroup.freeAddGroupCongr e) a = (FreeAddGroup.map ⇑e) a

full_name: FreeAddGroup.freeAddGroupCongr_refl
code: @[to_additive (attr := simp)]
theorem freeGroupCongr_refl : freeGroupCongr (Equiv.refl α) = MulEquiv.refl _ 
goal: FreeAddGroup.freeAddGroupCongr (Equiv.refl α) = AddEquiv.refl (FreeAddGroup α)

full_name: FreeGroup.freeGroupCongr_refl
code: @[to_additive (attr := simp)]
theorem freeGroupCongr_refl : freeGroupCongr (Equiv.refl α) = MulEquiv.refl _ 
goal: FreeGroup.freeGroupCongr (Equiv.refl α) = MulEquiv.refl (FreeGroup α)

full_name: FreeAddGroup.freeAddGroupCongr_symm
code: @[to_additive (attr := simp)]
theorem freeGroupCongr_symm {α β} (e : α ≃ β) : (freeGroupCongr e).symm = freeGroupCongr e.symm 
goal: (FreeAddGroup.freeAddGroupCongr e).symm = FreeAddGroup.freeAddGroupCongr e.symm

full_name: FreeGroup.freeGroupCongr_symm
code: @[to_additive (attr := simp)]
theorem freeGroupCongr_symm {α β} (e : α ≃ β) : (freeGroupCongr e).symm = freeGroupCongr e.symm 
goal: (FreeGroup.freeGroupCongr e).symm = FreeGroup.freeGroupCongr e.symm

full_name: FreeAddGroup.freeAddGroupCongr_trans
code: @[to_additive]
theorem freeGroupCongr_trans {α β γ} (e : α ≃ β) (f : β ≃ γ) :
    (freeGroupCongr e).trans (freeGroupCongr f) = freeGroupCongr (e.trans f) 
goal: (FreeAddGroup.freeAddGroupCongr e).trans (FreeAddGroup.freeAddGroupCongr f) = FreeAddGroup.freeAddGroupCongr (e.trans f)

full_name: FreeGroup.freeGroupCongr_trans
code: @[to_additive]
theorem freeGroupCongr_trans {α β γ} (e : α ≃ β) (f : β ≃ γ) :
    (freeGroupCongr e).trans (freeGroupCongr f) = freeGroupCongr (e.trans f) 
goal: (FreeGroup.freeGroupCongr e).trans (FreeGroup.freeGroupCongr f) = FreeGroup.freeGroupCongr (e.trans f)

full_name: FreeAddGroup.sum
code: /-- If `α` is a group, then any function from `α` to `α` extends uniquely to a homomorphism from the
free group over `α` to `α`. This is the multiplicative version of `FreeGroup.sum`. -/
@[to_additive "If `α` is an additive group, then any function from `α` to `α` extends uniquely to an
  additive homomorphism from the additive free group over `α` to `α`."]
def prod : FreeGroup α →* α 
goal: FreeAddGroup α →+ α

full_name: FreeGroup.prod
code: /-- If `α` is a group, then any function from `α` to `α` extends uniquely to a homomorphism from the
free group over `α` to `α`. This is the multiplicative version of `FreeGroup.sum`. -/
@[to_additive "If `α` is an additive group, then any function from `α` to `α` extends uniquely to an
  additive homomorphism from the additive free group over `α` to `α`."]
def prod : FreeGroup α →* α 
goal: FreeGroup α →* α

full_name: FreeAddGroup.sum_mk
code: @[to_additive (attr := simp)]
theorem prod_mk : prod (mk L) = List.prod (L.map fun x => cond x.2 x.1 x.1⁻¹) 
goal: FreeAddGroup.sum (FreeAddGroup.mk L) = (List.map (fun x => bif x.2 then x.1 else -x.1) L).sum

full_name: FreeGroup.prod_mk
code: @[to_additive (attr := simp)]
theorem prod_mk : prod (mk L) = List.prod (L.map fun x => cond x.2 x.1 x.1⁻¹) 
goal: FreeGroup.prod (FreeGroup.mk L) = (List.map (fun x => bif x.2 then x.1 else x.1⁻¹) L).prod

full_name: FreeGroup.prod.of
code: @[to_additive (attr := simp)]
theorem prod.of {x : α} : prod (of x) = x 
goal: FreeGroup.prod (FreeGroup.of x) = x

full_name: FreeAddGroup.sum.of
code: @[to_additive (attr := simp)]
theorem prod.of {x : α} : prod (of x) = x 
goal: FreeAddGroup.sum (FreeAddGroup.of x) = x

full_name: FreeGroup.prod.unique
code: @[to_additive]
theorem prod.unique (g : FreeGroup α →* α) (hg : ∀ x, g (FreeGroup.of x) = x) {x} : g x = prod x 
goal: g x = FreeGroup.prod x

full_name: FreeAddGroup.sum.unique
code: @[to_additive]
theorem prod.unique (g : FreeGroup α →* α) (hg : ∀ x, g (FreeGroup.of x) = x) {x} : g x = prod x 
goal: g x = FreeAddGroup.sum x

full_name: FreeGroup.lift_eq_prod_map
code: @[to_additive]
theorem lift_eq_prod_map {β : Type v} [Group β] {f : α → β} {x} : lift f x = prod (map f x) 
goal: (FreeGroup.lift f) x = FreeGroup.prod ((FreeGroup.map f) x)

full_name: FreeAddGroup.lift_eq_sum_map
code: @[to_additive]
theorem lift_eq_prod_map {β : Type v} [Group β] {f : α → β} {x} : lift f x = prod (map f x) 
goal: (FreeAddGroup.lift f) x = FreeAddGroup.sum ((FreeAddGroup.map f) x)

full_name: FreeGroup.sum
code: /-- If `α` is a group, then any function from `α` to `α` extends uniquely to a homomorphism from the
free group over `α` to `α`. This is the additive version of `Prod`. -/
def sum : α 
goal: α

full_name: FreeGroup.sum_mk
code: @[simp]
theorem sum_mk : sum (mk L) = List.sum (L.map fun x => cond x.2 x.1 (-x.1)) 
goal: (FreeGroup.mk L).sum = (List.map (fun x => bif x.2 then x.1 else -x.1) L).sum

full_name: FreeGroup.sum.of
code: @[simp]
theorem sum.of {x : α} : sum (of x) = x 
goal: (FreeGroup.of x).sum = x

full_name: FreeGroup.sum.map_mul
code: @[simp]
theorem sum.map_mul : sum (x * y) = sum x + sum y 
goal: (x * y).sum = x.sum + y.sum

full_name: FreeGroup.sum.map_one
code: @[simp]
theorem sum.map_one : sum (1 : FreeGroup α) = 0 
goal: FreeGroup.sum 1 = 0

full_name: FreeGroup.sum.map_inv
code: @[simp]
theorem sum.map_inv : sum x⁻¹ = -sum x 
goal: x⁻¹.sum = -x.sum

full_name: FreeGroup.freeGroupEmptyEquivUnit
code: /-- The bijection between the free group on the empty type, and a type with one element. -/
@[to_additive "The bijection between the additive free group on the empty type, and a type with one
  element."]
def freeGroupEmptyEquivUnit : FreeGroup Empty ≃ Unit 
goal: FreeGroup Empty ≃ Unit

full_name: FreeAddGroup.freeAddGroupEmptyEquivAddUnit
code: /-- The bijection between the free group on the empty type, and a type with one element. -/
@[to_additive "The bijection between the additive free group on the empty type, and a type with one
  element."]
def freeGroupEmptyEquivUnit : FreeGroup Empty ≃ Unit 
goal: FreeAddGroup Empty ≃ Unit

full_name: FreeGroup.freeGroupUnitEquivInt
code: /-- The bijection between the free group on a singleton, and the integers. -/
def freeGroupUnitEquivInt : FreeGroup Unit ≃ ℤ 
goal: FreeGroup Unit ≃ ℤ

full_name: FreeGroup.instMonad
code: @[to_additive]
instance : Monad FreeGroup.{u} 
goal: Monad FreeGroup

full_name: FreeAddGroup.instMonad
code: @[to_additive]
instance : Monad FreeGroup.{u} 
goal: Monad FreeAddGroup

full_name: FreeAddGroup.induction_on
code: @[to_additive (attr := elab_as_elim, induction_eliminator)]
protected theorem induction_on {C : FreeGroup α → Prop} (z : FreeGroup α) (C1 : C 1)
    (Cp : ∀ x, C <| pure x) (Ci : ∀ x, C (pure x) → C (pure x)⁻¹)
    (Cm : ∀ x y, C x → C y → C (x * y)) : C z 
goal: C z

full_name: FreeGroup.induction_on
code: @[to_additive (attr := elab_as_elim, induction_eliminator)]
protected theorem induction_on {C : FreeGroup α → Prop} (z : FreeGroup α) (C1 : C 1)
    (Cp : ∀ x, C <| pure x) (Ci : ∀ x, C (pure x) → C (pure x)⁻¹)
    (Cm : ∀ x y, C x → C y → C (x * y)) : C z 
goal: C z

full_name: FreeGroup.map_pure
code: @[to_additive]
theorem map_pure (f : α → β) (x : α) : f <$> (pure x : FreeGroup α) = pure (f x) 
goal: f <$> pure x = pure (f x)

full_name: FreeAddGroup.map_pure
code: @[to_additive]
theorem map_pure (f : α → β) (x : α) : f <$> (pure x : FreeGroup α) = pure (f x) 
goal: f <$> pure x = pure (f x)

full_name: FreeGroup.map_one
code: @[to_additive (attr := simp)]
theorem map_one (f : α → β) : f <$> (1 : FreeGroup α) = 1 
goal: f <$> 1 = 1

full_name: FreeAddGroup.map_zero
code: @[to_additive (attr := simp)]
theorem map_one (f : α → β) : f <$> (1 : FreeGroup α) = 1 
goal: f <$> 0 = 0

full_name: FreeAddGroup.map_add
code: @[to_additive (attr := simp)]
theorem map_mul (f : α → β) (x y : FreeGroup α) : f <$> (x * y) = f <$> x * f <$> y 
goal: f <$> (x + y) = f <$> x + f <$> y

full_name: FreeGroup.map_mul
code: @[to_additive (attr := simp)]
theorem map_mul (f : α → β) (x y : FreeGroup α) : f <$> (x * y) = f <$> x * f <$> y 
goal: f <$> (x * y) = f <$> x * f <$> y

full_name: FreeAddGroup.map_neg
code: @[to_additive (attr := simp)]
theorem map_inv (f : α → β) (x : FreeGroup α) : f <$> x⁻¹ = (f <$> x)⁻¹ 
goal: f <$> (-x) = -f <$> x

full_name: FreeGroup.map_inv
code: @[to_additive (attr := simp)]
theorem map_inv (f : α → β) (x : FreeGroup α) : f <$> x⁻¹ = (f <$> x)⁻¹ 
goal: f <$> x⁻¹ = (f <$> x)⁻¹

full_name: FreeAddGroup.pure_bind
code: @[to_additive]
theorem pure_bind (f : α → FreeGroup β) (x) : pure x >>= f = f x 
goal: pure x >>= f = f x

full_name: FreeGroup.pure_bind
code: @[to_additive]
theorem pure_bind (f : α → FreeGroup β) (x) : pure x >>= f = f x 
goal: pure x >>= f = f x

full_name: FreeAddGroup.zero_bind
code: @[to_additive (attr := simp)]
theorem one_bind (f : α → FreeGroup β) : 1 >>= f = 1 
goal: 0 >>= f = 0

full_name: FreeGroup.one_bind
code: @[to_additive (attr := simp)]
theorem one_bind (f : α → FreeGroup β) : 1 >>= f = 1 
goal: 1 >>= f = 1

full_name: FreeAddGroup.add_bind
code: @[to_additive (attr := simp)]
theorem mul_bind (f : α → FreeGroup β) (x y : FreeGroup α) : x * y >>= f = (x >>= f) * (y >>= f) 
goal: x + y >>= f = (x >>= f) + (y >>= f)

full_name: FreeGroup.mul_bind
code: @[to_additive (attr := simp)]
theorem mul_bind (f : α → FreeGroup β) (x y : FreeGroup α) : x * y >>= f = (x >>= f) * (y >>= f) 
goal: x * y >>= f = (x >>= f) * (y >>= f)

full_name: FreeAddGroup.neg_bind
code: @[to_additive (attr := simp)]
theorem inv_bind (f : α → FreeGroup β) (x : FreeGroup α) : x⁻¹ >>= f = (x >>= f)⁻¹ 
goal: -x >>= f = -(x >>= f)

full_name: FreeGroup.inv_bind
code: @[to_additive (attr := simp)]
theorem inv_bind (f : α → FreeGroup β) (x : FreeGroup α) : x⁻¹ >>= f = (x >>= f)⁻¹ 
goal: x⁻¹ >>= f = (x >>= f)⁻¹

full_name: FreeAddGroup.instLawfulMonad
code: @[to_additive]
instance : LawfulMonad FreeGroup.{u} 
goal: LawfulMonad FreeAddGroup

full_name: FreeGroup.instLawfulMonad
code: @[to_additive]
instance : LawfulMonad FreeGroup.{u} 
goal: LawfulMonad FreeGroup

full_name: FreeGroup.reduce
code: /-- The maximal reduction of a word. It is computable
iff `α` has decidable equality. -/
@[to_additive "The maximal reduction of a word. It is computable iff `α` has decidable equality."]
def reduce : (L : List (α × Bool)) -> List (α × Bool) 
goal: List (α × Bool)

full_name: FreeAddGroup.reduce
code: /-- The maximal reduction of a word. It is computable
iff `α` has decidable equality. -/
@[to_additive "The maximal reduction of a word. It is computable iff `α` has decidable equality."]
def reduce : (L : List (α × Bool)) -> List (α × Bool) 
goal: List (α × Bool)

full_name: FreeAddGroup.reduce.cons
code: @[to_additive (attr := simp)]
theorem reduce.cons (x) :
    reduce (x :: L) =
      List.casesOn (reduce L) [x] fun hd tl =>
        if x.1 = hd.1 ∧ x.2 = not hd.2 then tl else x :: hd :: tl 
goal: FreeAddGroup.reduce (x :: L) =
  List.casesOn (FreeAddGroup.reduce L) [x] fun hd tl => if x.1 = hd.1 ∧ x.2 = !hd.2 then tl else x :: hd :: tl

full_name: FreeGroup.reduce.cons
code: @[to_additive (attr := simp)]
theorem reduce.cons (x) :
    reduce (x :: L) =
      List.casesOn (reduce L) [x] fun hd tl =>
        if x.1 = hd.1 ∧ x.2 = not hd.2 then tl else x :: hd :: tl 
goal: FreeGroup.reduce (x :: L) =
  List.casesOn (FreeGroup.reduce L) [x] fun hd tl => if x.1 = hd.1 ∧ x.2 = !hd.2 then tl else x :: hd :: tl

full_name: FreeGroup.reduce.red
code: /-- The first theorem that characterises the function `reduce`: a word reduces to its maximal
  reduction. -/
@[to_additive "The first theorem that characterises the function `reduce`: a word reduces to its
  maximal reduction."]
theorem reduce.red : Red L (reduce L) 
goal: FreeGroup.Red L (FreeGroup.reduce L)

full_name: FreeAddGroup.reduce.red
code: /-- The first theorem that characterises the function `reduce`: a word reduces to its maximal
  reduction. -/
@[to_additive "The first theorem that characterises the function `reduce`: a word reduces to its
  maximal reduction."]
theorem reduce.red : Red L (reduce L) 
goal: FreeAddGroup.Red L (FreeAddGroup.reduce L)

full_name: FreeGroup.reduce.not
code: @[to_additive]
theorem reduce.not {p : Prop} :
    ∀ {L₁ L₂ L₃ : List (α × Bool)} {x b}, reduce L₁ = L₂ ++ (x, b) :: (x, !b) :: L₃ → p
  
goal: FreeGroup.reduce L₁ = L₂ ++ (x, b) :: (x, !b) :: L₃ → p

full_name: FreeAddGroup.reduce.not
code: @[to_additive]
theorem reduce.not {p : Prop} :
    ∀ {L₁ L₂ L₃ : List (α × Bool)} {x b}, reduce L₁ = L₂ ++ (x, b) :: (x, !b) :: L₃ → p
  
goal: FreeAddGroup.reduce L₁ = L₂ ++ (x, b) :: (x, !b) :: L₃ → p

full_name: FreeGroup.reduce.min
code: /-- The second theorem that characterises the function `reduce`: the maximal reduction of a word
only reduces to itself. -/
@[to_additive "The second theorem that characterises the function `reduce`: the maximal reduction of
  a word only reduces to itself."]
theorem reduce.min (H : Red (reduce L₁) L₂) : reduce L₁ = L₂ 
goal: FreeGroup.reduce L₁ = L₂

full_name: FreeAddGroup.reduce.min
code: /-- The second theorem that characterises the function `reduce`: the maximal reduction of a word
only reduces to itself. -/
@[to_additive "The second theorem that characterises the function `reduce`: the maximal reduction of
  a word only reduces to itself."]
theorem reduce.min (H : Red (reduce L₁) L₂) : reduce L₁ = L₂ 
goal: FreeAddGroup.reduce L₁ = L₂

full_name: FreeGroup.reduce.idem
code: /-- `reduce` is idempotent, i.e. the maximal reduction of the maximal reduction of a word is the
  maximal reduction of the word. -/
@[to_additive (attr := simp) "`reduce` is idempotent, i.e. the maximal reduction of the maximal
  reduction of a word is the maximal reduction of the word."]
theorem reduce.idem : reduce (reduce L) = reduce L 
goal: FreeGroup.reduce (FreeGroup.reduce L) = FreeGroup.reduce L

full_name: FreeAddGroup.reduce.idem
code: /-- `reduce` is idempotent, i.e. the maximal reduction of the maximal reduction of a word is the
  maximal reduction of the word. -/
@[to_additive (attr := simp) "`reduce` is idempotent, i.e. the maximal reduction of the maximal
  reduction of a word is the maximal reduction of the word."]
theorem reduce.idem : reduce (reduce L) = reduce L 
goal: FreeAddGroup.reduce (FreeAddGroup.reduce L) = FreeAddGroup.reduce L

full_name: FreeGroup.reduce.Step.eq
code: @[to_additive]
theorem reduce.Step.eq (H : Red.Step L₁ L₂) : reduce L₁ = reduce L₂ 
goal: FreeGroup.reduce L₁ = FreeGroup.reduce L₂

full_name: FreeAddGroup.reduce.Step.eq
code: @[to_additive]
theorem reduce.Step.eq (H : Red.Step L₁ L₂) : reduce L₁ = reduce L₂ 
goal: FreeAddGroup.reduce L₁ = FreeAddGroup.reduce L₂

full_name: FreeGroup.reduce.eq_of_red
code: /-- If a word reduces to another word, then they have a common maximal reduction. -/
@[to_additive "If a word reduces to another word, then they have a common maximal reduction."]
theorem reduce.eq_of_red (H : Red L₁ L₂) : reduce L₁ = reduce L₂ 
goal: FreeGroup.reduce L₁ = FreeGroup.reduce L₂

full_name: FreeAddGroup.reduce.eq_of_red
code: /-- If a word reduces to another word, then they have a common maximal reduction. -/
@[to_additive "If a word reduces to another word, then they have a common maximal reduction."]
theorem reduce.eq_of_red (H : Red L₁ L₂) : reduce L₁ = reduce L₂ 
goal: FreeAddGroup.reduce L₁ = FreeAddGroup.reduce L₂

full_name: FreeAddGroup.Red.reduce_right
code: @[to_additive]
theorem Red.reduce_right (h : Red L₁ L₂) : Red L₁ (reduce L₂) 
goal: FreeAddGroup.Red L₁ (FreeAddGroup.reduce L₂)

full_name: FreeGroup.Red.reduce_right
code: @[to_additive]
theorem Red.reduce_right (h : Red L₁ L₂) : Red L₁ (reduce L₂) 
goal: FreeGroup.Red L₁ (FreeGroup.reduce L₂)

full_name: FreeAddGroup.Red.reduce_left
code: @[to_additive]
theorem Red.reduce_left (h : Red L₁ L₂) : Red L₂ (reduce L₁) 
goal: FreeAddGroup.Red L₂ (FreeAddGroup.reduce L₁)

full_name: FreeGroup.Red.reduce_left
code: @[to_additive]
theorem Red.reduce_left (h : Red L₁ L₂) : Red L₂ (reduce L₁) 
goal: FreeGroup.Red L₂ (FreeGroup.reduce L₁)

full_name: FreeGroup.reduce.sound
code: /-- If two words correspond to the same element in the free group, then they
have a common maximal reduction. This is the proof that the function that sends
an element of the free group to its maximal reduction is well-defined. -/
@[to_additive "If two words correspond to the same element in the additive free group, then they
  have a common maximal reduction. This is the proof that the function that sends an element of the
  free group to its maximal reduction is well-defined."]
theorem reduce.sound (H : mk L₁ = mk L₂) : reduce L₁ = reduce L₂ 
goal: FreeGroup.reduce L₁ = FreeGroup.reduce L₂

full_name: FreeAddGroup.reduce.sound
code: /-- If two words correspond to the same element in the free group, then they
have a common maximal reduction. This is the proof that the function that sends
an element of the free group to its maximal reduction is well-defined. -/
@[to_additive "If two words correspond to the same element in the additive free group, then they
  have a common maximal reduction. This is the proof that the function that sends an element of the
  free group to its maximal reduction is well-defined."]
theorem reduce.sound (H : mk L₁ = mk L₂) : reduce L₁ = reduce L₂ 
goal: FreeAddGroup.reduce L₁ = FreeAddGroup.reduce L₂

full_name: FreeGroup.reduce.exact
code: /-- If two words have a common maximal reduction, then they correspond to the same element in the
  free group. -/
@[to_additive "If two words have a common maximal reduction, then they correspond to the same
  element in the additive free group."]
theorem reduce.exact (H : reduce L₁ = reduce L₂) : mk L₁ = mk L₂ 
goal: FreeGroup.mk L₁ = FreeGroup.mk L₂

full_name: FreeAddGroup.reduce.exact
code: /-- If two words have a common maximal reduction, then they correspond to the same element in the
  free group. -/
@[to_additive "If two words have a common maximal reduction, then they correspond to the same
  element in the additive free group."]
theorem reduce.exact (H : reduce L₁ = reduce L₂) : mk L₁ = mk L₂ 
goal: FreeAddGroup.mk L₁ = FreeAddGroup.mk L₂

full_name: FreeGroup.reduce.self
code: /-- A word and its maximal reduction correspond to the same element of the free group. -/
@[to_additive "A word and its maximal reduction correspond to the same element of the additive free
  group."]
theorem reduce.self : mk (reduce L) = mk L 
goal: FreeGroup.mk (FreeGroup.reduce L) = FreeGroup.mk L

full_name: FreeAddGroup.reduce.self
code: /-- A word and its maximal reduction correspond to the same element of the free group. -/
@[to_additive "A word and its maximal reduction correspond to the same element of the additive free
  group."]
theorem reduce.self : mk (reduce L) = mk L 
goal: FreeAddGroup.mk (FreeAddGroup.reduce L) = FreeAddGroup.mk L

full_name: FreeAddGroup.reduce.rev
code: /-- If words `w₁ w₂` are such that `w₁` reduces to `w₂`, then `w₂` reduces to the maximal reduction
  of `w₁`. -/
@[to_additive "If words `w₁ w₂` are such that `w₁` reduces to `w₂`, then `w₂` reduces to the maximal
  reduction of `w₁`."]
theorem reduce.rev (H : Red L₁ L₂) : Red L₂ (reduce L₁) 
goal: FreeAddGroup.Red L₂ (FreeAddGroup.reduce L₁)

full_name: FreeGroup.reduce.rev
code: /-- If words `w₁ w₂` are such that `w₁` reduces to `w₂`, then `w₂` reduces to the maximal reduction
  of `w₁`. -/
@[to_additive "If words `w₁ w₂` are such that `w₁` reduces to `w₂`, then `w₂` reduces to the maximal
  reduction of `w₁`."]
theorem reduce.rev (H : Red L₁ L₂) : Red L₂ (reduce L₁) 
goal: FreeGroup.Red L₂ (FreeGroup.reduce L₁)

full_name: FreeAddGroup.toWord
code: /-- The function that sends an element of the free group to its maximal reduction. -/
@[to_additive "The function that sends an element of the additive free group to its maximal
  reduction."]
def toWord : FreeGroup α → List (α × Bool) 
goal: FreeAddGroup α → List (α × Bool)

full_name: FreeGroup.toWord
code: /-- The function that sends an element of the free group to its maximal reduction. -/
@[to_additive "The function that sends an element of the additive free group to its maximal
  reduction."]
def toWord : FreeGroup α → List (α × Bool) 
goal: FreeGroup α → List (α × Bool)

full_name: FreeGroup.mk_toWord
code: @[to_additive]
theorem mk_toWord : ∀ {x : FreeGroup α}, mk (toWord x) = x 
goal: FreeGroup.mk x.toWord = x

full_name: FreeAddGroup.mk_toWord
code: @[to_additive]
theorem mk_toWord : ∀ {x : FreeGroup α}, mk (toWord x) = x 
goal: FreeAddGroup.mk x.toWord = x

full_name: FreeGroup.toWord_injective
code: @[to_additive]
theorem toWord_injective : Function.Injective (toWord : FreeGroup α → List (α × Bool)) 
goal: Function.Injective FreeGroup.toWord

full_name: FreeAddGroup.toWord_injective
code: @[to_additive]
theorem toWord_injective : Function.Injective (toWord : FreeGroup α → List (α × Bool)) 
goal: Function.Injective FreeAddGroup.toWord

full_name: FreeGroup.toWord_inj
code: @[to_additive (attr := simp)]
theorem toWord_inj {x y : FreeGroup α} : toWord x = toWord y ↔ x = y 
goal: x.toWord = y.toWord ↔ x = y

full_name: FreeAddGroup.toWord_inj
code: @[to_additive (attr := simp)]
theorem toWord_inj {x y : FreeGroup α} : toWord x = toWord y ↔ x = y 
goal: x.toWord = y.toWord ↔ x = y

full_name: FreeAddGroup.toWord_mk
code: @[to_additive (attr := simp)]
theorem toWord_mk : (mk L₁).toWord = reduce L₁ 
goal: (FreeAddGroup.mk L₁).toWord = FreeAddGroup.reduce L₁

full_name: FreeGroup.toWord_mk
code: @[to_additive (attr := simp)]
theorem toWord_mk : (mk L₁).toWord = reduce L₁ 
goal: (FreeGroup.mk L₁).toWord = FreeGroup.reduce L₁

full_name: FreeAddGroup.reduce_toWord
code: @[to_additive (attr := simp)]
theorem reduce_toWord : ∀ x : FreeGroup α, reduce (toWord x) = toWord x 
goal: FreeAddGroup.reduce x.toWord = x.toWord

full_name: FreeGroup.reduce_toWord
code: @[to_additive (attr := simp)]
theorem reduce_toWord : ∀ x : FreeGroup α, reduce (toWord x) = toWord x 
goal: FreeGroup.reduce x.toWord = x.toWord

full_name: FreeAddGroup.toWord_zero
code: @[to_additive (attr := simp)]
theorem toWord_one : (1 : FreeGroup α).toWord = [] 
goal: FreeAddGroup.toWord 0 = []

full_name: FreeGroup.toWord_one
code: @[to_additive (attr := simp)]
theorem toWord_one : (1 : FreeGroup α).toWord = [] 
goal: FreeGroup.toWord 1 = []

full_name: FreeGroup.toWord_eq_nil_iff
code: @[to_additive (attr := simp)]
theorem toWord_eq_nil_iff {x : FreeGroup α} : x.toWord = [] ↔ x = 1 
goal: x.toWord = [] ↔ x = 1

full_name: FreeAddGroup.toWord_eq_nil_iff
code: @[to_additive (attr := simp)]
theorem toWord_eq_nil_iff {x : FreeGroup α} : x.toWord = [] ↔ x = 1 
goal: x.toWord = [] ↔ x = 0

full_name: FreeAddGroup.reduce_negRev
code: @[to_additive]
theorem reduce_invRev {w : List (α × Bool)} : reduce (invRev w) = invRev (reduce w) 
goal: FreeAddGroup.reduce (FreeAddGroup.negRev w) = FreeAddGroup.negRev (FreeAddGroup.reduce w)

full_name: FreeGroup.reduce_invRev
code: @[to_additive]
theorem reduce_invRev {w : List (α × Bool)} : reduce (invRev w) = invRev (reduce w) 
goal: FreeGroup.reduce (FreeGroup.invRev w) = FreeGroup.invRev (FreeGroup.reduce w)

full_name: FreeGroup.toWord_inv
code: @[to_additive]
theorem toWord_inv {x : FreeGroup α} : x⁻¹.toWord = invRev x.toWord 
goal: x⁻¹.toWord = FreeGroup.invRev x.toWord

full_name: FreeAddGroup.toWord_neg
code: @[to_additive]
theorem toWord_inv {x : FreeGroup α} : x⁻¹.toWord = invRev x.toWord 
goal: (-x).toWord = FreeAddGroup.negRev x.toWord

full_name: FreeAddGroup.reduce.churchRosser
code: /-- **Constructive Church-Rosser theorem** (compare `church_rosser`). -/
@[to_additive "**Constructive Church-Rosser theorem** (compare `church_rosser`)."]
def reduce.churchRosser (H12 : Red L₁ L₂) (H13 : Red L₁ L₃) : { L₄ // Red L₂ L₄ ∧ Red L₃ L₄ } 
goal: { L₄ // FreeAddGroup.Red L₂ L₄ ∧ FreeAddGroup.Red L₃ L₄ }

full_name: FreeGroup.reduce.churchRosser
code: /-- **Constructive Church-Rosser theorem** (compare `church_rosser`). -/
@[to_additive "**Constructive Church-Rosser theorem** (compare `church_rosser`)."]
def reduce.churchRosser (H12 : Red L₁ L₂) (H13 : Red L₁ L₃) : { L₄ // Red L₂ L₄ ∧ Red L₃ L₄ } 
goal: { L₄ // FreeGroup.Red L₂ L₄ ∧ FreeGroup.Red L₃ L₄ }

full_name: FreeGroup.instDecidableEq
code: @[to_additive]
instance : DecidableEq (FreeGroup α) 
goal: DecidableEq (FreeGroup α)

full_name: FreeAddGroup.instDecidableEq
code: @[to_additive]
instance : DecidableEq (FreeGroup α) 
goal: DecidableEq (FreeAddGroup α)

full_name: FreeGroup.Red.decidableRel
code: instance Red.decidableRel : DecidableRel (@Red α)
  
goal: DecidableRel FreeGroup.Red

full_name: FreeGroup.Red.enum
code: /-- A list containing every word that `w₁` reduces to. -/
def Red.enum (L₁ : List (α × Bool)) : List (List (α × Bool)) 
goal: List (List (α × Bool))

full_name: FreeGroup.Red.enum.sound
code: theorem Red.enum.sound (H : L₂ ∈ List.filter (Red L₁) (List.sublists L₁)) : Red L₁ L₂ 
goal: FreeGroup.Red L₁ L₂

full_name: FreeGroup.Red.enum.complete
code: theorem Red.enum.complete (H : Red L₁ L₂) : L₂ ∈ Red.enum L₁ 
goal: L₂ ∈ FreeGroup.Red.enum L₁

full_name: FreeGroup.instFintypeSubtypeListProdBoolRed
code: instance : Fintype { L₂ // Red L₁ L₂ } 
goal: Fintype { L₂ // FreeGroup.Red L₁ L₂ }

full_name: FreeAddGroup.norm
code: /-- The length of reduced words provides a norm on a free group. -/
@[to_additive "The length of reduced words provides a norm on an additive free group."]
def norm (x : FreeGroup α) : ℕ 
goal: ℕ

full_name: FreeGroup.norm
code: /-- The length of reduced words provides a norm on a free group. -/
@[to_additive "The length of reduced words provides a norm on an additive free group."]
def norm (x : FreeGroup α) : ℕ 
goal: ℕ

full_name: FreeAddGroup.norm_neg_eq
code: @[to_additive (attr := simp)]
theorem norm_inv_eq {x : FreeGroup α} : norm x⁻¹ = norm x 
goal: (-x).norm = x.norm

full_name: FreeGroup.norm_inv_eq
code: @[to_additive (attr := simp)]
theorem norm_inv_eq {x : FreeGroup α} : norm x⁻¹ = norm x 
goal: x⁻¹.norm = x.norm

full_name: FreeGroup.norm_eq_zero
code: @[to_additive (attr := simp)]
theorem norm_eq_zero {x : FreeGroup α} : norm x = 0 ↔ x = 1 
goal: x.norm = 0 ↔ x = 1

full_name: FreeAddGroup.norm_eq_zero
code: @[to_additive (attr := simp)]
theorem norm_eq_zero {x : FreeGroup α} : norm x = 0 ↔ x = 1 
goal: x.norm = 0 ↔ x = 0

full_name: FreeAddGroup.norm_zero
code: @[to_additive (attr := simp)]
theorem norm_one : norm (1 : FreeGroup α) = 0 
goal: FreeAddGroup.norm 0 = 0

full_name: FreeGroup.norm_one
code: @[to_additive (attr := simp)]
theorem norm_one : norm (1 : FreeGroup α) = 0 
goal: FreeGroup.norm 1 = 0

full_name: FreeAddGroup.norm_mk_le
code: @[to_additive]
theorem norm_mk_le : norm (mk L₁) ≤ L₁.length 
goal: (FreeAddGroup.mk L₁).norm ≤ L₁.length

full_name: FreeGroup.norm_mk_le
code: @[to_additive]
theorem norm_mk_le : norm (mk L₁) ≤ L₁.length 
goal: (FreeGroup.mk L₁).norm ≤ L₁.length

full_name: FreeAddGroup.norm_add_le
code: @[to_additive]
theorem norm_mul_le (x y : FreeGroup α) : norm (x * y) ≤ norm x + norm y 
goal: (x + y).norm ≤ x.norm + y.norm

full_name: FreeGroup.norm_mul_le
code: @[to_additive]
theorem norm_mul_le (x y : FreeGroup α) : norm (x * y) ≤ norm x + norm y 
goal: (x * y).norm ≤ x.norm + y.norm